-/* Plugin Browser Thickbox related JS*/
+/* global plugininstallL10n, tb_click, tb_remove */
+
+/**
+ * Functionality for the plugin install screens.
+ */
var tb_position;
-jQuery(document).ready(function($) {
+jQuery( document ).ready( function( $ ) {
+
+ var tbWindow,
+ $focusedBefore,
+ $iframeBody,
+ $tabbables,
+ $firstTabbable,
+ $lastTabbable,
+ $uploadViewToggle = $( '.upload-view-toggle' ),
+ $wrap = $ ( '.wrap' ),
+ $body = $( document.body );
+
tb_position = function() {
- var tbWindow = $('#TB_window'), width = $(window).width(), H = $(window).height(), W = ( 720 < width ) ? 720 : width, adminbar_height = 0;
-
- if ( $('body.admin-bar').length )
- adminbar_height = 28;
-
- if ( tbWindow.size() ) {
- tbWindow.width( W - 50 ).height( H - 45 - adminbar_height );
- $('#TB_iframeContent').width( W - 50 ).height( H - 75 - adminbar_height );
- tbWindow.css({'margin-left': '-' + parseInt((( W - 50 ) / 2),10) + 'px'});
- if ( typeof document.body.style.maxWidth != 'undefined' )
- tbWindow.css({'top': 20 + adminbar_height + 'px','margin-top':'0'});
- };
-
- return $('a.thickbox').each( function() {
- var href = $(this).attr('href');
- if ( ! href )
+ var width = $( window ).width(),
+ H = $( window ).height() - ( ( 792 < width ) ? 60 : 20 ),
+ W = ( 792 < width ) ? 772 : width - 20;
+
+ tbWindow = $( '#TB_window' );
+
+ if ( tbWindow.length ) {
+ tbWindow.width( W ).height( H );
+ $( '#TB_iframeContent' ).width( W ).height( H );
+ tbWindow.css({
+ 'margin-left': '-' + parseInt( ( W / 2 ), 10 ) + 'px'
+ });
+ if ( typeof document.body.style.maxWidth !== 'undefined' ) {
+ tbWindow.css({
+ 'top': '30px',
+ 'margin-top': '0'
+ });
+ }
+ }
+
+ return $( 'a.thickbox' ).each( function() {
+ var href = $( this ).attr( 'href' );
+ if ( ! href ) {
return;
- href = href.replace(/&width=[0-9]+/g, '');
- href = href.replace(/&height=[0-9]+/g, '');
- $(this).attr( 'href', href + '&width=' + ( W - 80 ) + '&height=' + ( H - 85 - adminbar_height ) );
+ }
+ href = href.replace( /&width=[0-9]+/g, '' );
+ href = href.replace( /&height=[0-9]+/g, '' );
+ $(this).attr( 'href', href + '&width=' + W + '&height=' + ( H ) );
});
};
- $(window).resize(function(){ tb_position(); });
+ $( window ).resize( function() {
+ tb_position();
+ });
+
+ /*
+ * Custom events: when a Thickbox iframe has loaded and when the Thickbox
+ * modal gets removed from the DOM.
+ */
+ $body
+ .on( 'thickbox:iframe:loaded', tbWindow, function() {
+ iframeLoaded();
+ })
+ .on( 'thickbox:removed', function() {
+ // Set focus back to the element that opened the modal dialog.
+ // Note: IE 8 would need this wrapped in a fake setTimeout `0`.
+ $focusedBefore.focus();
+ });
+
+ function iframeLoaded() {
+ var $iframe = tbWindow.find( '#TB_iframeContent' );
+
+ // Get the iframe body.
+ $iframeBody = $iframe.contents().find( 'body' );
+
+ // Get the tabbable elements and handle the keydown event on first load.
+ handleTabbables();
+
+ // Set initial focus on the "Close" button.
+ $firstTabbable.focus();
+
+ /*
+ * When the "Install" button is disabled (e.g. the Plugin is already installed)
+ * then we can't predict where the last focusable element is. We need to get
+ * the tabbable elements and handle the keydown event again and again,
+ * each time the active tab panel changes.
+ */
+ $( '#plugin-information-tabs a', $iframeBody ).on( 'click', function() {
+ handleTabbables();
+ });
+
+ // Close the modal when pressing Escape.
+ $iframeBody.on( 'keydown', function( event ) {
+ if ( 27 !== event.which ) {
+ return;
+ }
+ tb_remove();
+ });
+ }
+
+ /*
+ * Get the tabbable elements and detach/attach the keydown event.
+ * Called after the iframe has fully loaded so we have all the elements we need.
+ * Called again each time a Tab gets clicked.
+ * @todo Consider to implement a WordPress general utility for this and don't use jQuery UI.
+ */
+ function handleTabbables() {
+ var $firstAndLast;
+ // Get all the tabbable elements.
+ $tabbables = $( ':tabbable', $iframeBody );
+ // Our first tabbable element is always the "Close" button.
+ $firstTabbable = tbWindow.find( '#TB_closeWindowButton' );
+ // Get the last tabbable element.
+ $lastTabbable = $tabbables.last();
+ // Make a jQuery collection.
+ $firstAndLast = $firstTabbable.add( $lastTabbable );
+ // Detach any previously attached keydown event.
+ $firstAndLast.off( 'keydown.wp-plugin-details' );
+ // Attach again the keydown event on the first and last focusable elements.
+ $firstAndLast.on( 'keydown.wp-plugin-details', function( event ) {
+ constrainTabbing( event );
+ });
+ }
+
+ // Constrain tabbing within the plugin modal dialog.
+ function constrainTabbing( event ) {
+ if ( 9 !== event.which ) {
+ return;
+ }
+
+ if ( $lastTabbable[0] === event.target && ! event.shiftKey ) {
+ event.preventDefault();
+ $firstTabbable.focus();
+ } else if ( $firstTabbable[0] === event.target && event.shiftKey ) {
+ event.preventDefault();
+ $lastTabbable.focus();
+ }
+ }
+
+ // Open the Plugin details modal.
+ $( '.thickbox.open-plugin-details-modal' ).on( 'click', function( e ) {
+ // The `data-title` attribute is used only in the Plugin screens.
+ var title = $( this ).data( 'title' ) ? plugininstallL10n.plugin_information + ' ' + $( this ).data( 'title' ) : plugininstallL10n.plugin_modal_label;
+
+ e.preventDefault();
+ e.stopPropagation();
+
+ // Store the element that has focus before opening the modal dialog, i.e. the control which opens it.
+ $focusedBefore = $( this );
- $('#dashboard_plugins, .plugins').on( 'click', 'a.thickbox', function() {
tb_click.call(this);
- $('#TB_title').css({'background-color':'#222','color':'#cfcfcf'});
- $('#TB_ajaxWindowTitle').html('<strong>' + plugininstallL10n.plugin_information + '</strong> ' + $(this).attr('title') );
- return false;
- });
+ // Set ARIA role and ARIA label.
+ tbWindow.attr({
+ 'role': 'dialog',
+ 'aria-label': plugininstallL10n.plugin_modal_label
+ });
- /* Plugin install related JS*/
- $('#plugin-information #sidemenu a').click( function() {
- var tab = $(this).attr('name');
- //Flip the tab
- $('#plugin-information-header a.current').removeClass('current');
- $(this).addClass('current');
- //Flip the content.
- $('#section-holder div.section').hide(); //Hide 'em all
- $('#section-' + tab).show();
- return false;
+ // Set title attribute on the iframe.
+ tbWindow.find( '#TB_iframeContent' ).attr( 'title', title );
});
- $('a.install-now').click( function() {
- return confirm( plugininstallL10n.ays );
+ /* Plugin install related JS */
+ $( '#plugin-information-tabs a' ).click( function( event ) {
+ var tab = $( this ).attr( 'name' );
+ event.preventDefault();
+
+ // Flip the tab
+ $( '#plugin-information-tabs a.current' ).removeClass( 'current' );
+ $( this ).addClass( 'current' );
+
+ // Only show the fyi box in the description section, on smaller screen, where it's otherwise always displayed at the top.
+ if ( 'description' !== tab && $( window ).width() < 772 ) {
+ $( '#plugin-information-content' ).find( '.fyi' ).hide();
+ } else {
+ $( '#plugin-information-content' ).find( '.fyi' ).show();
+ }
+
+ // Flip the content.
+ $( '#section-holder div.section' ).hide(); // Hide 'em all.
+ $( '#section-' + tab ).show();
});
+
+ /*
+ * When a user presses the "Upload Plugin" button, show the upload form in place
+ * rather than sending them to the devoted upload plugin page.
+ * The `?tab=upload` page still exists for no-js support and for plugins that
+ * might access it directly. When we're in this page, let the link behave
+ * like a link. Otherwise we're in the normal plugin installer pages and the
+ * link should behave like a toggle button.
+ */
+ if ( ! $wrap.hasClass( 'plugin-install-tab-upload' ) ) {
+ $uploadViewToggle
+ .attr({
+ role: 'button',
+ 'aria-expanded': 'false'
+ })
+ .on( 'click', function( event ) {
+ event.preventDefault();
+ $body.toggleClass( 'show-upload-view' );
+ $uploadViewToggle.attr( 'aria-expanded', $body.hasClass( 'show-upload-view' ) );
+ });
+ }
});