plugin-install.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /* global plugininstallL10n, tb_click, tb_remove */
  2. /**
  3. * Functionality for the plugin install screens.
  4. */
  5. var tb_position;
  6. jQuery( document ).ready( function( $ ) {
  7. var tbWindow,
  8. $focusedBefore,
  9. $iframeBody,
  10. $tabbables,
  11. $firstTabbable,
  12. $lastTabbable,
  13. $uploadViewToggle = $( '.upload-view-toggle' ),
  14. $wrap = $ ( '.wrap' ),
  15. $body = $( document.body );
  16. tb_position = function() {
  17. var width = $( window ).width(),
  18. H = $( window ).height() - ( ( 792 < width ) ? 60 : 20 ),
  19. W = ( 792 < width ) ? 772 : width - 20;
  20. tbWindow = $( '#TB_window' );
  21. if ( tbWindow.length ) {
  22. tbWindow.width( W ).height( H );
  23. $( '#TB_iframeContent' ).width( W ).height( H );
  24. tbWindow.css({
  25. 'margin-left': '-' + parseInt( ( W / 2 ), 10 ) + 'px'
  26. });
  27. if ( typeof document.body.style.maxWidth !== 'undefined' ) {
  28. tbWindow.css({
  29. 'top': '30px',
  30. 'margin-top': '0'
  31. });
  32. }
  33. }
  34. return $( 'a.thickbox' ).each( function() {
  35. var href = $( this ).attr( 'href' );
  36. if ( ! href ) {
  37. return;
  38. }
  39. href = href.replace( /&width=[0-9]+/g, '' );
  40. href = href.replace( /&height=[0-9]+/g, '' );
  41. $(this).attr( 'href', href + '&width=' + W + '&height=' + ( H ) );
  42. });
  43. };
  44. $( window ).resize( function() {
  45. tb_position();
  46. });
  47. /*
  48. * Custom events: when a Thickbox iframe has loaded and when the Thickbox
  49. * modal gets removed from the DOM.
  50. */
  51. $body
  52. .on( 'thickbox:iframe:loaded', tbWindow, function() {
  53. iframeLoaded();
  54. })
  55. .on( 'thickbox:removed', function() {
  56. // Set focus back to the element that opened the modal dialog.
  57. // Note: IE 8 would need this wrapped in a fake setTimeout `0`.
  58. $focusedBefore.focus();
  59. });
  60. function iframeLoaded() {
  61. var $iframe = tbWindow.find( '#TB_iframeContent' );
  62. // Get the iframe body.
  63. $iframeBody = $iframe.contents().find( 'body' );
  64. // Get the tabbable elements and handle the keydown event on first load.
  65. handleTabbables();
  66. // Set initial focus on the "Close" button.
  67. $firstTabbable.focus();
  68. /*
  69. * When the "Install" button is disabled (e.g. the Plugin is already installed)
  70. * then we can't predict where the last focusable element is. We need to get
  71. * the tabbable elements and handle the keydown event again and again,
  72. * each time the active tab panel changes.
  73. */
  74. $( '#plugin-information-tabs a', $iframeBody ).on( 'click', function() {
  75. handleTabbables();
  76. });
  77. // Close the modal when pressing Escape.
  78. $iframeBody.on( 'keydown', function( event ) {
  79. if ( 27 !== event.which ) {
  80. return;
  81. }
  82. tb_remove();
  83. });
  84. }
  85. /*
  86. * Get the tabbable elements and detach/attach the keydown event.
  87. * Called after the iframe has fully loaded so we have all the elements we need.
  88. * Called again each time a Tab gets clicked.
  89. * @todo Consider to implement a WordPress general utility for this and don't use jQuery UI.
  90. */
  91. function handleTabbables() {
  92. var $firstAndLast;
  93. // Get all the tabbable elements.
  94. $tabbables = $( ':tabbable', $iframeBody );
  95. // Our first tabbable element is always the "Close" button.
  96. $firstTabbable = tbWindow.find( '#TB_closeWindowButton' );
  97. // Get the last tabbable element.
  98. $lastTabbable = $tabbables.last();
  99. // Make a jQuery collection.
  100. $firstAndLast = $firstTabbable.add( $lastTabbable );
  101. // Detach any previously attached keydown event.
  102. $firstAndLast.off( 'keydown.wp-plugin-details' );
  103. // Attach again the keydown event on the first and last focusable elements.
  104. $firstAndLast.on( 'keydown.wp-plugin-details', function( event ) {
  105. constrainTabbing( event );
  106. });
  107. }
  108. // Constrain tabbing within the plugin modal dialog.
  109. function constrainTabbing( event ) {
  110. if ( 9 !== event.which ) {
  111. return;
  112. }
  113. if ( $lastTabbable[0] === event.target && ! event.shiftKey ) {
  114. event.preventDefault();
  115. $firstTabbable.focus();
  116. } else if ( $firstTabbable[0] === event.target && event.shiftKey ) {
  117. event.preventDefault();
  118. $lastTabbable.focus();
  119. }
  120. }
  121. // Open the Plugin details modal.
  122. $( '.thickbox.open-plugin-details-modal' ).on( 'click', function( e ) {
  123. // The `data-title` attribute is used only in the Plugin screens.
  124. var title = $( this ).data( 'title' ) ? plugininstallL10n.plugin_information + ' ' + $( this ).data( 'title' ) : plugininstallL10n.plugin_modal_label;
  125. e.preventDefault();
  126. e.stopPropagation();
  127. // Store the element that has focus before opening the modal dialog, i.e. the control which opens it.
  128. $focusedBefore = $( this );
  129. tb_click.call(this);
  130. // Set ARIA role and ARIA label.
  131. tbWindow.attr({
  132. 'role': 'dialog',
  133. 'aria-label': plugininstallL10n.plugin_modal_label
  134. });
  135. // Set title attribute on the iframe.
  136. tbWindow.find( '#TB_iframeContent' ).attr( 'title', title );
  137. });
  138. /* Plugin install related JS */
  139. $( '#plugin-information-tabs a' ).click( function( event ) {
  140. var tab = $( this ).attr( 'name' );
  141. event.preventDefault();
  142. // Flip the tab
  143. $( '#plugin-information-tabs a.current' ).removeClass( 'current' );
  144. $( this ).addClass( 'current' );
  145. // Only show the fyi box in the description section, on smaller screen, where it's otherwise always displayed at the top.
  146. if ( 'description' !== tab && $( window ).width() < 772 ) {
  147. $( '#plugin-information-content' ).find( '.fyi' ).hide();
  148. } else {
  149. $( '#plugin-information-content' ).find( '.fyi' ).show();
  150. }
  151. // Flip the content.
  152. $( '#section-holder div.section' ).hide(); // Hide 'em all.
  153. $( '#section-' + tab ).show();
  154. });
  155. /*
  156. * When a user presses the "Upload Plugin" button, show the upload form in place
  157. * rather than sending them to the devoted upload plugin page.
  158. * The `?tab=upload` page still exists for no-js support and for plugins that
  159. * might access it directly. When we're in this page, let the link behave
  160. * like a link. Otherwise we're in the normal plugin installer pages and the
  161. * link should behave like a toggle button.
  162. */
  163. if ( ! $wrap.hasClass( 'plugin-install-tab-upload' ) ) {
  164. $uploadViewToggle
  165. .attr({
  166. role: 'button',
  167. 'aria-expanded': 'false'
  168. })
  169. .on( 'click', function( event ) {
  170. event.preventDefault();
  171. $body.toggleClass( 'show-upload-view' );
  172. $uploadViewToggle.attr( 'aria-expanded', $body.hasClass( 'show-upload-view' ) );
  173. });
  174. }
  175. });