| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 /** 2 * @file Functionality for the plugin install screens. 3 * 4 * @output wp-admin/js/plugin-install.js 5 */ 6 7 /* global tb_click, tb_remove, tb_position */ 8 9 /** 10 * Initializes the plugin install screens. 11 * 12 * @param {JQueryStatic} $ The jQuery object. 13 */ 14 jQuery( function( $ ) { 15 16 var tbWindow, 17 $iframeBody, 18 $tabbables, 19 $firstTabbable, 20 $lastTabbable, 21 $focusedBefore = $(), 22 $uploadViewToggle = $( '.upload-view-toggle' ), 23 $wrap = $ ( '.wrap' ), 24 $body = $( document.body ); 25 26 window.tb_position = function() { 27 var width = $( window ).width(), 28 H = $( window ).height() - ( ( 792 < width ) ? 60 : 40 ), 29 W = ( 792 < width ) ? 772 : width - 20; 30 31 tbWindow = $( '#TB_window' ); 32 33 if ( tbWindow.length ) { 34 tbWindow.width( W ).height( H ); 35 $( '#TB_iframeContent' ).width( W ).height( H ); 36 tbWindow.css({ 37 'margin-left': '-' + parseInt( ( W / 2 ), 10 ) + 'px' 38 }); 39 if ( typeof document.body.style.maxWidth !== 'undefined' ) { 40 tbWindow.css({ 41 'top': '30px', 42 'margin-top': '0' 43 }); 44 } 45 } 46 47 return $( 'a.thickbox' ).each( function() { 48 var href = $( this ).attr( 'href' ); 49 if ( ! href ) { 50 return; 51 } 52 href = href.replace( /&width=[0-9]+/g, '' ); 53 href = href.replace( /&height=[0-9]+/g, '' ); 54 $(this).attr( 'href', href + '&width=' + W + '&height=' + ( H ) ); 55 }); 56 }; 57 58 $( window ).on( 'resize', function() { 59 tb_position(); 60 }); 61 62 /* 63 * Custom events: when a Thickbox iframe has loaded and when the Thickbox 64 * modal gets removed from the DOM. 65 */ 66 $body 67 .on( 'thickbox:iframe:loaded', tbWindow, function() { 68 /* 69 * Return if it's not the modal with the plugin details iframe. Other 70 * thickbox instances might want to load an iframe with content from 71 * an external domain. Avoid to access the iframe contents when we're 72 * not sure the iframe loads from the same domain. 73 */ 74 if ( ! tbWindow.hasClass( 'plugin-details-modal' ) ) { 75 return; 76 } 77 78 iframeLoaded(); 79 }) 80 .on( 'thickbox:removed', function() { 81 // Set focus back to the element that opened the modal dialog. 82 // Note: IE 8 would need this wrapped in a fake setTimeout `0`. 83 $focusedBefore.trigger( 'focus' ); 84 }); 85 86 /** 87 * Initializes the plugin details modal dialog after the iframe has fully loaded. 88 */ 89 function iframeLoaded() { 90 var $iframe = tbWindow.find( '#TB_iframeContent' ); 91 92 // Get the iframe body. 93 $iframeBody = $iframe.contents().find( 'body' ); 94 95 // Get the tabbable elements and handle the keydown event on first load. 96 handleTabbables(); 97 98 // Set initial focus on the "Close" button. 99 $firstTabbable.trigger( 'focus' ); 100 101 /* 102 * When the "Install" button is disabled (e.g. the Plugin is already installed) 103 * then we can't predict where the last focusable element is. We need to get 104 * the tabbable elements and handle the keydown event again and again, 105 * each time the active tab panel changes. 106 */ 107 $( '#plugin-information-tabs a', $iframeBody ).on( 'click', function() { 108 handleTabbables(); 109 }); 110 111 // Close the modal when pressing Escape. 112 $iframeBody.on( 'keydown', function( event ) { 113 if ( 27 !== event.which ) { 114 return; 115 } 116 tb_remove(); 117 }); 118 } 119 120 /** 121 * Gets the tabbable elements and detaches/attaches the keydown event. 122 * 123 * Called after the iframe has fully loaded so we have all the elements we need. 124 * Called again each time a Tab gets clicked. 125 * @todo Consider to implement a WordPress general utility for this and don't use jQuery UI. 126 */ 127 function handleTabbables() { 128 var $firstAndLast; 129 // Get all the tabbable elements. 130 $tabbables = $( ':tabbable', $iframeBody ); 131 // Our first tabbable element is always the "Close" button. 132 $firstTabbable = tbWindow.find( '#TB_closeWindowButton' ); 133 // Get the last tabbable element. 134 $lastTabbable = $tabbables.last(); 135 // Make a jQuery collection. 136 $firstAndLast = $firstTabbable.add( $lastTabbable ); 137 // Detach any previously attached keydown event. 138 $firstAndLast.off( 'keydown.wp-plugin-details' ); 139 // Attach again the keydown event on the first and last focusable elements. 140 $firstAndLast.on( 'keydown.wp-plugin-details', function( event ) { 141 constrainTabbing( event ); 142 }); 143 } 144 145 /** 146 * Constrains tabbing within the plugin modal dialog. 147 * 148 * @param {JQuery.Event} event The keydown event. 149 */ 150 function constrainTabbing( event ) { 151 if ( 9 !== event.which ) { 152 return; 153 } 154 155 if ( $lastTabbable[0] === event.target && ! event.shiftKey ) { 156 event.preventDefault(); 157 $firstTabbable.trigger( 'focus' ); 158 } else if ( $firstTabbable[0] === event.target && event.shiftKey ) { 159 event.preventDefault(); 160 $lastTabbable.trigger( 'focus' ); 161 } 162 } 163 164 /** 165 * Opens the Plugin details modal. 166 * 167 * The event is delegated to get also the links in the plugins search tab, 168 * after the Ajax search rebuilds the HTML. It's delegated on the closest 169 * ancestor and not on the body to avoid conflicts with other handlers, see 170 * Trac ticket #43082. 171 */ 172 $( '.wrap' ).on( 'click', '.thickbox.open-plugin-details-modal', function( e ) { 173 // The `data-title` attribute is used only in the Plugin screens. 174 var title = $( this ).data( 'title' ) ? 175 wp.i18n.sprintf( 176 // translators: %s: Plugin name. 177 wp.i18n.__( 'Plugin: %s' ), 178 $( this ).data( 'title' ) 179 ) : 180 wp.i18n.__( 'Plugin details' ); 181 182 e.preventDefault(); 183 e.stopPropagation(); 184 185 // Store the element that has focus before opening the modal dialog, i.e. the control which opens it. 186 $focusedBefore = $( this ); 187 188 tb_click.call(this); 189 190 // Set ARIA role, ARIA label, and add a CSS class. 191 tbWindow 192 .attr({ 193 'role': 'dialog', 194 'aria-label': wp.i18n.__( 'Plugin details' ) 195 }) 196 .addClass( 'plugin-details-modal' ); 197 198 // Set title attribute on the iframe. 199 tbWindow.find( '#TB_iframeContent' ).attr( 'title', title ); 200 }); 201 202 /* Plugin install related JS */ 203 $( '#plugin-information-tabs a' ).on( 'click', function( event ) { 204 var tab = $( this ).attr( 'name' ); 205 event.preventDefault(); 206 207 // Flip the tab. 208 $( '#plugin-information-tabs a.current' ).removeClass( 'current' ); 209 $( this ).addClass( 'current' ); 210 211 // Only show the fyi box in the description section, on smaller screen, 212 // where it's otherwise always displayed at the top. 213 if ( 'description' !== tab && $( window ).width() < 772 ) { 214 $( '#plugin-information-content' ).find( '.fyi' ).hide(); 215 } else { 216 $( '#plugin-information-content' ).find( '.fyi' ).show(); 217 } 218 219 // Flip the content. 220 $( '#section-holder div.section' ).hide(); // Hide 'em all. 221 $( '#section-' + tab ).show(); 222 }); 223 224 /* 225 * When a user presses the "Upload Plugin" button, show the upload form in place 226 * rather than sending them to the devoted upload plugin page. 227 * The `?tab=upload` page still exists for no-js support and for plugins that 228 * might access it directly. When we're in this page, let the link behave 229 * like a link. Otherwise we're in the normal plugin installer pages and the 230 * link should behave like a toggle button. 231 */ 232 if ( ! $wrap.hasClass( 'plugin-install-tab-upload' ) ) { 233 $uploadViewToggle 234 .attr({ 235 role: 'button', 236 'aria-expanded': 'false' 237 }) 238 .on( 'click', function( event ) { 239 event.preventDefault(); 240 $body.toggleClass( 'show-upload-view' ); 241 $uploadViewToggle.attr( 'aria-expanded', $body.hasClass( 'show-upload-view' ) ); 242 }); 243 } 244 });
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Thu Sep 10 08:20:30 2026 | Cross-referenced by PHPXref |