1 /* global tb_remove */ |
1 /** |
2 window.wp = window.wp || {}; |
2 * Functions for ajaxified updates, deletions and installs inside the WordPress admin. |
3 |
3 * |
4 (function( $, wp, pagenow ) { |
4 * @version 4.2.0 |
|
5 * |
|
6 * @package WordPress |
|
7 * @subpackage Administration |
|
8 */ |
|
9 |
|
10 /* global pagenow */ |
|
11 |
|
12 /** |
|
13 * @param {jQuery} $ jQuery object. |
|
14 * @param {object} wp WP object. |
|
15 * @param {object} settings WP Updates settings. |
|
16 * @param {string} settings.ajax_nonce AJAX nonce. |
|
17 * @param {object} settings.l10n Translation strings. |
|
18 * @param {object=} settings.plugins Base names of plugins in their different states. |
|
19 * @param {Array} settings.plugins.all Base names of all plugins. |
|
20 * @param {Array} settings.plugins.active Base names of active plugins. |
|
21 * @param {Array} settings.plugins.inactive Base names of inactive plugins. |
|
22 * @param {Array} settings.plugins.upgrade Base names of plugins with updates available. |
|
23 * @param {Array} settings.plugins.recently_activated Base names of recently activated plugins. |
|
24 * @param {object=} settings.themes Plugin/theme status information or null. |
|
25 * @param {number} settings.themes.all Amount of all themes. |
|
26 * @param {number} settings.themes.upgrade Amount of themes with updates available. |
|
27 * @param {number} settings.themes.disabled Amount of disabled themes. |
|
28 * @param {object=} settings.totals Combined information for available update counts. |
|
29 * @param {number} settings.totals.count Holds the amount of available updates. |
|
30 */ |
|
31 (function( $, wp, settings ) { |
|
32 var $document = $( document ); |
|
33 |
|
34 wp = wp || {}; |
|
35 |
|
36 /** |
|
37 * The WP Updates object. |
|
38 * |
|
39 * @since 4.2.0 |
|
40 * |
|
41 * @type {object} |
|
42 */ |
5 wp.updates = {}; |
43 wp.updates = {}; |
6 |
44 |
7 /** |
45 /** |
8 * User nonce for ajax calls. |
46 * User nonce for ajax calls. |
9 * |
47 * |
10 * @since 4.2.0 |
48 * @since 4.2.0 |
11 * |
49 * |
12 * @var string |
50 * @type {string} |
13 */ |
51 */ |
14 wp.updates.ajaxNonce = window._wpUpdatesSettings.ajax_nonce; |
52 wp.updates.ajaxNonce = settings.ajax_nonce; |
15 |
53 |
16 /** |
54 /** |
17 * Localized strings. |
55 * Localized strings. |
18 * |
56 * |
19 * @since 4.2.0 |
57 * @since 4.2.0 |
20 * |
58 * |
21 * @var object |
59 * @type {object} |
22 */ |
60 */ |
23 wp.updates.l10n = window._wpUpdatesSettings.l10n; |
61 wp.updates.l10n = settings.l10n; |
|
62 |
|
63 /** |
|
64 * Current search term. |
|
65 * |
|
66 * @since 4.6.0 |
|
67 * |
|
68 * @type {string} |
|
69 */ |
|
70 wp.updates.searchTerm = ''; |
24 |
71 |
25 /** |
72 /** |
26 * Whether filesystem credentials need to be requested from the user. |
73 * Whether filesystem credentials need to be requested from the user. |
27 * |
74 * |
28 * @since 4.2.0 |
75 * @since 4.2.0 |
29 * |
76 * |
30 * @var bool |
77 * @type {bool} |
31 */ |
78 */ |
32 wp.updates.shouldRequestFilesystemCredentials = null; |
79 wp.updates.shouldRequestFilesystemCredentials = false; |
33 |
80 |
34 /** |
81 /** |
35 * Filesystem credentials to be packaged along with the request. |
82 * Filesystem credentials to be packaged along with the request. |
36 * |
83 * |
37 * @since 4.2.0 |
84 * @since 4.2.0 |
38 * |
85 * @since 4.6.0 Added `available` property to indicate whether credentials have been provided. |
39 * @var object |
86 * |
|
87 * @type {object} filesystemCredentials Holds filesystem credentials. |
|
88 * @type {object} filesystemCredentials.ftp Holds FTP credentials. |
|
89 * @type {string} filesystemCredentials.ftp.host FTP host. Default empty string. |
|
90 * @type {string} filesystemCredentials.ftp.username FTP user name. Default empty string. |
|
91 * @type {string} filesystemCredentials.ftp.password FTP password. Default empty string. |
|
92 * @type {string} filesystemCredentials.ftp.connectionType Type of FTP connection. 'ssh', 'ftp', or 'ftps'. |
|
93 * Default empty string. |
|
94 * @type {object} filesystemCredentials.ssh Holds SSH credentials. |
|
95 * @type {string} filesystemCredentials.ssh.publicKey The public key. Default empty string. |
|
96 * @type {string} filesystemCredentials.ssh.privateKey The private key. Default empty string. |
|
97 * @type {string} filesystemCredentials.fsNonce Filesystem credentials form nonce. |
|
98 * @type {bool} filesystemCredentials.available Whether filesystem credentials have been provided. |
|
99 * Default 'false'. |
40 */ |
100 */ |
41 wp.updates.filesystemCredentials = { |
101 wp.updates.filesystemCredentials = { |
42 ftp: { |
102 ftp: { |
43 host: null, |
103 host: '', |
44 username: null, |
104 username: '', |
45 password: null, |
105 password: '', |
46 connectionType: null |
106 connectionType: '' |
47 }, |
107 }, |
48 ssh: { |
108 ssh: { |
49 publicKey: null, |
109 publicKey: '', |
50 privateKey: null |
110 privateKey: '' |
51 } |
111 }, |
52 }; |
112 fsNonce: '', |
53 |
113 available: false |
54 /** |
114 }; |
55 * Flag if we're waiting for an update to complete. |
115 |
|
116 /** |
|
117 * Whether we're waiting for an Ajax request to complete. |
56 * |
118 * |
57 * @since 4.2.0 |
119 * @since 4.2.0 |
58 * |
120 * @since 4.6.0 More accurately named `ajaxLocked`. |
59 * @var bool |
121 * |
60 */ |
122 * @type {bool} |
61 wp.updates.updateLock = false; |
123 */ |
62 |
124 wp.updates.ajaxLocked = false; |
63 /** |
125 |
64 * * Flag if we've done an update successfully. |
126 /** |
65 * |
127 * Admin notice template. |
66 * @since 4.2.0 |
128 * |
67 * |
129 * @since 4.6.0 |
68 * @var bool |
130 * |
69 */ |
131 * @type {function} A function that lazily-compiles the template requested. |
70 wp.updates.updateDoneSuccessfully = false; |
132 */ |
71 |
133 wp.updates.adminNotice = wp.template( 'wp-updates-admin-notice' ); |
72 /** |
134 |
|
135 /** |
|
136 * Update queue. |
|
137 * |
73 * If the user tries to update a plugin while an update is |
138 * If the user tries to update a plugin while an update is |
74 * already happening, it can be placed in this queue to perform later. |
139 * already happening, it can be placed in this queue to perform later. |
75 * |
140 * |
76 * @since 4.2.0 |
141 * @since 4.2.0 |
77 * |
142 * @since 4.6.0 More accurately named `queue`. |
78 * @var array |
143 * |
79 */ |
144 * @type {Array.object} |
80 wp.updates.updateQueue = []; |
145 */ |
81 |
146 wp.updates.queue = []; |
82 /** |
147 |
83 * Store a jQuery reference to return focus to when exiting the request credentials modal. |
148 /** |
|
149 * Holds a jQuery reference to return focus to when exiting the request credentials modal. |
84 * |
150 * |
85 * @since 4.2.0 |
151 * @since 4.2.0 |
86 * |
152 * |
87 * @var jQuery object |
153 * @type {jQuery} |
88 */ |
154 */ |
89 wp.updates.$elToReturnFocusToFromCredentialsModal = null; |
155 wp.updates.$elToReturnFocusToFromCredentialsModal = undefined; |
90 |
156 |
91 /** |
157 /** |
92 * Decrement update counts throughout the various menus. |
158 * Adds or updates an admin notice. |
93 * |
159 * |
94 * @since 3.9.0 |
160 * @since 4.6.0 |
95 * |
161 * |
96 * @param {string} updateType |
162 * @param {object} data |
97 */ |
163 * @param {*=} data.selector Optional. Selector of an element to be replaced with the admin notice. |
98 wp.updates.decrementCount = function( upgradeType ) { |
164 * @param {string=} data.id Optional. Unique id that will be used as the notice's id attribute. |
99 var count, |
165 * @param {string=} data.className Optional. Class names that will be used in the admin notice. |
100 pluginCount, |
166 * @param {string=} data.message Optional. The message displayed in the notice. |
101 $adminBarUpdateCount = $( '#wp-admin-bar-updates .ab-label' ), |
167 * @param {number=} data.successes Optional. The amount of successful operations. |
102 $dashboardNavMenuUpdateCount = $( 'a[href="update-core.php"] .update-plugins' ), |
168 * @param {number=} data.errors Optional. The amount of failed operations. |
103 $pluginsMenuItem = $( '#menu-plugins' ); |
169 * @param {Array=} data.errorMessages Optional. Error messages of failed operations. |
104 |
170 * |
105 |
171 */ |
106 count = $adminBarUpdateCount.text(); |
172 wp.updates.addAdminNotice = function( data ) { |
107 count = parseInt( count, 10 ) - 1; |
173 var $notice = $( data.selector ), $adminNotice; |
108 if ( count < 0 || isNaN( count ) ) { |
174 |
109 return; |
175 delete data.selector; |
110 } |
176 $adminNotice = wp.updates.adminNotice( data ); |
111 $( '#wp-admin-bar-updates .ab-item' ).removeAttr( 'title' ); |
177 |
112 $adminBarUpdateCount.text( count ); |
178 // Check if this admin notice already exists. |
113 |
179 if ( ! $notice.length ) { |
114 |
180 $notice = $( '#' + data.id ); |
115 $dashboardNavMenuUpdateCount.each( function( index, elem ) { |
181 } |
116 elem.className = elem.className.replace( /count-\d+/, 'count-' + count ); |
182 |
117 } ); |
183 if ( $notice.length ) { |
118 $dashboardNavMenuUpdateCount.removeAttr( 'title' ); |
184 $notice.replaceWith( $adminNotice ); |
119 $dashboardNavMenuUpdateCount.find( '.update-count' ).text( count ); |
185 } else { |
120 |
186 if ( 'customize' === pagenow ) { |
121 if ( 'plugin' === upgradeType ) { |
187 $( '.customize-themes-notifications' ).append( $adminNotice ); |
122 pluginCount = $pluginsMenuItem.find( '.plugin-count' ).eq(0).text(); |
188 } else { |
123 pluginCount = parseInt( pluginCount, 10 ) - 1; |
189 $( '.wrap' ).find( '> h1' ).after( $adminNotice ); |
124 if ( pluginCount < 0 || isNaN( pluginCount ) ) { |
190 } |
125 return; |
191 } |
126 } |
192 |
127 $pluginsMenuItem.find( '.plugin-count' ).text( pluginCount ); |
193 $document.trigger( 'wp-updates-notice-added' ); |
128 $pluginsMenuItem.find( '.update-plugins' ).each( function( index, elem ) { |
194 }; |
129 elem.className = elem.className.replace( /count-\d+/, 'count-' + pluginCount ); |
195 |
|
196 /** |
|
197 * Handles Ajax requests to WordPress. |
|
198 * |
|
199 * @since 4.6.0 |
|
200 * |
|
201 * @param {string} action The type of Ajax request ('update-plugin', 'install-theme', etc). |
|
202 * @param {object} data Data that needs to be passed to the ajax callback. |
|
203 * @return {$.promise} A jQuery promise that represents the request, |
|
204 * decorated with an abort() method. |
|
205 */ |
|
206 wp.updates.ajax = function( action, data ) { |
|
207 var options = {}; |
|
208 |
|
209 if ( wp.updates.ajaxLocked ) { |
|
210 wp.updates.queue.push( { |
|
211 action: action, |
|
212 data: data |
130 } ); |
213 } ); |
131 |
214 |
132 if (pluginCount > 0 ) { |
215 // Return a Deferred object so callbacks can always be registered. |
133 $( '.subsubsub .upgrade .count' ).text( '(' + pluginCount + ')' ); |
216 return $.Deferred(); |
134 } else { |
217 } |
135 $( '.subsubsub .upgrade' ).remove(); |
218 |
136 } |
219 wp.updates.ajaxLocked = true; |
137 } |
220 |
138 }; |
221 if ( data.success ) { |
139 |
222 options.success = data.success; |
140 /** |
223 delete data.success; |
141 * Send an Ajax request to the server to update a plugin. |
224 } |
142 * |
225 |
143 * @since 4.2.0 |
226 if ( data.error ) { |
144 * |
227 options.error = data.error; |
145 * @param {string} plugin |
228 delete data.error; |
146 * @param {string} slug |
229 } |
147 */ |
230 |
148 wp.updates.updatePlugin = function( plugin, slug ) { |
231 options.data = _.extend( data, { |
149 var $message, name; |
232 action: action, |
150 if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) { |
|
151 $message = $( '[data-slug="' + slug + '"]' ).next().find( '.update-message' ); |
|
152 } else if ( 'plugin-install' === pagenow ) { |
|
153 $message = $( '.plugin-card-' + slug ).find( '.update-now' ); |
|
154 name = $message.data( 'name' ); |
|
155 $message.attr( 'aria-label', wp.updates.l10n.updatingLabel.replace( '%s', name ) ); |
|
156 } |
|
157 |
|
158 $message.addClass( 'updating-message' ); |
|
159 if ( $message.html() !== wp.updates.l10n.updating ){ |
|
160 $message.data( 'originaltext', $message.html() ); |
|
161 } |
|
162 |
|
163 $message.text( wp.updates.l10n.updating ); |
|
164 wp.a11y.speak( wp.updates.l10n.updatingMsg ); |
|
165 |
|
166 if ( wp.updates.updateLock ) { |
|
167 wp.updates.updateQueue.push( { |
|
168 type: 'update-plugin', |
|
169 data: { |
|
170 plugin: plugin, |
|
171 slug: slug |
|
172 } |
|
173 } ); |
|
174 return; |
|
175 } |
|
176 |
|
177 wp.updates.updateLock = true; |
|
178 |
|
179 var data = { |
|
180 _ajax_nonce: wp.updates.ajaxNonce, |
233 _ajax_nonce: wp.updates.ajaxNonce, |
181 plugin: plugin, |
234 _fs_nonce: wp.updates.filesystemCredentials.fsNonce, |
182 slug: slug, |
|
183 username: wp.updates.filesystemCredentials.ftp.username, |
235 username: wp.updates.filesystemCredentials.ftp.username, |
184 password: wp.updates.filesystemCredentials.ftp.password, |
236 password: wp.updates.filesystemCredentials.ftp.password, |
185 hostname: wp.updates.filesystemCredentials.ftp.hostname, |
237 hostname: wp.updates.filesystemCredentials.ftp.hostname, |
186 connection_type: wp.updates.filesystemCredentials.ftp.connectionType, |
238 connection_type: wp.updates.filesystemCredentials.ftp.connectionType, |
187 public_key: wp.updates.filesystemCredentials.ssh.publicKey, |
239 public_key: wp.updates.filesystemCredentials.ssh.publicKey, |
188 private_key: wp.updates.filesystemCredentials.ssh.privateKey |
240 private_key: wp.updates.filesystemCredentials.ssh.privateKey |
189 }; |
241 } ); |
190 |
242 |
191 wp.ajax.post( 'update-plugin', data ) |
243 return wp.ajax.send( options ).always( wp.updates.ajaxAlways ); |
192 .done( wp.updates.updateSuccess ) |
244 }; |
193 .fail( wp.updates.updateError ); |
245 |
194 }; |
246 /** |
195 |
247 * Actions performed after every Ajax request. |
196 /** |
248 * |
197 * On a successful plugin update, update the UI with the result. |
249 * @since 4.6.0 |
|
250 * |
|
251 * @param {object} response |
|
252 * @param {array=} response.debug Optional. Debug information. |
|
253 * @param {string=} response.errorCode Optional. Error code for an error that occurred. |
|
254 */ |
|
255 wp.updates.ajaxAlways = function( response ) { |
|
256 if ( ! response.errorCode || 'unable_to_connect_to_filesystem' !== response.errorCode ) { |
|
257 wp.updates.ajaxLocked = false; |
|
258 wp.updates.queueChecker(); |
|
259 } |
|
260 |
|
261 if ( 'undefined' !== typeof response.debug && window.console && window.console.log ) { |
|
262 _.map( response.debug, function( message ) { |
|
263 window.console.log( $( '<p />' ).html( message ).text() ); |
|
264 } ); |
|
265 } |
|
266 }; |
|
267 |
|
268 /** |
|
269 * Refreshes update counts everywhere on the screen. |
|
270 * |
|
271 * @since 4.7.0 |
|
272 */ |
|
273 wp.updates.refreshCount = function() { |
|
274 var $adminBarUpdates = $( '#wp-admin-bar-updates' ), |
|
275 $dashboardNavMenuUpdateCount = $( 'a[href="update-core.php"] .update-plugins' ), |
|
276 $pluginsNavMenuUpdateCount = $( 'a[href="plugins.php"] .update-plugins' ), |
|
277 $appearanceNavMenuUpdateCount = $( 'a[href="themes.php"] .update-plugins' ), |
|
278 itemCount; |
|
279 |
|
280 $adminBarUpdates.find( '.ab-item' ).removeAttr( 'title' ); |
|
281 $adminBarUpdates.find( '.ab-label' ).text( settings.totals.counts.total ); |
|
282 |
|
283 // Remove the update count from the toolbar if it's zero. |
|
284 if ( 0 === settings.totals.counts.total ) { |
|
285 $adminBarUpdates.find( '.ab-label' ).parents( 'li' ).remove(); |
|
286 } |
|
287 |
|
288 // Update the "Updates" menu item. |
|
289 $dashboardNavMenuUpdateCount.each( function( index, element ) { |
|
290 element.className = element.className.replace( /count-\d+/, 'count-' + settings.totals.counts.total ); |
|
291 } ); |
|
292 if ( settings.totals.counts.total > 0 ) { |
|
293 $dashboardNavMenuUpdateCount.find( '.update-count' ).text( settings.totals.counts.total ); |
|
294 } else { |
|
295 $dashboardNavMenuUpdateCount.remove(); |
|
296 } |
|
297 |
|
298 // Update the "Plugins" menu item. |
|
299 $pluginsNavMenuUpdateCount.each( function( index, element ) { |
|
300 element.className = element.className.replace( /count-\d+/, 'count-' + settings.totals.counts.plugins ); |
|
301 } ); |
|
302 if ( settings.totals.counts.total > 0 ) { |
|
303 $pluginsNavMenuUpdateCount.find( '.plugin-count' ).text( settings.totals.counts.plugins ); |
|
304 } else { |
|
305 $pluginsNavMenuUpdateCount.remove(); |
|
306 } |
|
307 |
|
308 // Update the "Appearance" menu item. |
|
309 $appearanceNavMenuUpdateCount.each( function( index, element ) { |
|
310 element.className = element.className.replace( /count-\d+/, 'count-' + settings.totals.counts.themes ); |
|
311 } ); |
|
312 if ( settings.totals.counts.total > 0 ) { |
|
313 $appearanceNavMenuUpdateCount.find( '.theme-count' ).text( settings.totals.counts.themes ); |
|
314 } else { |
|
315 $appearanceNavMenuUpdateCount.remove(); |
|
316 } |
|
317 |
|
318 // Update list table filter navigation. |
|
319 if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) { |
|
320 itemCount = settings.totals.counts.plugins; |
|
321 } else if ( 'themes' === pagenow || 'themes-network' === pagenow ) { |
|
322 itemCount = settings.totals.counts.themes; |
|
323 } |
|
324 |
|
325 if ( itemCount > 0 ) { |
|
326 $( '.subsubsub .upgrade .count' ).text( '(' + itemCount + ')' ); |
|
327 } else { |
|
328 $( '.subsubsub .upgrade' ).remove(); |
|
329 $( '.subsubsub li:last' ).html( function() { return $( this ).children(); } ); |
|
330 } |
|
331 }; |
|
332 |
|
333 /** |
|
334 * Decrements the update counts throughout the various menus. |
|
335 * |
|
336 * This includes the toolbar, the "Updates" menu item and the menu items |
|
337 * for plugins and themes. |
|
338 * |
|
339 * @since 3.9.0 |
|
340 * |
|
341 * @param {string} type The type of item that was updated or deleted. |
|
342 * Can be 'plugin', 'theme'. |
|
343 */ |
|
344 wp.updates.decrementCount = function( type ) { |
|
345 settings.totals.counts.total = Math.max( --settings.totals.counts.total, 0 ); |
|
346 |
|
347 if ( 'plugin' === type ) { |
|
348 settings.totals.counts.plugins = Math.max( --settings.totals.counts.plugins, 0 ); |
|
349 } else if ( 'theme' === type ) { |
|
350 settings.totals.counts.themes = Math.max( --settings.totals.counts.themes, 0 ); |
|
351 } |
|
352 |
|
353 wp.updates.refreshCount( type ); |
|
354 }; |
|
355 |
|
356 /** |
|
357 * Sends an Ajax request to the server to update a plugin. |
198 * |
358 * |
199 * @since 4.2.0 |
359 * @since 4.2.0 |
200 * |
360 * @since 4.6.0 More accurately named `updatePlugin`. |
|
361 * |
|
362 * @param {object} args Arguments. |
|
363 * @param {string} args.plugin Plugin basename. |
|
364 * @param {string} args.slug Plugin slug. |
|
365 * @param {updatePluginSuccess=} args.success Optional. Success callback. Default: wp.updates.updatePluginSuccess |
|
366 * @param {updatePluginError=} args.error Optional. Error callback. Default: wp.updates.updatePluginError |
|
367 * @return {$.promise} A jQuery promise that represents the request, |
|
368 * decorated with an abort() method. |
|
369 */ |
|
370 wp.updates.updatePlugin = function( args ) { |
|
371 var $updateRow, $card, $message, message; |
|
372 |
|
373 args = _.extend( { |
|
374 success: wp.updates.updatePluginSuccess, |
|
375 error: wp.updates.updatePluginError |
|
376 }, args ); |
|
377 |
|
378 if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) { |
|
379 $updateRow = $( 'tr[data-plugin="' + args.plugin + '"]' ); |
|
380 $message = $updateRow.find( '.update-message' ).removeClass( 'notice-error' ).addClass( 'updating-message notice-warning' ).find( 'p' ); |
|
381 message = wp.updates.l10n.pluginUpdatingLabel.replace( '%s', $updateRow.find( '.plugin-title strong' ).text() ); |
|
382 } else if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) { |
|
383 $card = $( '.plugin-card-' + args.slug ); |
|
384 $message = $card.find( '.update-now' ).addClass( 'updating-message' ); |
|
385 message = wp.updates.l10n.pluginUpdatingLabel.replace( '%s', $message.data( 'name' ) ); |
|
386 |
|
387 // Remove previous error messages, if any. |
|
388 $card.removeClass( 'plugin-card-update-failed' ).find( '.notice.notice-error' ).remove(); |
|
389 } |
|
390 |
|
391 if ( $message.html() !== wp.updates.l10n.updating ) { |
|
392 $message.data( 'originaltext', $message.html() ); |
|
393 } |
|
394 |
|
395 $message |
|
396 .attr( 'aria-label', message ) |
|
397 .text( wp.updates.l10n.updating ); |
|
398 |
|
399 $document.trigger( 'wp-plugin-updating', args ); |
|
400 |
|
401 return wp.updates.ajax( 'update-plugin', args ); |
|
402 }; |
|
403 |
|
404 /** |
|
405 * Updates the UI appropriately after a successful plugin update. |
|
406 * |
|
407 * @since 4.2.0 |
|
408 * @since 4.6.0 More accurately named `updatePluginSuccess`. |
|
409 * |
|
410 * @typedef {object} updatePluginSuccess |
|
411 * @param {object} response Response from the server. |
|
412 * @param {string} response.slug Slug of the plugin to be updated. |
|
413 * @param {string} response.plugin Basename of the plugin to be updated. |
|
414 * @param {string} response.pluginName Name of the plugin to be updated. |
|
415 * @param {string} response.oldVersion Old version of the plugin. |
|
416 * @param {string} response.newVersion New version of the plugin. |
|
417 */ |
|
418 wp.updates.updatePluginSuccess = function( response ) { |
|
419 var $pluginRow, $updateMessage, newText; |
|
420 |
|
421 if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) { |
|
422 $pluginRow = $( 'tr[data-plugin="' + response.plugin + '"]' ) |
|
423 .removeClass( 'update' ) |
|
424 .addClass( 'updated' ); |
|
425 $updateMessage = $pluginRow.find( '.update-message' ) |
|
426 .removeClass( 'updating-message notice-warning' ) |
|
427 .addClass( 'updated-message notice-success' ).find( 'p' ); |
|
428 |
|
429 // Update the version number in the row. |
|
430 newText = $pluginRow.find( '.plugin-version-author-uri' ).html().replace( response.oldVersion, response.newVersion ); |
|
431 $pluginRow.find( '.plugin-version-author-uri' ).html( newText ); |
|
432 } else if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) { |
|
433 $updateMessage = $( '.plugin-card-' + response.slug ).find( '.update-now' ) |
|
434 .removeClass( 'updating-message' ) |
|
435 .addClass( 'button-disabled updated-message' ); |
|
436 } |
|
437 |
|
438 $updateMessage |
|
439 .attr( 'aria-label', wp.updates.l10n.pluginUpdatedLabel.replace( '%s', response.pluginName ) ) |
|
440 .text( wp.updates.l10n.pluginUpdated ); |
|
441 |
|
442 wp.a11y.speak( wp.updates.l10n.updatedMsg, 'polite' ); |
|
443 |
|
444 wp.updates.decrementCount( 'plugin' ); |
|
445 |
|
446 $document.trigger( 'wp-plugin-update-success', response ); |
|
447 }; |
|
448 |
|
449 /** |
|
450 * Updates the UI appropriately after a failed plugin update. |
|
451 * |
|
452 * @since 4.2.0 |
|
453 * @since 4.6.0 More accurately named `updatePluginError`. |
|
454 * |
|
455 * @typedef {object} updatePluginError |
|
456 * @param {object} response Response from the server. |
|
457 * @param {string} response.slug Slug of the plugin to be updated. |
|
458 * @param {string} response.plugin Basename of the plugin to be updated. |
|
459 * @param {string=} response.pluginName Optional. Name of the plugin to be updated. |
|
460 * @param {string} response.errorCode Error code for the error that occurred. |
|
461 * @param {string} response.errorMessage The error that occurred. |
|
462 */ |
|
463 wp.updates.updatePluginError = function( response ) { |
|
464 var $card, $message, errorMessage; |
|
465 |
|
466 if ( ! wp.updates.isValidResponse( response, 'update' ) ) { |
|
467 return; |
|
468 } |
|
469 |
|
470 if ( wp.updates.maybeHandleCredentialError( response, 'update-plugin' ) ) { |
|
471 return; |
|
472 } |
|
473 |
|
474 errorMessage = wp.updates.l10n.updateFailed.replace( '%s', response.errorMessage ); |
|
475 |
|
476 if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) { |
|
477 if ( response.plugin ) { |
|
478 $message = $( 'tr[data-plugin="' + response.plugin + '"]' ).find( '.update-message' ); |
|
479 } else { |
|
480 $message = $( 'tr[data-slug="' + response.slug + '"]' ).find( '.update-message' ); |
|
481 } |
|
482 $message.removeClass( 'updating-message notice-warning' ).addClass( 'notice-error' ).find( 'p' ).html( errorMessage ); |
|
483 |
|
484 if ( response.pluginName ) { |
|
485 $message.find( 'p' ) |
|
486 .attr( 'aria-label', wp.updates.l10n.pluginUpdateFailedLabel.replace( '%s', response.pluginName ) ); |
|
487 } else { |
|
488 $message.find( 'p' ).removeAttr( 'aria-label' ); |
|
489 } |
|
490 } else if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) { |
|
491 $card = $( '.plugin-card-' + response.slug ) |
|
492 .addClass( 'plugin-card-update-failed' ) |
|
493 .append( wp.updates.adminNotice( { |
|
494 className: 'update-message notice-error notice-alt is-dismissible', |
|
495 message: errorMessage |
|
496 } ) ); |
|
497 |
|
498 $card.find( '.update-now' ) |
|
499 .text( wp.updates.l10n.updateFailedShort ).removeClass( 'updating-message' ); |
|
500 |
|
501 if ( response.pluginName ) { |
|
502 $card.find( '.update-now' ) |
|
503 .attr( 'aria-label', wp.updates.l10n.pluginUpdateFailedLabel.replace( '%s', response.pluginName ) ); |
|
504 } else { |
|
505 $card.find( '.update-now' ).removeAttr( 'aria-label' ); |
|
506 } |
|
507 |
|
508 $card.on( 'click', '.notice.is-dismissible .notice-dismiss', function() { |
|
509 |
|
510 // Use same delay as the total duration of the notice fadeTo + slideUp animation. |
|
511 setTimeout( function() { |
|
512 $card |
|
513 .removeClass( 'plugin-card-update-failed' ) |
|
514 .find( '.column-name a' ).focus(); |
|
515 |
|
516 $card.find( '.update-now' ) |
|
517 .attr( 'aria-label', false ) |
|
518 .text( wp.updates.l10n.updateNow ); |
|
519 }, 200 ); |
|
520 } ); |
|
521 } |
|
522 |
|
523 wp.a11y.speak( errorMessage, 'assertive' ); |
|
524 |
|
525 $document.trigger( 'wp-plugin-update-error', response ); |
|
526 }; |
|
527 |
|
528 /** |
|
529 * Sends an Ajax request to the server to install a plugin. |
|
530 * |
|
531 * @since 4.6.0 |
|
532 * |
|
533 * @param {object} args Arguments. |
|
534 * @param {string} args.slug Plugin identifier in the WordPress.org Plugin repository. |
|
535 * @param {installPluginSuccess=} args.success Optional. Success callback. Default: wp.updates.installPluginSuccess |
|
536 * @param {installPluginError=} args.error Optional. Error callback. Default: wp.updates.installPluginError |
|
537 * @return {$.promise} A jQuery promise that represents the request, |
|
538 * decorated with an abort() method. |
|
539 */ |
|
540 wp.updates.installPlugin = function( args ) { |
|
541 var $card = $( '.plugin-card-' + args.slug ), |
|
542 $message = $card.find( '.install-now' ); |
|
543 |
|
544 args = _.extend( { |
|
545 success: wp.updates.installPluginSuccess, |
|
546 error: wp.updates.installPluginError |
|
547 }, args ); |
|
548 |
|
549 if ( 'import' === pagenow ) { |
|
550 $message = $( '[data-slug="' + args.slug + '"]' ); |
|
551 } |
|
552 |
|
553 if ( $message.html() !== wp.updates.l10n.installing ) { |
|
554 $message.data( 'originaltext', $message.html() ); |
|
555 } |
|
556 |
|
557 $message |
|
558 .addClass( 'updating-message' ) |
|
559 .attr( 'aria-label', wp.updates.l10n.pluginInstallingLabel.replace( '%s', $message.data( 'name' ) ) ) |
|
560 .text( wp.updates.l10n.installing ); |
|
561 |
|
562 wp.a11y.speak( wp.updates.l10n.installingMsg, 'polite' ); |
|
563 |
|
564 // Remove previous error messages, if any. |
|
565 $card.removeClass( 'plugin-card-install-failed' ).find( '.notice.notice-error' ).remove(); |
|
566 |
|
567 $document.trigger( 'wp-plugin-installing', args ); |
|
568 |
|
569 return wp.updates.ajax( 'install-plugin', args ); |
|
570 }; |
|
571 |
|
572 /** |
|
573 * Updates the UI appropriately after a successful plugin install. |
|
574 * |
|
575 * @since 4.6.0 |
|
576 * |
|
577 * @typedef {object} installPluginSuccess |
|
578 * @param {object} response Response from the server. |
|
579 * @param {string} response.slug Slug of the installed plugin. |
|
580 * @param {string} response.pluginName Name of the installed plugin. |
|
581 * @param {string} response.activateUrl URL to activate the just installed plugin. |
|
582 */ |
|
583 wp.updates.installPluginSuccess = function( response ) { |
|
584 var $message = $( '.plugin-card-' + response.slug ).find( '.install-now' ); |
|
585 |
|
586 $message |
|
587 .removeClass( 'updating-message' ) |
|
588 .addClass( 'updated-message installed' ) |
|
589 .attr( 'aria-label', wp.updates.l10n.pluginInstalledLabel.replace( '%s', response.pluginName ) ) |
|
590 .text( wp.updates.l10n.pluginInstalled ); |
|
591 |
|
592 if ( $message.hasClass( 'button-primary' ) ) { |
|
593 $message.addClass( 'button-primary-disabled' ); |
|
594 } else { |
|
595 $message.addClass( 'button-disabled' ); |
|
596 } |
|
597 |
|
598 wp.a11y.speak( wp.updates.l10n.installedMsg, 'polite' ); |
|
599 |
|
600 $document.trigger( 'wp-plugin-install-success', response ); |
|
601 |
|
602 if ( response.activateUrl ) { |
|
603 setTimeout( function() { |
|
604 |
|
605 // Transform the 'Install' button into an 'Activate' button. |
|
606 $message.removeClass( 'install-now installed button-primary-disabled button-secondary-disabled button-disabled updated-message' ) |
|
607 .addClass( 'activate-now' ) |
|
608 .attr( 'href', response.activateUrl ) |
|
609 .attr( 'aria-label', wp.updates.l10n.activatePluginLabel.replace( '%s', response.pluginName ) ) |
|
610 .text( response.activateLabel || wp.updates.l10n.activatePlugin ); |
|
611 }, 1000 ); |
|
612 } |
|
613 }; |
|
614 |
|
615 /** |
|
616 * Updates the UI appropriately after a failed plugin install. |
|
617 * |
|
618 * @since 4.6.0 |
|
619 * |
|
620 * @typedef {object} installPluginError |
|
621 * @param {object} response Response from the server. |
|
622 * @param {string} response.slug Slug of the plugin to be installed. |
|
623 * @param {string=} response.pluginName Optional. Name of the plugin to be installed. |
|
624 * @param {string} response.errorCode Error code for the error that occurred. |
|
625 * @param {string} response.errorMessage The error that occurred. |
|
626 */ |
|
627 wp.updates.installPluginError = function( response ) { |
|
628 var $card = $( '.plugin-card-' + response.slug ), |
|
629 $button = $card.find( '.install-now' ), |
|
630 errorMessage; |
|
631 |
|
632 if ( ! wp.updates.isValidResponse( response, 'install' ) ) { |
|
633 return; |
|
634 } |
|
635 |
|
636 if ( wp.updates.maybeHandleCredentialError( response, 'install-plugin' ) ) { |
|
637 return; |
|
638 } |
|
639 |
|
640 errorMessage = wp.updates.l10n.installFailed.replace( '%s', response.errorMessage ); |
|
641 |
|
642 $card |
|
643 .addClass( 'plugin-card-update-failed' ) |
|
644 .append( '<div class="notice notice-error notice-alt is-dismissible"><p>' + errorMessage + '</p></div>' ); |
|
645 |
|
646 $card.on( 'click', '.notice.is-dismissible .notice-dismiss', function() { |
|
647 |
|
648 // Use same delay as the total duration of the notice fadeTo + slideUp animation. |
|
649 setTimeout( function() { |
|
650 $card |
|
651 .removeClass( 'plugin-card-update-failed' ) |
|
652 .find( '.column-name a' ).focus(); |
|
653 }, 200 ); |
|
654 } ); |
|
655 |
|
656 $button |
|
657 .removeClass( 'updating-message' ).addClass( 'button-disabled' ) |
|
658 .attr( 'aria-label', wp.updates.l10n.pluginInstallFailedLabel.replace( '%s', $button.data( 'name' ) ) ) |
|
659 .text( wp.updates.l10n.installFailedShort ); |
|
660 |
|
661 wp.a11y.speak( errorMessage, 'assertive' ); |
|
662 |
|
663 $document.trigger( 'wp-plugin-install-error', response ); |
|
664 }; |
|
665 |
|
666 /** |
|
667 * Updates the UI appropriately after a successful importer install. |
|
668 * |
|
669 * @since 4.6.0 |
|
670 * |
|
671 * @typedef {object} installImporterSuccess |
|
672 * @param {object} response Response from the server. |
|
673 * @param {string} response.slug Slug of the installed plugin. |
|
674 * @param {string} response.pluginName Name of the installed plugin. |
|
675 * @param {string} response.activateUrl URL to activate the just installed plugin. |
|
676 */ |
|
677 wp.updates.installImporterSuccess = function( response ) { |
|
678 wp.updates.addAdminNotice( { |
|
679 id: 'install-success', |
|
680 className: 'notice-success is-dismissible', |
|
681 message: wp.updates.l10n.importerInstalledMsg.replace( '%s', response.activateUrl + '&from=import' ) |
|
682 } ); |
|
683 |
|
684 $( '[data-slug="' + response.slug + '"]' ) |
|
685 .removeClass( 'install-now updating-message' ) |
|
686 .addClass( 'activate-now' ) |
|
687 .attr({ |
|
688 'href': response.activateUrl + '&from=import', |
|
689 'aria-label': wp.updates.l10n.activateImporterLabel.replace( '%s', response.pluginName ) |
|
690 }) |
|
691 .text( wp.updates.l10n.activateImporter ); |
|
692 |
|
693 wp.a11y.speak( wp.updates.l10n.installedMsg, 'polite' ); |
|
694 |
|
695 $document.trigger( 'wp-importer-install-success', response ); |
|
696 }; |
|
697 |
|
698 /** |
|
699 * Updates the UI appropriately after a failed importer install. |
|
700 * |
|
701 * @since 4.6.0 |
|
702 * |
|
703 * @typedef {object} installImporterError |
|
704 * @param {object} response Response from the server. |
|
705 * @param {string} response.slug Slug of the plugin to be installed. |
|
706 * @param {string=} response.pluginName Optional. Name of the plugin to be installed. |
|
707 * @param {string} response.errorCode Error code for the error that occurred. |
|
708 * @param {string} response.errorMessage The error that occurred. |
|
709 */ |
|
710 wp.updates.installImporterError = function( response ) { |
|
711 var errorMessage = wp.updates.l10n.installFailed.replace( '%s', response.errorMessage ), |
|
712 $installLink = $( '[data-slug="' + response.slug + '"]' ), |
|
713 pluginName = $installLink.data( 'name' ); |
|
714 |
|
715 if ( ! wp.updates.isValidResponse( response, 'install' ) ) { |
|
716 return; |
|
717 } |
|
718 |
|
719 if ( wp.updates.maybeHandleCredentialError( response, 'install-plugin' ) ) { |
|
720 return; |
|
721 } |
|
722 |
|
723 wp.updates.addAdminNotice( { |
|
724 id: response.errorCode, |
|
725 className: 'notice-error is-dismissible', |
|
726 message: errorMessage |
|
727 } ); |
|
728 |
|
729 $installLink |
|
730 .removeClass( 'updating-message' ) |
|
731 .text( wp.updates.l10n.installNow ) |
|
732 .attr( 'aria-label', wp.updates.l10n.installNowLabel.replace( '%s', pluginName ) ); |
|
733 |
|
734 wp.a11y.speak( errorMessage, 'assertive' ); |
|
735 |
|
736 $document.trigger( 'wp-importer-install-error', response ); |
|
737 }; |
|
738 |
|
739 /** |
|
740 * Sends an Ajax request to the server to delete a plugin. |
|
741 * |
|
742 * @since 4.6.0 |
|
743 * |
|
744 * @param {object} args Arguments. |
|
745 * @param {string} args.plugin Basename of the plugin to be deleted. |
|
746 * @param {string} args.slug Slug of the plugin to be deleted. |
|
747 * @param {deletePluginSuccess=} args.success Optional. Success callback. Default: wp.updates.deletePluginSuccess |
|
748 * @param {deletePluginError=} args.error Optional. Error callback. Default: wp.updates.deletePluginError |
|
749 * @return {$.promise} A jQuery promise that represents the request, |
|
750 * decorated with an abort() method. |
|
751 */ |
|
752 wp.updates.deletePlugin = function( args ) { |
|
753 var $link = $( '[data-plugin="' + args.plugin + '"]' ).find( '.row-actions a.delete' ); |
|
754 |
|
755 args = _.extend( { |
|
756 success: wp.updates.deletePluginSuccess, |
|
757 error: wp.updates.deletePluginError |
|
758 }, args ); |
|
759 |
|
760 if ( $link.html() !== wp.updates.l10n.deleting ) { |
|
761 $link |
|
762 .data( 'originaltext', $link.html() ) |
|
763 .text( wp.updates.l10n.deleting ); |
|
764 } |
|
765 |
|
766 wp.a11y.speak( wp.updates.l10n.deleting, 'polite' ); |
|
767 |
|
768 $document.trigger( 'wp-plugin-deleting', args ); |
|
769 |
|
770 return wp.updates.ajax( 'delete-plugin', args ); |
|
771 }; |
|
772 |
|
773 /** |
|
774 * Updates the UI appropriately after a successful plugin deletion. |
|
775 * |
|
776 * @since 4.6.0 |
|
777 * |
|
778 * @typedef {object} deletePluginSuccess |
|
779 * @param {object} response Response from the server. |
|
780 * @param {string} response.slug Slug of the plugin that was deleted. |
|
781 * @param {string} response.plugin Base name of the plugin that was deleted. |
|
782 * @param {string} response.pluginName Name of the plugin that was deleted. |
|
783 */ |
|
784 wp.updates.deletePluginSuccess = function( response ) { |
|
785 |
|
786 // Removes the plugin and updates rows. |
|
787 $( '[data-plugin="' + response.plugin + '"]' ).css( { backgroundColor: '#faafaa' } ).fadeOut( 350, function() { |
|
788 var $form = $( '#bulk-action-form' ), |
|
789 $views = $( '.subsubsub' ), |
|
790 $pluginRow = $( this ), |
|
791 columnCount = $form.find( 'thead th:not(.hidden), thead td' ).length, |
|
792 pluginDeletedRow = wp.template( 'item-deleted-row' ), |
|
793 /** @type {object} plugins Base names of plugins in their different states. */ |
|
794 plugins = settings.plugins; |
|
795 |
|
796 // Add a success message after deleting a plugin. |
|
797 if ( ! $pluginRow.hasClass( 'plugin-update-tr' ) ) { |
|
798 $pluginRow.after( |
|
799 pluginDeletedRow( { |
|
800 slug: response.slug, |
|
801 plugin: response.plugin, |
|
802 colspan: columnCount, |
|
803 name: response.pluginName |
|
804 } ) |
|
805 ); |
|
806 } |
|
807 |
|
808 $pluginRow.remove(); |
|
809 |
|
810 // Remove plugin from update count. |
|
811 if ( -1 !== _.indexOf( plugins.upgrade, response.plugin ) ) { |
|
812 plugins.upgrade = _.without( plugins.upgrade, response.plugin ); |
|
813 wp.updates.decrementCount( 'plugin' ); |
|
814 } |
|
815 |
|
816 // Remove from views. |
|
817 if ( -1 !== _.indexOf( plugins.inactive, response.plugin ) ) { |
|
818 plugins.inactive = _.without( plugins.inactive, response.plugin ); |
|
819 if ( plugins.inactive.length ) { |
|
820 $views.find( '.inactive .count' ).text( '(' + plugins.inactive.length + ')' ); |
|
821 } else { |
|
822 $views.find( '.inactive' ).remove(); |
|
823 } |
|
824 } |
|
825 |
|
826 if ( -1 !== _.indexOf( plugins.active, response.plugin ) ) { |
|
827 plugins.active = _.without( plugins.active, response.plugin ); |
|
828 if ( plugins.active.length ) { |
|
829 $views.find( '.active .count' ).text( '(' + plugins.active.length + ')' ); |
|
830 } else { |
|
831 $views.find( '.active' ).remove(); |
|
832 } |
|
833 } |
|
834 |
|
835 if ( -1 !== _.indexOf( plugins.recently_activated, response.plugin ) ) { |
|
836 plugins.recently_activated = _.without( plugins.recently_activated, response.plugin ); |
|
837 if ( plugins.recently_activated.length ) { |
|
838 $views.find( '.recently_activated .count' ).text( '(' + plugins.recently_activated.length + ')' ); |
|
839 } else { |
|
840 $views.find( '.recently_activated' ).remove(); |
|
841 } |
|
842 } |
|
843 |
|
844 plugins.all = _.without( plugins.all, response.plugin ); |
|
845 |
|
846 if ( plugins.all.length ) { |
|
847 $views.find( '.all .count' ).text( '(' + plugins.all.length + ')' ); |
|
848 } else { |
|
849 $form.find( '.tablenav' ).css( { visibility: 'hidden' } ); |
|
850 $views.find( '.all' ).remove(); |
|
851 |
|
852 if ( ! $form.find( 'tr.no-items' ).length ) { |
|
853 $form.find( '#the-list' ).append( '<tr class="no-items"><td class="colspanchange" colspan="' + columnCount + '">' + wp.updates.l10n.noPlugins + '</td></tr>' ); |
|
854 } |
|
855 } |
|
856 } ); |
|
857 |
|
858 wp.a11y.speak( wp.updates.l10n.pluginDeleted, 'polite' ); |
|
859 |
|
860 $document.trigger( 'wp-plugin-delete-success', response ); |
|
861 }; |
|
862 |
|
863 /** |
|
864 * Updates the UI appropriately after a failed plugin deletion. |
|
865 * |
|
866 * @since 4.6.0 |
|
867 * |
|
868 * @typedef {object} deletePluginError |
|
869 * @param {object} response Response from the server. |
|
870 * @param {string} response.slug Slug of the plugin to be deleted. |
|
871 * @param {string} response.plugin Base name of the plugin to be deleted |
|
872 * @param {string=} response.pluginName Optional. Name of the plugin to be deleted. |
|
873 * @param {string} response.errorCode Error code for the error that occurred. |
|
874 * @param {string} response.errorMessage The error that occurred. |
|
875 */ |
|
876 wp.updates.deletePluginError = function( response ) { |
|
877 var $plugin, $pluginUpdateRow, |
|
878 pluginUpdateRow = wp.template( 'item-update-row' ), |
|
879 noticeContent = wp.updates.adminNotice( { |
|
880 className: 'update-message notice-error notice-alt', |
|
881 message: response.errorMessage |
|
882 } ); |
|
883 |
|
884 if ( response.plugin ) { |
|
885 $plugin = $( 'tr.inactive[data-plugin="' + response.plugin + '"]' ); |
|
886 $pluginUpdateRow = $plugin.siblings( '[data-plugin="' + response.plugin + '"]' ); |
|
887 } else { |
|
888 $plugin = $( 'tr.inactive[data-slug="' + response.slug + '"]' ); |
|
889 $pluginUpdateRow = $plugin.siblings( '[data-slug="' + response.slug + '"]' ); |
|
890 } |
|
891 |
|
892 if ( ! wp.updates.isValidResponse( response, 'delete' ) ) { |
|
893 return; |
|
894 } |
|
895 |
|
896 if ( wp.updates.maybeHandleCredentialError( response, 'delete-plugin' ) ) { |
|
897 return; |
|
898 } |
|
899 |
|
900 // Add a plugin update row if it doesn't exist yet. |
|
901 if ( ! $pluginUpdateRow.length ) { |
|
902 $plugin.addClass( 'update' ).after( |
|
903 pluginUpdateRow( { |
|
904 slug: response.slug, |
|
905 plugin: response.plugin || response.slug, |
|
906 colspan: $( '#bulk-action-form' ).find( 'thead th:not(.hidden), thead td' ).length, |
|
907 content: noticeContent |
|
908 } ) |
|
909 ); |
|
910 } else { |
|
911 |
|
912 // Remove previous error messages, if any. |
|
913 $pluginUpdateRow.find( '.notice-error' ).remove(); |
|
914 |
|
915 $pluginUpdateRow.find( '.plugin-update' ).append( noticeContent ); |
|
916 } |
|
917 |
|
918 $document.trigger( 'wp-plugin-delete-error', response ); |
|
919 }; |
|
920 |
|
921 /** |
|
922 * Sends an Ajax request to the server to update a theme. |
|
923 * |
|
924 * @since 4.6.0 |
|
925 * |
|
926 * @param {object} args Arguments. |
|
927 * @param {string} args.slug Theme stylesheet. |
|
928 * @param {updateThemeSuccess=} args.success Optional. Success callback. Default: wp.updates.updateThemeSuccess |
|
929 * @param {updateThemeError=} args.error Optional. Error callback. Default: wp.updates.updateThemeError |
|
930 * @return {$.promise} A jQuery promise that represents the request, |
|
931 * decorated with an abort() method. |
|
932 */ |
|
933 wp.updates.updateTheme = function( args ) { |
|
934 var $notice; |
|
935 |
|
936 args = _.extend( { |
|
937 success: wp.updates.updateThemeSuccess, |
|
938 error: wp.updates.updateThemeError |
|
939 }, args ); |
|
940 |
|
941 if ( 'themes-network' === pagenow ) { |
|
942 $notice = $( '[data-slug="' + args.slug + '"]' ).find( '.update-message' ).removeClass( 'notice-error' ).addClass( 'updating-message notice-warning' ).find( 'p' ); |
|
943 |
|
944 } else if ( 'customize' === pagenow ) { |
|
945 |
|
946 // Update the theme details UI. |
|
947 $notice = $( '[data-slug="' + args.slug + '"].notice' ).removeClass( 'notice-large' ); |
|
948 |
|
949 $notice.find( 'h3' ).remove(); |
|
950 |
|
951 // Add the top-level UI, and update both. |
|
952 $notice = $notice.add( $( '#customize-control-installed_theme_' + args.slug ).find( '.update-message' ) ); |
|
953 $notice = $notice.addClass( 'updating-message' ).find( 'p' ); |
|
954 |
|
955 } else { |
|
956 $notice = $( '#update-theme' ).closest( '.notice' ).removeClass( 'notice-large' ); |
|
957 |
|
958 $notice.find( 'h3' ).remove(); |
|
959 |
|
960 $notice = $notice.add( $( '[data-slug="' + args.slug + '"]' ).find( '.update-message' ) ); |
|
961 $notice = $notice.addClass( 'updating-message' ).find( 'p' ); |
|
962 } |
|
963 |
|
964 if ( $notice.html() !== wp.updates.l10n.updating ) { |
|
965 $notice.data( 'originaltext', $notice.html() ); |
|
966 } |
|
967 |
|
968 wp.a11y.speak( wp.updates.l10n.updatingMsg, 'polite' ); |
|
969 $notice.text( wp.updates.l10n.updating ); |
|
970 |
|
971 $document.trigger( 'wp-theme-updating', args ); |
|
972 |
|
973 return wp.updates.ajax( 'update-theme', args ); |
|
974 }; |
|
975 |
|
976 /** |
|
977 * Updates the UI appropriately after a successful theme update. |
|
978 * |
|
979 * @since 4.6.0 |
|
980 * |
|
981 * @typedef {object} updateThemeSuccess |
201 * @param {object} response |
982 * @param {object} response |
202 */ |
983 * @param {string} response.slug Slug of the theme to be updated. |
203 wp.updates.updateSuccess = function( response ) { |
984 * @param {object} response.theme Updated theme. |
204 var $updateMessage, name, $pluginRow, newText; |
985 * @param {string} response.oldVersion Old version of the theme. |
205 if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) { |
986 * @param {string} response.newVersion New version of the theme. |
206 $pluginRow = $( '[data-slug="' + response.slug + '"]' ).first(); |
987 */ |
207 $updateMessage = $pluginRow.next().find( '.update-message' ); |
988 wp.updates.updateThemeSuccess = function( response ) { |
208 $pluginRow.addClass( 'updated' ).removeClass( 'update' ); |
989 var isModalOpen = $( 'body.modal-open' ).length, |
|
990 $theme = $( '[data-slug="' + response.slug + '"]' ), |
|
991 updatedMessage = { |
|
992 className: 'updated-message notice-success notice-alt', |
|
993 message: wp.updates.l10n.themeUpdated |
|
994 }, |
|
995 $notice, newText; |
|
996 |
|
997 if ( 'customize' === pagenow ) { |
|
998 $theme = $( '.updating-message' ).siblings( '.theme-name' ); |
|
999 |
|
1000 if ( $theme.length ) { |
|
1001 |
|
1002 // Update the version number in the row. |
|
1003 newText = $theme.html().replace( response.oldVersion, response.newVersion ); |
|
1004 $theme.html( newText ); |
|
1005 } |
|
1006 |
|
1007 $notice = $( '.theme-info .notice' ).add( wp.customize.control( 'installed_theme_' + response.slug ).container.find( '.theme' ).find( '.update-message' ) ); |
|
1008 } else if ( 'themes-network' === pagenow ) { |
|
1009 $notice = $theme.find( '.update-message' ); |
209 |
1010 |
210 // Update the version number in the row. |
1011 // Update the version number in the row. |
211 newText = $pluginRow.find('.plugin-version-author-uri').html().replace( response.oldVersion, response.newVersion ); |
1012 newText = $theme.find( '.theme-version-author-uri' ).html().replace( response.oldVersion, response.newVersion ); |
212 $pluginRow.find('.plugin-version-author-uri').html( newText ); |
1013 $theme.find( '.theme-version-author-uri' ).html( newText ); |
213 |
1014 } else { |
214 // Add updated class to update message parent tr |
1015 $notice = $( '.theme-info .notice' ).add( $theme.find( '.update-message' ) ); |
215 $pluginRow.next().addClass( 'updated' ); |
1016 |
216 } else if ( 'plugin-install' === pagenow ) { |
1017 // Focus on Customize button after updating. |
217 $updateMessage = $( '.plugin-card-' + response.slug ).find( '.update-now' ); |
1018 if ( isModalOpen ) { |
218 $updateMessage.addClass( 'button-disabled' ); |
1019 $( '.load-customize:visible' ).focus(); |
219 name = $updateMessage.data( 'name' ); |
1020 } else { |
220 $updateMessage.attr( 'aria-label', wp.updates.l10n.updatedLabel.replace( '%s', name ) ); |
1021 $theme.find( '.load-customize' ).focus(); |
221 } |
1022 } |
222 |
1023 } |
223 $updateMessage.removeClass( 'updating-message' ).addClass( 'updated-message' ); |
1024 |
224 $updateMessage.text( wp.updates.l10n.updated ); |
1025 wp.updates.addAdminNotice( _.extend( { selector: $notice }, updatedMessage ) ); |
225 wp.a11y.speak( wp.updates.l10n.updatedMsg ); |
1026 wp.a11y.speak( wp.updates.l10n.updatedMsg, 'polite' ); |
226 |
1027 |
227 wp.updates.decrementCount( 'plugin' ); |
1028 wp.updates.decrementCount( 'theme' ); |
228 |
1029 |
229 wp.updates.updateDoneSuccessfully = true; |
1030 $document.trigger( 'wp-theme-update-success', response ); |
230 |
1031 |
231 /* |
1032 // Show updated message after modal re-rendered. |
232 * The lock can be released since the update was successful, |
1033 if ( isModalOpen && 'customize' !== pagenow ) { |
233 * and any other updates can commence. |
1034 $( '.theme-info .theme-author' ).after( wp.updates.adminNotice( updatedMessage ) ); |
234 */ |
1035 } |
235 wp.updates.updateLock = false; |
1036 }; |
236 |
1037 |
237 $(document).trigger( 'wp-plugin-update-success', response ); |
1038 /** |
238 |
1039 * Updates the UI appropriately after a failed theme update. |
239 wp.updates.queueChecker(); |
1040 * |
240 }; |
1041 * @since 4.6.0 |
241 |
1042 * |
242 |
1043 * @typedef {object} updateThemeError |
243 /** |
1044 * @param {object} response Response from the server. |
244 * On a plugin update error, update the UI appropriately. |
1045 * @param {string} response.slug Slug of the theme to be updated. |
|
1046 * @param {string} response.errorCode Error code for the error that occurred. |
|
1047 * @param {string} response.errorMessage The error that occurred. |
|
1048 */ |
|
1049 wp.updates.updateThemeError = function( response ) { |
|
1050 var $theme = $( '[data-slug="' + response.slug + '"]' ), |
|
1051 errorMessage = wp.updates.l10n.updateFailed.replace( '%s', response.errorMessage ), |
|
1052 $notice; |
|
1053 |
|
1054 if ( ! wp.updates.isValidResponse( response, 'update' ) ) { |
|
1055 return; |
|
1056 } |
|
1057 |
|
1058 if ( wp.updates.maybeHandleCredentialError( response, 'update-theme' ) ) { |
|
1059 return; |
|
1060 } |
|
1061 |
|
1062 if ( 'customize' === pagenow ) { |
|
1063 $theme = wp.customize.control( 'installed_theme_' + response.slug ).container.find( '.theme' ); |
|
1064 } |
|
1065 |
|
1066 if ( 'themes-network' === pagenow ) { |
|
1067 $notice = $theme.find( '.update-message ' ); |
|
1068 } else { |
|
1069 $notice = $( '.theme-info .notice' ).add( $theme.find( '.notice' ) ); |
|
1070 |
|
1071 $( 'body.modal-open' ).length ? $( '.load-customize:visible' ).focus() : $theme.find( '.load-customize' ).focus(); |
|
1072 } |
|
1073 |
|
1074 wp.updates.addAdminNotice( { |
|
1075 selector: $notice, |
|
1076 className: 'update-message notice-error notice-alt is-dismissible', |
|
1077 message: errorMessage |
|
1078 } ); |
|
1079 |
|
1080 wp.a11y.speak( errorMessage, 'polite' ); |
|
1081 |
|
1082 $document.trigger( 'wp-theme-update-error', response ); |
|
1083 }; |
|
1084 |
|
1085 /** |
|
1086 * Sends an Ajax request to the server to install a theme. |
|
1087 * |
|
1088 * @since 4.6.0 |
|
1089 * |
|
1090 * @param {object} args |
|
1091 * @param {string} args.slug Theme stylesheet. |
|
1092 * @param {installThemeSuccess=} args.success Optional. Success callback. Default: wp.updates.installThemeSuccess |
|
1093 * @param {installThemeError=} args.error Optional. Error callback. Default: wp.updates.installThemeError |
|
1094 * @return {$.promise} A jQuery promise that represents the request, |
|
1095 * decorated with an abort() method. |
|
1096 */ |
|
1097 wp.updates.installTheme = function( args ) { |
|
1098 var $message = $( '.theme-install[data-slug="' + args.slug + '"]' ); |
|
1099 |
|
1100 args = _.extend( { |
|
1101 success: wp.updates.installThemeSuccess, |
|
1102 error: wp.updates.installThemeError |
|
1103 }, args ); |
|
1104 |
|
1105 $message.addClass( 'updating-message' ); |
|
1106 $message.parents( '.theme' ).addClass( 'focus' ); |
|
1107 if ( $message.html() !== wp.updates.l10n.installing ) { |
|
1108 $message.data( 'originaltext', $message.html() ); |
|
1109 } |
|
1110 |
|
1111 $message |
|
1112 .text( wp.updates.l10n.installing ) |
|
1113 .attr( 'aria-label', wp.updates.l10n.themeInstallingLabel.replace( '%s', $message.data( 'name' ) ) ); |
|
1114 wp.a11y.speak( wp.updates.l10n.installingMsg, 'polite' ); |
|
1115 |
|
1116 // Remove previous error messages, if any. |
|
1117 $( '.install-theme-info, [data-slug="' + args.slug + '"]' ).removeClass( 'theme-install-failed' ).find( '.notice.notice-error' ).remove(); |
|
1118 |
|
1119 $document.trigger( 'wp-theme-installing', args ); |
|
1120 |
|
1121 return wp.updates.ajax( 'install-theme', args ); |
|
1122 }; |
|
1123 |
|
1124 /** |
|
1125 * Updates the UI appropriately after a successful theme install. |
|
1126 * |
|
1127 * @since 4.6.0 |
|
1128 * |
|
1129 * @typedef {object} installThemeSuccess |
|
1130 * @param {object} response Response from the server. |
|
1131 * @param {string} response.slug Slug of the theme to be installed. |
|
1132 * @param {string} response.customizeUrl URL to the Customizer for the just installed theme. |
|
1133 * @param {string} response.activateUrl URL to activate the just installed theme. |
|
1134 */ |
|
1135 wp.updates.installThemeSuccess = function( response ) { |
|
1136 var $card = $( '.wp-full-overlay-header, [data-slug=' + response.slug + ']' ), |
|
1137 $message; |
|
1138 |
|
1139 $document.trigger( 'wp-theme-install-success', response ); |
|
1140 |
|
1141 $message = $card.find( '.button-primary' ) |
|
1142 .removeClass( 'updating-message' ) |
|
1143 .addClass( 'updated-message disabled' ) |
|
1144 .attr( 'aria-label', wp.updates.l10n.themeInstalledLabel.replace( '%s', response.themeName ) ) |
|
1145 .text( wp.updates.l10n.themeInstalled ); |
|
1146 |
|
1147 wp.a11y.speak( wp.updates.l10n.installedMsg, 'polite' ); |
|
1148 |
|
1149 setTimeout( function() { |
|
1150 |
|
1151 if ( response.activateUrl ) { |
|
1152 |
|
1153 // Transform the 'Install' button into an 'Activate' button. |
|
1154 $message |
|
1155 .attr( 'href', response.activateUrl ) |
|
1156 .removeClass( 'theme-install updated-message disabled' ) |
|
1157 .addClass( 'activate' ) |
|
1158 .attr( 'aria-label', wp.updates.l10n.activateThemeLabel.replace( '%s', response.themeName ) ) |
|
1159 .text( wp.updates.l10n.activateTheme ); |
|
1160 } |
|
1161 |
|
1162 if ( response.customizeUrl ) { |
|
1163 |
|
1164 // Transform the 'Preview' button into a 'Live Preview' button. |
|
1165 $message.siblings( '.preview' ).replaceWith( function () { |
|
1166 return $( '<a>' ) |
|
1167 .attr( 'href', response.customizeUrl ) |
|
1168 .addClass( 'button load-customize' ) |
|
1169 .text( wp.updates.l10n.livePreview ); |
|
1170 } ); |
|
1171 } |
|
1172 }, 1000 ); |
|
1173 }; |
|
1174 |
|
1175 /** |
|
1176 * Updates the UI appropriately after a failed theme install. |
|
1177 * |
|
1178 * @since 4.6.0 |
|
1179 * |
|
1180 * @typedef {object} installThemeError |
|
1181 * @param {object} response Response from the server. |
|
1182 * @param {string} response.slug Slug of the theme to be installed. |
|
1183 * @param {string} response.errorCode Error code for the error that occurred. |
|
1184 * @param {string} response.errorMessage The error that occurred. |
|
1185 */ |
|
1186 wp.updates.installThemeError = function( response ) { |
|
1187 var $card, $button, |
|
1188 errorMessage = wp.updates.l10n.installFailed.replace( '%s', response.errorMessage ), |
|
1189 $message = wp.updates.adminNotice( { |
|
1190 className: 'update-message notice-error notice-alt', |
|
1191 message: errorMessage |
|
1192 } ); |
|
1193 |
|
1194 if ( ! wp.updates.isValidResponse( response, 'install' ) ) { |
|
1195 return; |
|
1196 } |
|
1197 |
|
1198 if ( wp.updates.maybeHandleCredentialError( response, 'install-theme' ) ) { |
|
1199 return; |
|
1200 } |
|
1201 |
|
1202 if ( 'customize' === pagenow ) { |
|
1203 if ( $document.find( 'body' ).hasClass( 'modal-open' ) ) { |
|
1204 $button = $( '.theme-install[data-slug="' + response.slug + '"]' ); |
|
1205 $card = $( '.theme-overlay .theme-info' ).prepend( $message ); |
|
1206 } else { |
|
1207 $button = $( '.theme-install[data-slug="' + response.slug + '"]' ); |
|
1208 $card = $button.closest( '.theme' ).addClass( 'theme-install-failed' ).append( $message ); |
|
1209 } |
|
1210 wp.customize.notifications.remove( 'theme_installing' ); |
|
1211 } else { |
|
1212 if ( $document.find( 'body' ).hasClass( 'full-overlay-active' ) ) { |
|
1213 $button = $( '.theme-install[data-slug="' + response.slug + '"]' ); |
|
1214 $card = $( '.install-theme-info' ).prepend( $message ); |
|
1215 } else { |
|
1216 $card = $( '[data-slug="' + response.slug + '"]' ).removeClass( 'focus' ).addClass( 'theme-install-failed' ).append( $message ); |
|
1217 $button = $card.find( '.theme-install' ); |
|
1218 } |
|
1219 } |
|
1220 |
|
1221 $button |
|
1222 .removeClass( 'updating-message' ) |
|
1223 .attr( 'aria-label', wp.updates.l10n.themeInstallFailedLabel.replace( '%s', $button.data( 'name' ) ) ) |
|
1224 .text( wp.updates.l10n.installFailedShort ); |
|
1225 |
|
1226 wp.a11y.speak( errorMessage, 'assertive' ); |
|
1227 |
|
1228 $document.trigger( 'wp-theme-install-error', response ); |
|
1229 }; |
|
1230 |
|
1231 /** |
|
1232 * Sends an Ajax request to the server to delete a theme. |
|
1233 * |
|
1234 * @since 4.6.0 |
|
1235 * |
|
1236 * @param {object} args |
|
1237 * @param {string} args.slug Theme stylesheet. |
|
1238 * @param {deleteThemeSuccess=} args.success Optional. Success callback. Default: wp.updates.deleteThemeSuccess |
|
1239 * @param {deleteThemeError=} args.error Optional. Error callback. Default: wp.updates.deleteThemeError |
|
1240 * @return {$.promise} A jQuery promise that represents the request, |
|
1241 * decorated with an abort() method. |
|
1242 */ |
|
1243 wp.updates.deleteTheme = function( args ) { |
|
1244 var $button; |
|
1245 |
|
1246 if ( 'themes' === pagenow ) { |
|
1247 $button = $( '.theme-actions .delete-theme' ); |
|
1248 } else if ( 'themes-network' === pagenow ) { |
|
1249 $button = $( '[data-slug="' + args.slug + '"]' ).find( '.row-actions a.delete' ); |
|
1250 } |
|
1251 |
|
1252 args = _.extend( { |
|
1253 success: wp.updates.deleteThemeSuccess, |
|
1254 error: wp.updates.deleteThemeError |
|
1255 }, args ); |
|
1256 |
|
1257 if ( $button && $button.html() !== wp.updates.l10n.deleting ) { |
|
1258 $button |
|
1259 .data( 'originaltext', $button.html() ) |
|
1260 .text( wp.updates.l10n.deleting ); |
|
1261 } |
|
1262 |
|
1263 wp.a11y.speak( wp.updates.l10n.deleting, 'polite' ); |
|
1264 |
|
1265 // Remove previous error messages, if any. |
|
1266 $( '.theme-info .update-message' ).remove(); |
|
1267 |
|
1268 $document.trigger( 'wp-theme-deleting', args ); |
|
1269 |
|
1270 return wp.updates.ajax( 'delete-theme', args ); |
|
1271 }; |
|
1272 |
|
1273 /** |
|
1274 * Updates the UI appropriately after a successful theme deletion. |
|
1275 * |
|
1276 * @since 4.6.0 |
|
1277 * |
|
1278 * @typedef {object} deleteThemeSuccess |
|
1279 * @param {object} response Response from the server. |
|
1280 * @param {string} response.slug Slug of the theme that was deleted. |
|
1281 */ |
|
1282 wp.updates.deleteThemeSuccess = function( response ) { |
|
1283 var $themeRows = $( '[data-slug="' + response.slug + '"]' ); |
|
1284 |
|
1285 if ( 'themes-network' === pagenow ) { |
|
1286 |
|
1287 // Removes the theme and updates rows. |
|
1288 $themeRows.css( { backgroundColor: '#faafaa' } ).fadeOut( 350, function() { |
|
1289 var $views = $( '.subsubsub' ), |
|
1290 $themeRow = $( this ), |
|
1291 totals = settings.themes, |
|
1292 deletedRow = wp.template( 'item-deleted-row' ); |
|
1293 |
|
1294 if ( ! $themeRow.hasClass( 'plugin-update-tr' ) ) { |
|
1295 $themeRow.after( |
|
1296 deletedRow( { |
|
1297 slug: response.slug, |
|
1298 colspan: $( '#bulk-action-form' ).find( 'thead th:not(.hidden), thead td' ).length, |
|
1299 name: $themeRow.find( '.theme-title strong' ).text() |
|
1300 } ) |
|
1301 ); |
|
1302 } |
|
1303 |
|
1304 $themeRow.remove(); |
|
1305 |
|
1306 // Remove theme from update count. |
|
1307 if ( $themeRow.hasClass( 'update' ) ) { |
|
1308 totals.upgrade--; |
|
1309 wp.updates.decrementCount( 'theme' ); |
|
1310 } |
|
1311 |
|
1312 // Remove from views. |
|
1313 if ( $themeRow.hasClass( 'inactive' ) ) { |
|
1314 totals.disabled--; |
|
1315 if ( totals.disabled ) { |
|
1316 $views.find( '.disabled .count' ).text( '(' + totals.disabled + ')' ); |
|
1317 } else { |
|
1318 $views.find( '.disabled' ).remove(); |
|
1319 } |
|
1320 } |
|
1321 |
|
1322 // There is always at least one theme available. |
|
1323 $views.find( '.all .count' ).text( '(' + --totals.all + ')' ); |
|
1324 } ); |
|
1325 } |
|
1326 |
|
1327 wp.a11y.speak( wp.updates.l10n.themeDeleted, 'polite' ); |
|
1328 |
|
1329 $document.trigger( 'wp-theme-delete-success', response ); |
|
1330 }; |
|
1331 |
|
1332 /** |
|
1333 * Updates the UI appropriately after a failed theme deletion. |
|
1334 * |
|
1335 * @since 4.6.0 |
|
1336 * |
|
1337 * @typedef {object} deleteThemeError |
|
1338 * @param {object} response Response from the server. |
|
1339 * @param {string} response.slug Slug of the theme to be deleted. |
|
1340 * @param {string} response.errorCode Error code for the error that occurred. |
|
1341 * @param {string} response.errorMessage The error that occurred. |
|
1342 */ |
|
1343 wp.updates.deleteThemeError = function( response ) { |
|
1344 var $themeRow = $( 'tr.inactive[data-slug="' + response.slug + '"]' ), |
|
1345 $button = $( '.theme-actions .delete-theme' ), |
|
1346 updateRow = wp.template( 'item-update-row' ), |
|
1347 $updateRow = $themeRow.siblings( '#' + response.slug + '-update' ), |
|
1348 errorMessage = wp.updates.l10n.deleteFailed.replace( '%s', response.errorMessage ), |
|
1349 $message = wp.updates.adminNotice( { |
|
1350 className: 'update-message notice-error notice-alt', |
|
1351 message: errorMessage |
|
1352 } ); |
|
1353 |
|
1354 if ( wp.updates.maybeHandleCredentialError( response, 'delete-theme' ) ) { |
|
1355 return; |
|
1356 } |
|
1357 |
|
1358 if ( 'themes-network' === pagenow ) { |
|
1359 if ( ! $updateRow.length ) { |
|
1360 $themeRow.addClass( 'update' ).after( |
|
1361 updateRow( { |
|
1362 slug: response.slug, |
|
1363 colspan: $( '#bulk-action-form' ).find( 'thead th:not(.hidden), thead td' ).length, |
|
1364 content: $message |
|
1365 } ) |
|
1366 ); |
|
1367 } else { |
|
1368 // Remove previous error messages, if any. |
|
1369 $updateRow.find( '.notice-error' ).remove(); |
|
1370 $updateRow.find( '.plugin-update' ).append( $message ); |
|
1371 } |
|
1372 } else { |
|
1373 $( '.theme-info .theme-description' ).before( $message ); |
|
1374 } |
|
1375 |
|
1376 $button.html( $button.data( 'originaltext' ) ); |
|
1377 |
|
1378 wp.a11y.speak( errorMessage, 'assertive' ); |
|
1379 |
|
1380 $document.trigger( 'wp-theme-delete-error', response ); |
|
1381 }; |
|
1382 |
|
1383 /** |
|
1384 * Adds the appropriate callback based on the type of action and the current page. |
|
1385 * |
|
1386 * @since 4.6.0 |
|
1387 * @private |
|
1388 * |
|
1389 * @param {object} data AJAX payload. |
|
1390 * @param {string} action The type of request to perform. |
|
1391 * @return {object} The AJAX payload with the appropriate callbacks. |
|
1392 */ |
|
1393 wp.updates._addCallbacks = function( data, action ) { |
|
1394 if ( 'import' === pagenow && 'install-plugin' === action ) { |
|
1395 data.success = wp.updates.installImporterSuccess; |
|
1396 data.error = wp.updates.installImporterError; |
|
1397 } |
|
1398 |
|
1399 return data; |
|
1400 }; |
|
1401 |
|
1402 /** |
|
1403 * Pulls available jobs from the queue and runs them. |
245 * |
1404 * |
246 * @since 4.2.0 |
1405 * @since 4.2.0 |
247 * |
1406 * @since 4.6.0 Can handle multiple job types. |
248 * @param {object} response |
1407 */ |
249 */ |
1408 wp.updates.queueChecker = function() { |
250 wp.updates.updateError = function( response ) { |
1409 var job; |
251 var $message, name; |
1410 |
252 wp.updates.updateDoneSuccessfully = false; |
1411 if ( wp.updates.ajaxLocked || ! wp.updates.queue.length ) { |
253 if ( response.errorCode && response.errorCode == 'unable_to_connect_to_filesystem' ) { |
|
254 wp.updates.credentialError( response, 'update-plugin' ); |
|
255 return; |
1412 return; |
256 } |
1413 } |
257 if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) { |
1414 |
258 $message = $( '[data-slug="' + response.slug + '"]' ).next().find( '.update-message' ); |
1415 job = wp.updates.queue.shift(); |
259 } else if ( 'plugin-install' === pagenow ) { |
1416 |
260 $message = $( '.plugin-card-' + response.slug ).find( '.update-now' ); |
1417 // Handle a queue job. |
261 |
1418 switch ( job.action ) { |
262 name = $message.data( 'name' ); |
1419 case 'install-plugin': |
263 $message.attr( 'aria-label', wp.updates.l10n.updateFailedLabel.replace( '%s', name ) ); |
1420 wp.updates.installPlugin( job.data ); |
264 } |
1421 break; |
265 $message.removeClass( 'updating-message' ); |
1422 |
266 $message.text( wp.updates.l10n.updateFailed ); |
1423 case 'update-plugin': |
267 wp.a11y.speak( wp.updates.l10n.updateFailed ); |
1424 wp.updates.updatePlugin( job.data ); |
268 |
1425 break; |
269 $(document).trigger( 'wp-plugin-update-error', response ); |
1426 |
270 }; |
1427 case 'delete-plugin': |
271 |
1428 wp.updates.deletePlugin( job.data ); |
272 /** |
1429 break; |
273 * Show an error message in the request for credentials form. |
1430 |
274 * |
1431 case 'install-theme': |
275 * @param {string} message |
1432 wp.updates.installTheme( job.data ); |
|
1433 break; |
|
1434 |
|
1435 case 'update-theme': |
|
1436 wp.updates.updateTheme( job.data ); |
|
1437 break; |
|
1438 |
|
1439 case 'delete-theme': |
|
1440 wp.updates.deleteTheme( job.data ); |
|
1441 break; |
|
1442 |
|
1443 default: |
|
1444 break; |
|
1445 } |
|
1446 }; |
|
1447 |
|
1448 /** |
|
1449 * Requests the users filesystem credentials if they aren't already known. |
|
1450 * |
276 * @since 4.2.0 |
1451 * @since 4.2.0 |
277 */ |
1452 * |
278 wp.updates.showErrorInCredentialsForm = function( message ) { |
1453 * @param {Event=} event Optional. Event interface. |
279 var $modal = $( '.notification-dialog' ); |
1454 */ |
280 |
1455 wp.updates.requestFilesystemCredentials = function( event ) { |
281 // Remove any existing error. |
1456 if ( false === wp.updates.filesystemCredentials.available ) { |
282 $modal.find( '.error' ).remove(); |
1457 /* |
283 |
1458 * After exiting the credentials request modal, |
284 $modal.find( 'h3' ).after( '<div class="error">' + message + '</div>' ); |
1459 * return the focus to the element triggering the request. |
285 }; |
1460 */ |
286 |
1461 if ( event && ! wp.updates.$elToReturnFocusToFromCredentialsModal ) { |
287 /** |
1462 wp.updates.$elToReturnFocusToFromCredentialsModal = $( event.target ); |
288 * Events that need to happen when there is a credential error |
1463 } |
|
1464 |
|
1465 wp.updates.ajaxLocked = true; |
|
1466 wp.updates.requestForCredentialsModalOpen(); |
|
1467 } |
|
1468 }; |
|
1469 |
|
1470 /** |
|
1471 * Requests the users filesystem credentials if needed and there is no lock. |
|
1472 * |
|
1473 * @since 4.6.0 |
|
1474 * |
|
1475 * @param {Event=} event Optional. Event interface. |
|
1476 */ |
|
1477 wp.updates.maybeRequestFilesystemCredentials = function( event ) { |
|
1478 if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.ajaxLocked ) { |
|
1479 wp.updates.requestFilesystemCredentials( event ); |
|
1480 } |
|
1481 }; |
|
1482 |
|
1483 /** |
|
1484 * Keydown handler for the request for credentials modal. |
|
1485 * |
|
1486 * Closes the modal when the escape key is pressed and |
|
1487 * constrains keyboard navigation to inside the modal. |
289 * |
1488 * |
290 * @since 4.2.0 |
1489 * @since 4.2.0 |
291 */ |
1490 * |
292 wp.updates.credentialError = function( response, type ) { |
1491 * @param {Event} event Event interface. |
293 wp.updates.updateQueue.push( { |
|
294 'type': type, |
|
295 'data': { |
|
296 // Not cool that we're depending on response for this data. |
|
297 // This would feel more whole in a view all tied together. |
|
298 plugin: response.plugin, |
|
299 slug: response.slug |
|
300 } |
|
301 } ); |
|
302 wp.updates.showErrorInCredentialsForm( response.error ); |
|
303 wp.updates.requestFilesystemCredentials(); |
|
304 }; |
|
305 |
|
306 /** |
|
307 * If an update job has been placed in the queue, queueChecker pulls it out and runs it. |
|
308 * |
|
309 * @since 4.2.0 |
|
310 */ |
|
311 wp.updates.queueChecker = function() { |
|
312 if ( wp.updates.updateLock || wp.updates.updateQueue.length <= 0 ) { |
|
313 return; |
|
314 } |
|
315 |
|
316 var job = wp.updates.updateQueue.shift(); |
|
317 |
|
318 wp.updates.updatePlugin( job.data.plugin, job.data.slug ); |
|
319 }; |
|
320 |
|
321 |
|
322 /** |
|
323 * Request the users filesystem credentials if we don't have them already. |
|
324 * |
|
325 * @since 4.2.0 |
|
326 */ |
|
327 wp.updates.requestFilesystemCredentials = function( event ) { |
|
328 if ( wp.updates.updateDoneSuccessfully === false ) { |
|
329 /* |
|
330 * For the plugin install screen, return the focus to the install button |
|
331 * after exiting the credentials request modal. |
|
332 */ |
|
333 if ( 'plugin-install' === pagenow && event ) { |
|
334 wp.updates.$elToReturnFocusToFromCredentialsModal = $( event.target ); |
|
335 } |
|
336 |
|
337 wp.updates.updateLock = true; |
|
338 |
|
339 wp.updates.requestForCredentialsModalOpen(); |
|
340 } |
|
341 }; |
|
342 |
|
343 /** |
|
344 * Keydown handler for the request for credentials modal. |
|
345 * |
|
346 * Close the modal when the escape key is pressed. |
|
347 * Constrain keyboard navigation to inside the modal. |
|
348 * |
|
349 * @since 4.2.0 |
|
350 */ |
1492 */ |
351 wp.updates.keydown = function( event ) { |
1493 wp.updates.keydown = function( event ) { |
352 if ( 27 === event.keyCode ) { |
1494 if ( 27 === event.keyCode ) { |
353 wp.updates.requestForCredentialsModalCancel(); |
1495 wp.updates.requestForCredentialsModalCancel(); |
354 } else if ( 9 === event.keyCode ) { |
1496 } else if ( 9 === event.keyCode ) { |
355 // #upgrade button must always be the last focusable element in the dialog. |
1497 |
356 if ( event.target.id === 'upgrade' && ! event.shiftKey ) { |
1498 // #upgrade button must always be the last focus-able element in the dialog. |
|
1499 if ( 'upgrade' === event.target.id && ! event.shiftKey ) { |
357 $( '#hostname' ).focus(); |
1500 $( '#hostname' ).focus(); |
|
1501 |
358 event.preventDefault(); |
1502 event.preventDefault(); |
359 } else if ( event.target.id === 'hostname' && event.shiftKey ) { |
1503 } else if ( 'hostname' === event.target.id && event.shiftKey ) { |
360 $( '#upgrade' ).focus(); |
1504 $( '#upgrade' ).focus(); |
|
1505 |
361 event.preventDefault(); |
1506 event.preventDefault(); |
362 } |
1507 } |
363 } |
1508 } |
364 }; |
1509 }; |
365 |
1510 |
366 /** |
1511 /** |
367 * Open the request for credentials modal. |
1512 * Opens the request for credentials modal. |
368 * |
1513 * |
369 * @since 4.2.0 |
1514 * @since 4.2.0 |
370 */ |
1515 */ |
371 wp.updates.requestForCredentialsModalOpen = function() { |
1516 wp.updates.requestForCredentialsModalOpen = function() { |
372 var $modal = $( '#request-filesystem-credentials-dialog' ); |
1517 var $modal = $( '#request-filesystem-credentials-dialog' ); |
|
1518 |
373 $( 'body' ).addClass( 'modal-open' ); |
1519 $( 'body' ).addClass( 'modal-open' ); |
374 $modal.show(); |
1520 $modal.show(); |
375 |
|
376 $modal.find( 'input:enabled:first' ).focus(); |
1521 $modal.find( 'input:enabled:first' ).focus(); |
377 $modal.keydown( wp.updates.keydown ); |
1522 $modal.on( 'keydown', wp.updates.keydown ); |
378 }; |
1523 }; |
379 |
1524 |
380 /** |
1525 /** |
381 * Close the request for credentials modal. |
1526 * Closes the request for credentials modal. |
382 * |
1527 * |
383 * @since 4.2.0 |
1528 * @since 4.2.0 |
384 */ |
1529 */ |
385 wp.updates.requestForCredentialsModalClose = function() { |
1530 wp.updates.requestForCredentialsModalClose = function() { |
386 $( '#request-filesystem-credentials-dialog' ).hide(); |
1531 $( '#request-filesystem-credentials-dialog' ).hide(); |
387 $( 'body' ).removeClass( 'modal-open' ); |
1532 $( 'body' ).removeClass( 'modal-open' ); |
388 wp.updates.$elToReturnFocusToFromCredentialsModal.focus(); |
1533 |
389 }; |
1534 if ( wp.updates.$elToReturnFocusToFromCredentialsModal ) { |
390 |
1535 wp.updates.$elToReturnFocusToFromCredentialsModal.focus(); |
391 /** |
1536 } |
392 * The steps that need to happen when the modal is canceled out |
1537 }; |
|
1538 |
|
1539 /** |
|
1540 * Takes care of the steps that need to happen when the modal is canceled out. |
393 * |
1541 * |
394 * @since 4.2.0 |
1542 * @since 4.2.0 |
|
1543 * @since 4.6.0 Triggers an event for callbacks to listen to and add their actions. |
395 */ |
1544 */ |
396 wp.updates.requestForCredentialsModalCancel = function() { |
1545 wp.updates.requestForCredentialsModalCancel = function() { |
397 // no updateLock and no updateQueue means we already have cleared things up |
1546 |
398 var slug, $message; |
1547 // Not ajaxLocked and no queue means we already have cleared things up. |
399 |
1548 if ( ! wp.updates.ajaxLocked && ! wp.updates.queue.length ) { |
400 if( wp.updates.updateLock === false && wp.updates.updateQueue.length === 0 ){ |
|
401 return; |
1549 return; |
402 } |
1550 } |
403 |
1551 |
404 slug = wp.updates.updateQueue[0].data.slug, |
1552 _.each( wp.updates.queue, function( job ) { |
405 |
1553 $document.trigger( 'credential-modal-cancel', job ); |
406 // remove the lock, and clear the queue |
1554 } ); |
407 wp.updates.updateLock = false; |
1555 |
408 wp.updates.updateQueue = []; |
1556 // Remove the lock, and clear the queue. |
|
1557 wp.updates.ajaxLocked = false; |
|
1558 wp.updates.queue = []; |
409 |
1559 |
410 wp.updates.requestForCredentialsModalClose(); |
1560 wp.updates.requestForCredentialsModalClose(); |
411 if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) { |
1561 }; |
412 $message = $( '[data-slug="' + slug + '"]' ).next().find( '.update-message' ); |
1562 |
413 } else if ( 'plugin-install' === pagenow ) { |
1563 /** |
414 $message = $( '.plugin-card-' + slug ).find( '.update-now' ); |
1564 * Displays an error message in the request for credentials form. |
415 } |
1565 * |
416 |
1566 * @since 4.2.0 |
417 $message.removeClass( 'updating-message' ); |
1567 * |
418 $message.html( $message.data( 'originaltext' ) ); |
1568 * @param {string} message Error message. |
419 wp.a11y.speak( wp.updates.l10n.updateCancel ); |
1569 */ |
420 }; |
1570 wp.updates.showErrorInCredentialsForm = function( message ) { |
421 /** |
1571 var $filesystemForm = $( '#request-filesystem-credentials-form' ); |
422 * Potentially add an AYS to a user attempting to leave the page |
1572 |
|
1573 // Remove any existing error. |
|
1574 $filesystemForm.find( '.notice' ).remove(); |
|
1575 $filesystemForm.find( '#request-filesystem-credentials-title' ).after( '<div class="notice notice-alt notice-error"><p>' + message + '</p></div>' ); |
|
1576 }; |
|
1577 |
|
1578 /** |
|
1579 * Handles credential errors and runs events that need to happen in that case. |
|
1580 * |
|
1581 * @since 4.2.0 |
|
1582 * |
|
1583 * @param {object} response Ajax response. |
|
1584 * @param {string} action The type of request to perform. |
|
1585 */ |
|
1586 wp.updates.credentialError = function( response, action ) { |
|
1587 |
|
1588 // Restore callbacks. |
|
1589 response = wp.updates._addCallbacks( response, action ); |
|
1590 |
|
1591 wp.updates.queue.unshift( { |
|
1592 action: action, |
|
1593 |
|
1594 /* |
|
1595 * Not cool that we're depending on response for this data. |
|
1596 * This would feel more whole in a view all tied together. |
|
1597 */ |
|
1598 data: response |
|
1599 } ); |
|
1600 |
|
1601 wp.updates.filesystemCredentials.available = false; |
|
1602 wp.updates.showErrorInCredentialsForm( response.errorMessage ); |
|
1603 wp.updates.requestFilesystemCredentials(); |
|
1604 }; |
|
1605 |
|
1606 /** |
|
1607 * Handles credentials errors if it could not connect to the filesystem. |
|
1608 * |
|
1609 * @since 4.6.0 |
|
1610 * |
|
1611 * @typedef {object} maybeHandleCredentialError |
|
1612 * @param {object} response Response from the server. |
|
1613 * @param {string} response.errorCode Error code for the error that occurred. |
|
1614 * @param {string} response.errorMessage The error that occurred. |
|
1615 * @param {string} action The type of request to perform. |
|
1616 * @returns {boolean} Whether there is an error that needs to be handled or not. |
|
1617 */ |
|
1618 wp.updates.maybeHandleCredentialError = function( response, action ) { |
|
1619 if ( wp.updates.shouldRequestFilesystemCredentials && response.errorCode && 'unable_to_connect_to_filesystem' === response.errorCode ) { |
|
1620 wp.updates.credentialError( response, action ); |
|
1621 return true; |
|
1622 } |
|
1623 |
|
1624 return false; |
|
1625 }; |
|
1626 |
|
1627 /** |
|
1628 * Validates an AJAX response to ensure it's a proper object. |
|
1629 * |
|
1630 * If the response deems to be invalid, an admin notice is being displayed. |
|
1631 * |
|
1632 * @param {(object|string)} response Response from the server. |
|
1633 * @param {function=} response.always Optional. Callback for when the Deferred is resolved or rejected. |
|
1634 * @param {string=} response.statusText Optional. Status message corresponding to the status code. |
|
1635 * @param {string=} response.responseText Optional. Request response as text. |
|
1636 * @param {string} action Type of action the response is referring to. Can be 'delete', |
|
1637 * 'update' or 'install'. |
|
1638 */ |
|
1639 wp.updates.isValidResponse = function( response, action ) { |
|
1640 var error = wp.updates.l10n.unknownError, |
|
1641 errorMessage; |
|
1642 |
|
1643 // Make sure the response is a valid data object and not a Promise object. |
|
1644 if ( _.isObject( response ) && ! _.isFunction( response.always ) ) { |
|
1645 return true; |
|
1646 } |
|
1647 |
|
1648 if ( _.isString( response ) && '-1' === response ) { |
|
1649 error = wp.updates.l10n.nonceError; |
|
1650 } else if ( _.isString( response ) ) { |
|
1651 error = response; |
|
1652 } else if ( 'undefined' !== typeof response.readyState && 0 === response.readyState ) { |
|
1653 error = wp.updates.l10n.connectionError; |
|
1654 } else if ( _.isString( response.responseText ) && '' !== response.responseText ) { |
|
1655 error = response.responseText; |
|
1656 } else if ( _.isString( response.statusText ) ) { |
|
1657 error = response.statusText; |
|
1658 } |
|
1659 |
|
1660 switch ( action ) { |
|
1661 case 'update': |
|
1662 errorMessage = wp.updates.l10n.updateFailed; |
|
1663 break; |
|
1664 |
|
1665 case 'install': |
|
1666 errorMessage = wp.updates.l10n.installFailed; |
|
1667 break; |
|
1668 |
|
1669 case 'delete': |
|
1670 errorMessage = wp.updates.l10n.deleteFailed; |
|
1671 break; |
|
1672 } |
|
1673 |
|
1674 // Messages are escaped, remove HTML tags to make them more readable. |
|
1675 error = error.replace( /<[\/a-z][^<>]*>/gi, '' ); |
|
1676 errorMessage = errorMessage.replace( '%s', error ); |
|
1677 |
|
1678 // Add admin notice. |
|
1679 wp.updates.addAdminNotice( { |
|
1680 id: 'unknown_error', |
|
1681 className: 'notice-error is-dismissible', |
|
1682 message: _.escape( errorMessage ) |
|
1683 } ); |
|
1684 |
|
1685 // Remove the lock, and clear the queue. |
|
1686 wp.updates.ajaxLocked = false; |
|
1687 wp.updates.queue = []; |
|
1688 |
|
1689 // Change buttons of all running updates. |
|
1690 $( '.button.updating-message' ) |
|
1691 .removeClass( 'updating-message' ) |
|
1692 .removeAttr( 'aria-label' ) |
|
1693 .prop( 'disabled', true ) |
|
1694 .text( wp.updates.l10n.updateFailedShort ); |
|
1695 |
|
1696 $( '.updating-message:not(.button):not(.thickbox)' ) |
|
1697 .removeClass( 'updating-message notice-warning' ) |
|
1698 .addClass( 'notice-error' ) |
|
1699 .find( 'p' ) |
|
1700 .removeAttr( 'aria-label' ) |
|
1701 .text( errorMessage ); |
|
1702 |
|
1703 wp.a11y.speak( errorMessage, 'assertive' ); |
|
1704 |
|
1705 return false; |
|
1706 }; |
|
1707 |
|
1708 /** |
|
1709 * Potentially adds an AYS to a user attempting to leave the page. |
423 * |
1710 * |
424 * If an update is on-going and a user attempts to leave the page, |
1711 * If an update is on-going and a user attempts to leave the page, |
425 * open an "Are you sure?" alert. |
1712 * opens an "Are you sure?" alert. |
426 * |
1713 * |
427 * @since 4.2.0 |
1714 * @since 4.2.0 |
428 */ |
1715 */ |
429 |
|
430 wp.updates.beforeunload = function() { |
1716 wp.updates.beforeunload = function() { |
431 if ( wp.updates.updateLock ) { |
1717 if ( wp.updates.ajaxLocked ) { |
432 return wp.updates.l10n.beforeunload; |
1718 return wp.updates.l10n.beforeunload; |
433 } |
1719 } |
434 }; |
1720 }; |
435 |
1721 |
436 |
1722 $( function() { |
437 $( document ).ready( function() { |
1723 var $pluginFilter = $( '#plugin-filter' ), |
|
1724 $bulkActionForm = $( '#bulk-action-form' ), |
|
1725 $filesystemForm = $( '#request-filesystem-credentials-form' ), |
|
1726 $filesystemModal = $( '#request-filesystem-credentials-dialog' ), |
|
1727 $pluginSearch = $( '.plugins-php .wp-filter-search' ), |
|
1728 $pluginInstallSearch = $( '.plugin-install-php .wp-filter-search' ); |
|
1729 |
|
1730 settings = _.extend( settings, window._wpUpdatesItemCounts || {} ); |
|
1731 |
|
1732 if ( settings.totals ) { |
|
1733 wp.updates.refreshCount(); |
|
1734 } |
|
1735 |
438 /* |
1736 /* |
439 * Check whether a user needs to submit filesystem credentials based on whether |
1737 * Whether a user needs to submit filesystem credentials. |
440 * the form was output on the page server-side. |
1738 * |
|
1739 * This is based on whether the form was output on the page server-side. |
441 * |
1740 * |
442 * @see {wp_print_request_filesystem_credentials_modal() in PHP} |
1741 * @see {wp_print_request_filesystem_credentials_modal() in PHP} |
443 */ |
1742 */ |
444 wp.updates.shouldRequestFilesystemCredentials = ( $( '#request-filesystem-credentials-dialog' ).length <= 0 ) ? false : true; |
1743 wp.updates.shouldRequestFilesystemCredentials = $filesystemModal.length > 0; |
445 |
1744 |
446 // File system credentials form submit noop-er / handler. |
1745 /** |
447 $( '#request-filesystem-credentials-dialog form' ).on( 'submit', function() { |
1746 * File system credentials form submit noop-er / handler. |
|
1747 * |
|
1748 * @since 4.2.0 |
|
1749 */ |
|
1750 $filesystemModal.on( 'submit', 'form', function( event ) { |
|
1751 event.preventDefault(); |
|
1752 |
448 // Persist the credentials input by the user for the duration of the page load. |
1753 // Persist the credentials input by the user for the duration of the page load. |
449 wp.updates.filesystemCredentials.ftp.hostname = $('#hostname').val(); |
1754 wp.updates.filesystemCredentials.ftp.hostname = $( '#hostname' ).val(); |
450 wp.updates.filesystemCredentials.ftp.username = $('#username').val(); |
1755 wp.updates.filesystemCredentials.ftp.username = $( '#username' ).val(); |
451 wp.updates.filesystemCredentials.ftp.password = $('#password').val(); |
1756 wp.updates.filesystemCredentials.ftp.password = $( '#password' ).val(); |
452 wp.updates.filesystemCredentials.ftp.connectionType = $('input[name="connection_type"]:checked').val(); |
1757 wp.updates.filesystemCredentials.ftp.connectionType = $( 'input[name="connection_type"]:checked' ).val(); |
453 wp.updates.filesystemCredentials.ssh.publicKey = $('#public_key').val(); |
1758 wp.updates.filesystemCredentials.ssh.publicKey = $( '#public_key' ).val(); |
454 wp.updates.filesystemCredentials.ssh.privateKey = $('#private_key').val(); |
1759 wp.updates.filesystemCredentials.ssh.privateKey = $( '#private_key' ).val(); |
|
1760 wp.updates.filesystemCredentials.fsNonce = $( '#_fs_nonce' ).val(); |
|
1761 wp.updates.filesystemCredentials.available = true; |
|
1762 |
|
1763 // Unlock and invoke the queue. |
|
1764 wp.updates.ajaxLocked = false; |
|
1765 wp.updates.queueChecker(); |
455 |
1766 |
456 wp.updates.requestForCredentialsModalClose(); |
1767 wp.updates.requestForCredentialsModalClose(); |
457 |
1768 } ); |
458 // Unlock and invoke the queue. |
1769 |
459 wp.updates.updateLock = false; |
1770 /** |
|
1771 * Closes the request credentials modal when clicking the 'Cancel' button or outside of the modal. |
|
1772 * |
|
1773 * @since 4.2.0 |
|
1774 */ |
|
1775 $filesystemModal.on( 'click', '[data-js-action="close"], .notification-dialog-background', wp.updates.requestForCredentialsModalCancel ); |
|
1776 |
|
1777 /** |
|
1778 * Hide SSH fields when not selected. |
|
1779 * |
|
1780 * @since 4.2.0 |
|
1781 */ |
|
1782 $filesystemForm.on( 'change', 'input[name="connection_type"]', function() { |
|
1783 $( '#ssh-keys' ).toggleClass( 'hidden', ( 'ssh' !== $( this ).val() ) ); |
|
1784 } ).change(); |
|
1785 |
|
1786 /** |
|
1787 * Handles events after the credential modal was closed. |
|
1788 * |
|
1789 * @since 4.6.0 |
|
1790 * |
|
1791 * @param {Event} event Event interface. |
|
1792 * @param {string} job The install/update.delete request. |
|
1793 */ |
|
1794 $document.on( 'credential-modal-cancel', function( event, job ) { |
|
1795 var $updatingMessage = $( '.updating-message' ), |
|
1796 $message, originalText; |
|
1797 |
|
1798 if ( 'import' === pagenow ) { |
|
1799 $updatingMessage.removeClass( 'updating-message' ); |
|
1800 } else if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) { |
|
1801 if ( 'update-plugin' === job.action ) { |
|
1802 $message = $( 'tr[data-plugin="' + job.data.plugin + '"]' ).find( '.update-message' ); |
|
1803 } else if ( 'delete-plugin' === job.action ) { |
|
1804 $message = $( '[data-plugin="' + job.data.plugin + '"]' ).find( '.row-actions a.delete' ); |
|
1805 } |
|
1806 } else if ( 'themes' === pagenow || 'themes-network' === pagenow ) { |
|
1807 if ( 'update-theme' === job.action ) { |
|
1808 $message = $( '[data-slug="' + job.data.slug + '"]' ).find( '.update-message' ); |
|
1809 } else if ( 'delete-theme' === job.action && 'themes-network' === pagenow ) { |
|
1810 $message = $( '[data-slug="' + job.data.slug + '"]' ).find( '.row-actions a.delete' ); |
|
1811 } else if ( 'delete-theme' === job.action && 'themes' === pagenow ) { |
|
1812 $message = $( '.theme-actions .delete-theme' ); |
|
1813 } |
|
1814 } else { |
|
1815 $message = $updatingMessage; |
|
1816 } |
|
1817 |
|
1818 if ( $message && $message.hasClass( 'updating-message' ) ) { |
|
1819 originalText = $message.data( 'originaltext' ); |
|
1820 |
|
1821 if ( 'undefined' === typeof originalText ) { |
|
1822 originalText = $( '<p>' ).html( $message.find( 'p' ).data( 'originaltext' ) ); |
|
1823 } |
|
1824 |
|
1825 $message |
|
1826 .removeClass( 'updating-message' ) |
|
1827 .html( originalText ); |
|
1828 |
|
1829 if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) { |
|
1830 if ( 'update-plugin' === job.action ) { |
|
1831 $message.attr( 'aria-label', wp.updates.l10n.pluginUpdateNowLabel.replace( '%s', $message.data( 'name' ) ) ); |
|
1832 } else if ( 'install-plugin' === job.action ) { |
|
1833 $message.attr( 'aria-label', wp.updates.l10n.pluginInstallNowLabel.replace( '%s', $message.data( 'name' ) ) ); |
|
1834 } |
|
1835 } |
|
1836 } |
|
1837 |
|
1838 wp.a11y.speak( wp.updates.l10n.updateCancel, 'polite' ); |
|
1839 } ); |
|
1840 |
|
1841 /** |
|
1842 * Click handler for plugin updates in List Table view. |
|
1843 * |
|
1844 * @since 4.2.0 |
|
1845 * |
|
1846 * @param {Event} event Event interface. |
|
1847 */ |
|
1848 $bulkActionForm.on( 'click', '[data-plugin] .update-link', function( event ) { |
|
1849 var $message = $( event.target ), |
|
1850 $pluginRow = $message.parents( 'tr' ); |
|
1851 |
|
1852 event.preventDefault(); |
|
1853 |
|
1854 if ( $message.hasClass( 'updating-message' ) || $message.hasClass( 'button-disabled' ) ) { |
|
1855 return; |
|
1856 } |
|
1857 |
|
1858 wp.updates.maybeRequestFilesystemCredentials( event ); |
|
1859 |
|
1860 // Return the user to the input box of the plugin's table row after closing the modal. |
|
1861 wp.updates.$elToReturnFocusToFromCredentialsModal = $pluginRow.find( '.check-column input' ); |
|
1862 wp.updates.updatePlugin( { |
|
1863 plugin: $pluginRow.data( 'plugin' ), |
|
1864 slug: $pluginRow.data( 'slug' ) |
|
1865 } ); |
|
1866 } ); |
|
1867 |
|
1868 /** |
|
1869 * Click handler for plugin updates in plugin install view. |
|
1870 * |
|
1871 * @since 4.2.0 |
|
1872 * |
|
1873 * @param {Event} event Event interface. |
|
1874 */ |
|
1875 $pluginFilter.on( 'click', '.update-now', function( event ) { |
|
1876 var $button = $( event.target ); |
|
1877 event.preventDefault(); |
|
1878 |
|
1879 if ( $button.hasClass( 'updating-message' ) || $button.hasClass( 'button-disabled' ) ) { |
|
1880 return; |
|
1881 } |
|
1882 |
|
1883 wp.updates.maybeRequestFilesystemCredentials( event ); |
|
1884 |
|
1885 wp.updates.updatePlugin( { |
|
1886 plugin: $button.data( 'plugin' ), |
|
1887 slug: $button.data( 'slug' ) |
|
1888 } ); |
|
1889 } ); |
|
1890 |
|
1891 /** |
|
1892 * Click handler for plugin installs in plugin install view. |
|
1893 * |
|
1894 * @since 4.6.0 |
|
1895 * |
|
1896 * @param {Event} event Event interface. |
|
1897 */ |
|
1898 $pluginFilter.on( 'click', '.install-now', function( event ) { |
|
1899 var $button = $( event.target ); |
|
1900 event.preventDefault(); |
|
1901 |
|
1902 if ( $button.hasClass( 'updating-message' ) || $button.hasClass( 'button-disabled' ) ) { |
|
1903 return; |
|
1904 } |
|
1905 |
|
1906 if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.ajaxLocked ) { |
|
1907 wp.updates.requestFilesystemCredentials( event ); |
|
1908 |
|
1909 $document.on( 'credential-modal-cancel', function() { |
|
1910 var $message = $( '.install-now.updating-message' ); |
|
1911 |
|
1912 $message |
|
1913 .removeClass( 'updating-message' ) |
|
1914 .text( wp.updates.l10n.installNow ); |
|
1915 |
|
1916 wp.a11y.speak( wp.updates.l10n.updateCancel, 'polite' ); |
|
1917 } ); |
|
1918 } |
|
1919 |
|
1920 wp.updates.installPlugin( { |
|
1921 slug: $button.data( 'slug' ) |
|
1922 } ); |
|
1923 } ); |
|
1924 |
|
1925 /** |
|
1926 * Click handler for importer plugins installs in the Import screen. |
|
1927 * |
|
1928 * @since 4.6.0 |
|
1929 * |
|
1930 * @param {Event} event Event interface. |
|
1931 */ |
|
1932 $document.on( 'click', '.importer-item .install-now', function( event ) { |
|
1933 var $button = $( event.target ), |
|
1934 pluginName = $( this ).data( 'name' ); |
|
1935 |
|
1936 event.preventDefault(); |
|
1937 |
|
1938 if ( $button.hasClass( 'updating-message' ) ) { |
|
1939 return; |
|
1940 } |
|
1941 |
|
1942 if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.ajaxLocked ) { |
|
1943 wp.updates.requestFilesystemCredentials( event ); |
|
1944 |
|
1945 $document.on( 'credential-modal-cancel', function() { |
|
1946 |
|
1947 $button |
|
1948 .removeClass( 'updating-message' ) |
|
1949 .text( wp.updates.l10n.installNow ) |
|
1950 .attr( 'aria-label', wp.updates.l10n.installNowLabel.replace( '%s', pluginName ) ); |
|
1951 |
|
1952 wp.a11y.speak( wp.updates.l10n.updateCancel, 'polite' ); |
|
1953 } ); |
|
1954 } |
|
1955 |
|
1956 wp.updates.installPlugin( { |
|
1957 slug: $button.data( 'slug' ), |
|
1958 pagenow: pagenow, |
|
1959 success: wp.updates.installImporterSuccess, |
|
1960 error: wp.updates.installImporterError |
|
1961 } ); |
|
1962 } ); |
|
1963 |
|
1964 /** |
|
1965 * Click handler for plugin deletions. |
|
1966 * |
|
1967 * @since 4.6.0 |
|
1968 * |
|
1969 * @param {Event} event Event interface. |
|
1970 */ |
|
1971 $bulkActionForm.on( 'click', '[data-plugin] a.delete', function( event ) { |
|
1972 var $pluginRow = $( event.target ).parents( 'tr' ); |
|
1973 |
|
1974 event.preventDefault(); |
|
1975 |
|
1976 if ( ! window.confirm( wp.updates.l10n.aysDeleteUninstall.replace( '%s', $pluginRow.find( '.plugin-title strong' ).text() ) ) ) { |
|
1977 return; |
|
1978 } |
|
1979 |
|
1980 wp.updates.maybeRequestFilesystemCredentials( event ); |
|
1981 |
|
1982 wp.updates.deletePlugin( { |
|
1983 plugin: $pluginRow.data( 'plugin' ), |
|
1984 slug: $pluginRow.data( 'slug' ) |
|
1985 } ); |
|
1986 |
|
1987 } ); |
|
1988 |
|
1989 /** |
|
1990 * Click handler for theme updates. |
|
1991 * |
|
1992 * @since 4.6.0 |
|
1993 * |
|
1994 * @param {Event} event Event interface. |
|
1995 */ |
|
1996 $document.on( 'click', '.themes-php.network-admin .update-link', function( event ) { |
|
1997 var $message = $( event.target ), |
|
1998 $themeRow = $message.parents( 'tr' ); |
|
1999 |
|
2000 event.preventDefault(); |
|
2001 |
|
2002 if ( $message.hasClass( 'updating-message' ) || $message.hasClass( 'button-disabled' ) ) { |
|
2003 return; |
|
2004 } |
|
2005 |
|
2006 wp.updates.maybeRequestFilesystemCredentials( event ); |
|
2007 |
|
2008 // Return the user to the input box of the theme's table row after closing the modal. |
|
2009 wp.updates.$elToReturnFocusToFromCredentialsModal = $themeRow.find( '.check-column input' ); |
|
2010 wp.updates.updateTheme( { |
|
2011 slug: $themeRow.data( 'slug' ) |
|
2012 } ); |
|
2013 } ); |
|
2014 |
|
2015 /** |
|
2016 * Click handler for theme deletions. |
|
2017 * |
|
2018 * @since 4.6.0 |
|
2019 * |
|
2020 * @param {Event} event Event interface. |
|
2021 */ |
|
2022 $document.on( 'click', '.themes-php.network-admin a.delete', function( event ) { |
|
2023 var $themeRow = $( event.target ).parents( 'tr' ); |
|
2024 |
|
2025 event.preventDefault(); |
|
2026 |
|
2027 if ( ! window.confirm( wp.updates.l10n.aysDelete.replace( '%s', $themeRow.find( '.theme-title strong' ).text() ) ) ) { |
|
2028 return; |
|
2029 } |
|
2030 |
|
2031 wp.updates.maybeRequestFilesystemCredentials( event ); |
|
2032 |
|
2033 wp.updates.deleteTheme( { |
|
2034 slug: $themeRow.data( 'slug' ) |
|
2035 } ); |
|
2036 } ); |
|
2037 |
|
2038 /** |
|
2039 * Bulk action handler for plugins and themes. |
|
2040 * |
|
2041 * Handles both deletions and updates. |
|
2042 * |
|
2043 * @since 4.6.0 |
|
2044 * |
|
2045 * @param {Event} event Event interface. |
|
2046 */ |
|
2047 $bulkActionForm.on( 'click', '[type="submit"]:not([name="clear-recent-list"])', function( event ) { |
|
2048 var bulkAction = $( event.target ).siblings( 'select' ).val(), |
|
2049 itemsSelected = $bulkActionForm.find( 'input[name="checked[]"]:checked' ), |
|
2050 success = 0, |
|
2051 error = 0, |
|
2052 errorMessages = [], |
|
2053 type, action; |
|
2054 |
|
2055 // Determine which type of item we're dealing with. |
|
2056 switch ( pagenow ) { |
|
2057 case 'plugins': |
|
2058 case 'plugins-network': |
|
2059 type = 'plugin'; |
|
2060 break; |
|
2061 |
|
2062 case 'themes-network': |
|
2063 type = 'theme'; |
|
2064 break; |
|
2065 |
|
2066 default: |
|
2067 return; |
|
2068 } |
|
2069 |
|
2070 // Bail if there were no items selected. |
|
2071 if ( ! itemsSelected.length ) { |
|
2072 event.preventDefault(); |
|
2073 $( 'html, body' ).animate( { scrollTop: 0 } ); |
|
2074 |
|
2075 return wp.updates.addAdminNotice( { |
|
2076 id: 'no-items-selected', |
|
2077 className: 'notice-error is-dismissible', |
|
2078 message: wp.updates.l10n.noItemsSelected |
|
2079 } ); |
|
2080 } |
|
2081 |
|
2082 // Determine the type of request we're dealing with. |
|
2083 switch ( bulkAction ) { |
|
2084 case 'update-selected': |
|
2085 action = bulkAction.replace( 'selected', type ); |
|
2086 break; |
|
2087 |
|
2088 case 'delete-selected': |
|
2089 if ( ! window.confirm( 'plugin' === type ? wp.updates.l10n.aysBulkDelete : wp.updates.l10n.aysBulkDeleteThemes ) ) { |
|
2090 event.preventDefault(); |
|
2091 return; |
|
2092 } |
|
2093 |
|
2094 action = bulkAction.replace( 'selected', type ); |
|
2095 break; |
|
2096 |
|
2097 default: |
|
2098 return; |
|
2099 } |
|
2100 |
|
2101 wp.updates.maybeRequestFilesystemCredentials( event ); |
|
2102 |
|
2103 event.preventDefault(); |
|
2104 |
|
2105 // Un-check the bulk checkboxes. |
|
2106 $bulkActionForm.find( '.manage-column [type="checkbox"]' ).prop( 'checked', false ); |
|
2107 |
|
2108 $document.trigger( 'wp-' + type + '-bulk-' + bulkAction, itemsSelected ); |
|
2109 |
|
2110 // Find all the checkboxes which have been checked. |
|
2111 itemsSelected.each( function( index, element ) { |
|
2112 var $checkbox = $( element ), |
|
2113 $itemRow = $checkbox.parents( 'tr' ); |
|
2114 |
|
2115 // Only add update-able items to the update queue. |
|
2116 if ( 'update-selected' === bulkAction && ( ! $itemRow.hasClass( 'update' ) || $itemRow.find( 'notice-error' ).length ) ) { |
|
2117 |
|
2118 // Un-check the box. |
|
2119 $checkbox.prop( 'checked', false ); |
|
2120 return; |
|
2121 } |
|
2122 |
|
2123 // Add it to the queue. |
|
2124 wp.updates.queue.push( { |
|
2125 action: action, |
|
2126 data: { |
|
2127 plugin: $itemRow.data( 'plugin' ), |
|
2128 slug: $itemRow.data( 'slug' ) |
|
2129 } |
|
2130 } ); |
|
2131 } ); |
|
2132 |
|
2133 // Display bulk notification for updates of any kind. |
|
2134 $document.on( 'wp-plugin-update-success wp-plugin-update-error wp-theme-update-success wp-theme-update-error', function( event, response ) { |
|
2135 var $itemRow = $( '[data-slug="' + response.slug + '"]' ), |
|
2136 $bulkActionNotice, itemName; |
|
2137 |
|
2138 if ( 'wp-' + response.update + '-update-success' === event.type ) { |
|
2139 success++; |
|
2140 } else { |
|
2141 itemName = response.pluginName ? response.pluginName : $itemRow.find( '.column-primary strong' ).text(); |
|
2142 |
|
2143 error++; |
|
2144 errorMessages.push( itemName + ': ' + response.errorMessage ); |
|
2145 } |
|
2146 |
|
2147 $itemRow.find( 'input[name="checked[]"]:checked' ).prop( 'checked', false ); |
|
2148 |
|
2149 wp.updates.adminNotice = wp.template( 'wp-bulk-updates-admin-notice' ); |
|
2150 |
|
2151 wp.updates.addAdminNotice( { |
|
2152 id: 'bulk-action-notice', |
|
2153 className: 'bulk-action-notice', |
|
2154 successes: success, |
|
2155 errors: error, |
|
2156 errorMessages: errorMessages, |
|
2157 type: response.update |
|
2158 } ); |
|
2159 |
|
2160 $bulkActionNotice = $( '#bulk-action-notice' ).on( 'click', 'button', function() { |
|
2161 // $( this ) is the clicked button, no need to get it again. |
|
2162 $( this ) |
|
2163 .toggleClass( 'bulk-action-errors-collapsed' ) |
|
2164 .attr( 'aria-expanded', ! $( this ).hasClass( 'bulk-action-errors-collapsed' ) ); |
|
2165 // Show the errors list. |
|
2166 $bulkActionNotice.find( '.bulk-action-errors' ).toggleClass( 'hidden' ); |
|
2167 } ); |
|
2168 |
|
2169 if ( error > 0 && ! wp.updates.queue.length ) { |
|
2170 $( 'html, body' ).animate( { scrollTop: 0 } ); |
|
2171 } |
|
2172 } ); |
|
2173 |
|
2174 // Reset admin notice template after #bulk-action-notice was added. |
|
2175 $document.on( 'wp-updates-notice-added', function() { |
|
2176 wp.updates.adminNotice = wp.template( 'wp-updates-admin-notice' ); |
|
2177 } ); |
|
2178 |
|
2179 // Check the queue, now that the event handlers have been added. |
460 wp.updates.queueChecker(); |
2180 wp.updates.queueChecker(); |
461 |
2181 } ); |
462 return false; |
2182 |
463 }); |
2183 if ( $pluginInstallSearch.length ) { |
464 |
2184 $pluginInstallSearch.attr( 'aria-describedby', 'live-search-desc' ); |
465 // Close the request credentials modal when |
2185 } |
466 $( '#request-filesystem-credentials-dialog [data-js-action="close"], .notification-dialog-background' ).on( 'click', function() { |
2186 |
467 wp.updates.requestForCredentialsModalCancel(); |
2187 /** |
468 }); |
2188 * Handles changes to the plugin search box on the new-plugin page, |
469 |
2189 * searching the repository dynamically. |
470 // Click handler for plugin updates in List Table view. |
2190 * |
471 $( '.plugin-update-tr' ).on( 'click', '.update-link', function( e ) { |
2191 * @since 4.6.0 |
472 e.preventDefault(); |
2192 */ |
473 if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.updateLock ) { |
2193 $pluginInstallSearch.on( 'keyup input', _.debounce( function( event, eventtype ) { |
474 wp.updates.requestFilesystemCredentials( e ); |
2194 var $searchTab = $( '.plugin-install-search' ), data, searchLocation; |
475 } |
2195 |
476 var updateRow = $( e.target ).parents( '.plugin-update-tr' ); |
2196 data = { |
477 // Return the user to the input box of the plugin's table row after closing the modal. |
2197 _ajax_nonce: wp.updates.ajaxNonce, |
478 wp.updates.$elToReturnFocusToFromCredentialsModal = $( '#' + updateRow.data( 'slug' ) ).find( '.check-column input' ); |
2198 s: event.target.value, |
479 wp.updates.updatePlugin( updateRow.data( 'plugin' ), updateRow.data( 'slug' ) ); |
2199 tab: 'search', |
480 } ); |
2200 type: $( '#typeselector' ).val(), |
481 |
2201 pagenow: pagenow |
482 $( '.plugin-card' ).on( 'click', '.update-now', function( e ) { |
2202 }; |
483 e.preventDefault(); |
2203 searchLocation = location.href.split( '?' )[ 0 ] + '?' + $.param( _.omit( data, [ '_ajax_nonce', 'pagenow' ] ) ); |
484 var $button = $( e.target ); |
2204 |
485 |
2205 // Clear on escape. |
486 if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.updateLock ) { |
2206 if ( 'keyup' === event.type && 27 === event.which ) { |
487 wp.updates.requestFilesystemCredentials( e ); |
2207 event.target.value = ''; |
488 } |
2208 } |
489 |
2209 |
490 wp.updates.updatePlugin( $button.data( 'plugin' ), $button.data( 'slug' ) ); |
2210 if ( wp.updates.searchTerm === data.s && 'typechange' !== eventtype ) { |
491 } ); |
2211 return; |
492 |
2212 } else { |
493 // |
2213 $pluginFilter.empty(); |
494 $( '#plugin_update_from_iframe' ).on( 'click' , function( e ) { |
2214 wp.updates.searchTerm = data.s; |
495 var target, data; |
2215 } |
496 |
2216 |
497 target = window.parent == window ? null : window.parent, |
2217 if ( window.history && window.history.replaceState ) { |
|
2218 window.history.replaceState( null, '', searchLocation ); |
|
2219 } |
|
2220 |
|
2221 if ( ! $searchTab.length ) { |
|
2222 $searchTab = $( '<li class="plugin-install-search" />' ) |
|
2223 .append( $( '<a />', { |
|
2224 'class': 'current', |
|
2225 'href': searchLocation, |
|
2226 'text': wp.updates.l10n.searchResultsLabel |
|
2227 } ) ); |
|
2228 |
|
2229 $( '.wp-filter .filter-links .current' ) |
|
2230 .removeClass( 'current' ) |
|
2231 .parents( '.filter-links' ) |
|
2232 .prepend( $searchTab ); |
|
2233 |
|
2234 $pluginFilter.prev( 'p' ).remove(); |
|
2235 $( '.plugins-popular-tags-wrapper' ).remove(); |
|
2236 } |
|
2237 |
|
2238 if ( 'undefined' !== typeof wp.updates.searchRequest ) { |
|
2239 wp.updates.searchRequest.abort(); |
|
2240 } |
|
2241 $( 'body' ).addClass( 'loading-content' ); |
|
2242 |
|
2243 wp.updates.searchRequest = wp.ajax.post( 'search-install-plugins', data ).done( function( response ) { |
|
2244 $( 'body' ).removeClass( 'loading-content' ); |
|
2245 $pluginFilter.append( response.items ); |
|
2246 delete wp.updates.searchRequest; |
|
2247 |
|
2248 if ( 0 === response.count ) { |
|
2249 wp.a11y.speak( wp.updates.l10n.noPluginsFound ); |
|
2250 } else { |
|
2251 wp.a11y.speak( wp.updates.l10n.pluginsFound.replace( '%d', response.count ) ); |
|
2252 } |
|
2253 } ); |
|
2254 }, 500 ) ); |
|
2255 |
|
2256 if ( $pluginSearch.length ) { |
|
2257 $pluginSearch.attr( 'aria-describedby', 'live-search-desc' ); |
|
2258 } |
|
2259 |
|
2260 /** |
|
2261 * Handles changes to the plugin search box on the Installed Plugins screen, |
|
2262 * searching the plugin list dynamically. |
|
2263 * |
|
2264 * @since 4.6.0 |
|
2265 */ |
|
2266 $pluginSearch.on( 'keyup input', _.debounce( function( event ) { |
|
2267 var data = { |
|
2268 _ajax_nonce: wp.updates.ajaxNonce, |
|
2269 s: event.target.value, |
|
2270 pagenow: pagenow, |
|
2271 plugin_status: 'all' |
|
2272 }, |
|
2273 queryArgs; |
|
2274 |
|
2275 // Clear on escape. |
|
2276 if ( 'keyup' === event.type && 27 === event.which ) { |
|
2277 event.target.value = ''; |
|
2278 } |
|
2279 |
|
2280 if ( wp.updates.searchTerm === data.s ) { |
|
2281 return; |
|
2282 } else { |
|
2283 wp.updates.searchTerm = data.s; |
|
2284 } |
|
2285 |
|
2286 queryArgs = _.object( _.compact( _.map( location.search.slice( 1 ).split( '&' ), function( item ) { |
|
2287 if ( item ) return item.split( '=' ); |
|
2288 } ) ) ); |
|
2289 |
|
2290 data.plugin_status = queryArgs.plugin_status || 'all'; |
|
2291 |
|
2292 if ( window.history && window.history.replaceState ) { |
|
2293 window.history.replaceState( null, '', location.href.split( '?' )[ 0 ] + '?s=' + data.s + '&plugin_status=' + data.plugin_status ); |
|
2294 } |
|
2295 |
|
2296 if ( 'undefined' !== typeof wp.updates.searchRequest ) { |
|
2297 wp.updates.searchRequest.abort(); |
|
2298 } |
|
2299 |
|
2300 $bulkActionForm.empty(); |
|
2301 $( 'body' ).addClass( 'loading-content' ); |
|
2302 $( '.subsubsub .current' ).removeClass( 'current' ); |
|
2303 |
|
2304 wp.updates.searchRequest = wp.ajax.post( 'search-plugins', data ).done( function( response ) { |
|
2305 |
|
2306 // Can we just ditch this whole subtitle business? |
|
2307 var $subTitle = $( '<span />' ).addClass( 'subtitle' ).html( wp.updates.l10n.searchResults.replace( '%s', _.escape( data.s ) ) ), |
|
2308 $oldSubTitle = $( '.wrap .subtitle' ); |
|
2309 |
|
2310 if ( ! data.s.length ) { |
|
2311 $oldSubTitle.remove(); |
|
2312 $( '.subsubsub .' + data.plugin_status + ' a' ).addClass( 'current' ); |
|
2313 } else if ( $oldSubTitle.length ) { |
|
2314 $oldSubTitle.replaceWith( $subTitle ); |
|
2315 } else { |
|
2316 $( '.wp-header-end' ).before( $subTitle ); |
|
2317 } |
|
2318 |
|
2319 $( 'body' ).removeClass( 'loading-content' ); |
|
2320 $bulkActionForm.append( response.items ); |
|
2321 delete wp.updates.searchRequest; |
|
2322 |
|
2323 if ( 0 === response.count ) { |
|
2324 wp.a11y.speak( wp.updates.l10n.noPluginsFound ); |
|
2325 } else { |
|
2326 wp.a11y.speak( wp.updates.l10n.pluginsFound.replace( '%d', response.count ) ); |
|
2327 } |
|
2328 } ); |
|
2329 }, 500 ) ); |
|
2330 |
|
2331 /** |
|
2332 * Trigger a search event when the search form gets submitted. |
|
2333 * |
|
2334 * @since 4.6.0 |
|
2335 */ |
|
2336 $document.on( 'submit', '.search-plugins', function( event ) { |
|
2337 event.preventDefault(); |
|
2338 |
|
2339 $( 'input.wp-filter-search' ).trigger( 'input' ); |
|
2340 } ); |
|
2341 |
|
2342 /** |
|
2343 * Trigger a search event when the "Try Again" button is clicked. |
|
2344 * |
|
2345 * @since 4.9.0 |
|
2346 */ |
|
2347 $document.on( 'click', '.try-again', function( event ) { |
|
2348 event.preventDefault(); |
|
2349 $pluginInstallSearch.trigger( 'input' ); |
|
2350 } ); |
|
2351 |
|
2352 /** |
|
2353 * Trigger a search event when the search type gets changed. |
|
2354 * |
|
2355 * @since 4.6.0 |
|
2356 */ |
|
2357 $( '#typeselector' ).on( 'change', function() { |
|
2358 var $search = $( 'input[name="s"]' ); |
|
2359 |
|
2360 if ( $search.val().length ) { |
|
2361 $search.trigger( 'input', 'typechange' ); |
|
2362 } |
|
2363 } ); |
|
2364 |
|
2365 /** |
|
2366 * Click handler for updating a plugin from the details modal on `plugin-install.php`. |
|
2367 * |
|
2368 * @since 4.2.0 |
|
2369 * |
|
2370 * @param {Event} event Event interface. |
|
2371 */ |
|
2372 $( '#plugin_update_from_iframe' ).on( 'click', function( event ) { |
|
2373 var target = window.parent === window ? null : window.parent, |
|
2374 update; |
|
2375 |
498 $.support.postMessage = !! window.postMessage; |
2376 $.support.postMessage = !! window.postMessage; |
499 |
2377 |
500 if ( $.support.postMessage === false || target === null || window.parent.location.pathname.indexOf( 'update-core.php' ) !== -1 ) |
2378 if ( false === $.support.postMessage || null === target || -1 !== window.parent.location.pathname.indexOf( 'update-core.php' ) ) { |
501 return; |
2379 return; |
502 |
2380 } |
503 e.preventDefault(); |
2381 |
504 |
2382 event.preventDefault(); |
505 data = { |
2383 |
506 'action' : 'updatePlugin', |
2384 update = { |
507 'slug' : $(this).data('slug') |
2385 action: 'update-plugin', |
|
2386 data: { |
|
2387 plugin: $( this ).data( 'plugin' ), |
|
2388 slug: $( this ).data( 'slug' ) |
|
2389 } |
508 }; |
2390 }; |
509 |
2391 |
510 target.postMessage( JSON.stringify( data ), window.location.origin ); |
2392 target.postMessage( JSON.stringify( update ), window.location.origin ); |
511 }); |
2393 } ); |
512 |
2394 |
|
2395 /** |
|
2396 * Click handler for installing a plugin from the details modal on `plugin-install.php`. |
|
2397 * |
|
2398 * @since 4.6.0 |
|
2399 * |
|
2400 * @param {Event} event Event interface. |
|
2401 */ |
|
2402 $( '#plugin_install_from_iframe' ).on( 'click', function( event ) { |
|
2403 var target = window.parent === window ? null : window.parent, |
|
2404 install; |
|
2405 |
|
2406 $.support.postMessage = !! window.postMessage; |
|
2407 |
|
2408 if ( false === $.support.postMessage || null === target || -1 !== window.parent.location.pathname.indexOf( 'index.php' ) ) { |
|
2409 return; |
|
2410 } |
|
2411 |
|
2412 event.preventDefault(); |
|
2413 |
|
2414 install = { |
|
2415 action: 'install-plugin', |
|
2416 data: { |
|
2417 slug: $( this ).data( 'slug' ) |
|
2418 } |
|
2419 }; |
|
2420 |
|
2421 target.postMessage( JSON.stringify( install ), window.location.origin ); |
|
2422 } ); |
|
2423 |
|
2424 /** |
|
2425 * Handles postMessage events. |
|
2426 * |
|
2427 * @since 4.2.0 |
|
2428 * @since 4.6.0 Switched `update-plugin` action to use the queue. |
|
2429 * |
|
2430 * @param {Event} event Event interface. |
|
2431 */ |
|
2432 $( window ).on( 'message', function( event ) { |
|
2433 var originalEvent = event.originalEvent, |
|
2434 expectedOrigin = document.location.protocol + '//' + document.location.hostname, |
|
2435 message; |
|
2436 |
|
2437 if ( originalEvent.origin !== expectedOrigin ) { |
|
2438 return; |
|
2439 } |
|
2440 |
|
2441 try { |
|
2442 message = $.parseJSON( originalEvent.data ); |
|
2443 } catch ( e ) { |
|
2444 return; |
|
2445 } |
|
2446 |
|
2447 if ( ! message || 'undefined' === typeof message.action ) { |
|
2448 return; |
|
2449 } |
|
2450 |
|
2451 switch ( message.action ) { |
|
2452 |
|
2453 // Called from `wp-admin/includes/class-wp-upgrader-skins.php`. |
|
2454 case 'decrementUpdateCount': |
|
2455 /** @property {string} message.upgradeType */ |
|
2456 wp.updates.decrementCount( message.upgradeType ); |
|
2457 break; |
|
2458 |
|
2459 case 'install-plugin': |
|
2460 case 'update-plugin': |
|
2461 /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */ |
|
2462 window.tb_remove(); |
|
2463 /* jscs:enable */ |
|
2464 |
|
2465 message.data = wp.updates._addCallbacks( message.data, message.action ); |
|
2466 |
|
2467 wp.updates.queue.push( message ); |
|
2468 wp.updates.queueChecker(); |
|
2469 break; |
|
2470 } |
|
2471 } ); |
|
2472 |
|
2473 /** |
|
2474 * Adds a callback to display a warning before leaving the page. |
|
2475 * |
|
2476 * @since 4.2.0 |
|
2477 */ |
|
2478 $( window ).on( 'beforeunload', wp.updates.beforeunload ); |
513 } ); |
2479 } ); |
514 |
2480 })( jQuery, window.wp, window._wpUpdatesSettings ); |
515 $( window ).on( 'message', function( e ) { |
|
516 var event = e.originalEvent, |
|
517 message, |
|
518 loc = document.location, |
|
519 expectedOrigin = loc.protocol + '//' + loc.hostname; |
|
520 |
|
521 if ( event.origin !== expectedOrigin ) { |
|
522 return; |
|
523 } |
|
524 |
|
525 message = $.parseJSON( event.data ); |
|
526 |
|
527 if ( typeof message.action === 'undefined' ) { |
|
528 return; |
|
529 } |
|
530 |
|
531 switch (message.action){ |
|
532 case 'decrementUpdateCount' : |
|
533 wp.updates.decrementCount( message.upgradeType ); |
|
534 break; |
|
535 case 'updatePlugin' : |
|
536 tb_remove(); |
|
537 if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) { |
|
538 // Return the user to the input box of the plugin's table row after closing the modal. |
|
539 $( '#' + message.slug ).find( '.check-column input' ).focus(); |
|
540 // trigger the update |
|
541 $( '.plugin-update-tr[data-slug="' + message.slug + '"]' ).find( '.update-link' ).trigger( 'click' ); |
|
542 } else if ( 'plugin-install' === pagenow ) { |
|
543 $( '.plugin-card-' + message.slug ).find( 'h4 a' ).focus(); |
|
544 $( '.plugin-card-' + message.slug ).find( '[data-slug="' + message.slug + '"]' ).trigger( 'click' ); |
|
545 } |
|
546 break; |
|
547 } |
|
548 |
|
549 } ); |
|
550 |
|
551 $( window ).on( 'beforeunload', wp.updates.beforeunload ); |
|
552 |
|
553 })( jQuery, window.wp, window.pagenow, window.ajaxurl ); |
|