]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-admin/js/updates.js
WordPress 4.2.3-scripts
[autoinstalls/wordpress.git] / wp-admin / js / updates.js
1 /* global tb_remove */
2 window.wp = window.wp || {};
3
4 (function( $, wp, pagenow ) {
5         wp.updates = {};
6
7         /**
8          * User nonce for ajax calls.
9          *
10          * @since 4.2.0
11          *
12          * @var string
13          */
14         wp.updates.ajaxNonce = window._wpUpdatesSettings.ajax_nonce;
15
16         /**
17          * Localized strings.
18          *
19          * @since 4.2.0
20          *
21          * @var object
22          */
23         wp.updates.l10n = window._wpUpdatesSettings.l10n;
24
25         /**
26          * Whether filesystem credentials need to be requested from the user.
27          *
28          * @since 4.2.0
29          *
30          * @var bool
31          */
32         wp.updates.shouldRequestFilesystemCredentials = null;
33
34         /**
35          * Filesystem credentials to be packaged along with the request.
36          *
37          * @since 4.2.0
38          *
39          * @var object
40          */
41         wp.updates.filesystemCredentials = {
42                 ftp: {
43                         host: null,
44                         username: null,
45                         password: null,
46                         connectionType: null
47                 },
48                 ssh: {
49                         publicKey: null,
50                         privateKey: null
51                 }
52         };
53
54         /**
55          * Flag if we're waiting for an update to complete.
56          *
57          * @since 4.2.0
58          *
59          * @var bool
60          */
61         wp.updates.updateLock = false;
62
63         /**
64          * * Flag if we've done an update successfully.
65          *
66          * @since 4.2.0
67          *
68          * @var bool
69          */
70         wp.updates.updateDoneSuccessfully = false;
71
72         /**
73          * 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.
75          *
76          * @since 4.2.0
77          *
78          * @var array
79          */
80         wp.updates.updateQueue = [];
81
82         /**
83          * Store a jQuery reference to return focus to when exiting the request credentials modal.
84          *
85          * @since 4.2.0
86          *
87          * @var jQuery object
88          */
89         wp.updates.$elToReturnFocusToFromCredentialsModal = null;
90
91         /**
92          * Decrement update counts throughout the various menus.
93          *
94          * @since 3.9.0
95          *
96          * @param {string} updateType
97          */
98         wp.updates.decrementCount = function( upgradeType ) {
99                 var count,
100                         pluginCount,
101                         $adminBarUpdateCount = $( '#wp-admin-bar-updates .ab-label' ),
102                         $dashboardNavMenuUpdateCount = $( 'a[href="update-core.php"] .update-plugins' ),
103                         $pluginsMenuItem = $( '#menu-plugins' );
104
105
106                 count = $adminBarUpdateCount.text();
107                 count = parseInt( count, 10 ) - 1;
108                 if ( count < 0 || isNaN( count ) ) {
109                         return;
110                 }
111                 $( '#wp-admin-bar-updates .ab-item' ).removeAttr( 'title' );
112                 $adminBarUpdateCount.text( count );
113
114
115                 $dashboardNavMenuUpdateCount.each( function( index, elem ) {
116                         elem.className = elem.className.replace( /count-\d+/, 'count-' + count );
117                 } );
118                 $dashboardNavMenuUpdateCount.removeAttr( 'title' );
119                 $dashboardNavMenuUpdateCount.find( '.update-count' ).text( count );
120
121                 if ( 'plugin' === upgradeType ) {
122                         pluginCount = $pluginsMenuItem.find( '.plugin-count' ).eq(0).text();
123                         pluginCount = parseInt( pluginCount, 10 ) - 1;
124                         if ( pluginCount < 0 || isNaN( pluginCount ) ) {
125                                 return;
126                         }
127                         $pluginsMenuItem.find( '.plugin-count' ).text( pluginCount );
128                         $pluginsMenuItem.find( '.update-plugins' ).each( function( index, elem ) {
129                                 elem.className = elem.className.replace( /count-\d+/, 'count-' + pluginCount );
130                         } );
131
132                         if (pluginCount > 0 ) {
133                                 $( '.subsubsub .upgrade .count' ).text( '(' + pluginCount + ')' );
134                         } else {
135                                 $( '.subsubsub .upgrade' ).remove();
136                         }
137                 }
138         };
139
140         /**
141          * Send an Ajax request to the server to update a plugin.
142          *
143          * @since 4.2.0
144          *
145          * @param {string} plugin
146          * @param {string} slug
147          */
148         wp.updates.updatePlugin = function( plugin, slug ) {
149                 var $message, name;
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,
181                         plugin:          plugin,
182                         slug:            slug,
183                         username:        wp.updates.filesystemCredentials.ftp.username,
184                         password:        wp.updates.filesystemCredentials.ftp.password,
185                         hostname:        wp.updates.filesystemCredentials.ftp.hostname,
186                         connection_type: wp.updates.filesystemCredentials.ftp.connectionType,
187                         public_key:      wp.updates.filesystemCredentials.ssh.publicKey,
188                         private_key:     wp.updates.filesystemCredentials.ssh.privateKey
189                 };
190
191                 wp.ajax.post( 'update-plugin', data )
192                         .done( wp.updates.updateSuccess )
193                         .fail( wp.updates.updateError );
194         };
195
196         /**
197          * On a successful plugin update, update the UI with the result.
198          *
199          * @since 4.2.0
200          *
201          * @param {object} response
202          */
203         wp.updates.updateSuccess = function( response ) {
204                 var $updateMessage, name, $pluginRow, newText;
205                 if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
206                         $pluginRow = $( '[data-slug="' + response.slug + '"]' ).first();
207                         $updateMessage = $pluginRow.next().find( '.update-message' );
208                         $pluginRow.addClass( 'updated' ).removeClass( 'update' );
209
210                         // Update the version number in the row.
211                         newText = $pluginRow.find('.plugin-version-author-uri').html().replace( response.oldVersion, response.newVersion );
212                         $pluginRow.find('.plugin-version-author-uri').html( newText );
213
214                         // Add updated class to update message parent tr
215                         $pluginRow.next().addClass( 'updated' );
216                 } else if ( 'plugin-install' === pagenow ) {
217                         $updateMessage = $( '.plugin-card-' + response.slug ).find( '.update-now' );
218                         $updateMessage.addClass( 'button-disabled' );
219                         name = $updateMessage.data( 'name' );
220                         $updateMessage.attr( 'aria-label', wp.updates.l10n.updatedLabel.replace( '%s', name ) );
221                 }
222
223                 $updateMessage.removeClass( 'updating-message' ).addClass( 'updated-message' );
224                 $updateMessage.text( wp.updates.l10n.updated );
225                 wp.a11y.speak( wp.updates.l10n.updatedMsg );
226
227                 wp.updates.decrementCount( 'plugin' );
228
229                 wp.updates.updateDoneSuccessfully = true;
230
231                 /*
232                  * The lock can be released since the update was successful,
233                  * and any other updates can commence.
234                  */
235                 wp.updates.updateLock = false;
236
237                 $(document).trigger( 'wp-plugin-update-success', response );
238
239                 wp.updates.queueChecker();
240         };
241
242
243         /**
244          * On a plugin update error, update the UI appropriately.
245          *
246          * @since 4.2.0
247          *
248          * @param {object} response
249          */
250         wp.updates.updateError = function( response ) {
251                 var $message, name;
252                 wp.updates.updateDoneSuccessfully = false;
253                 if ( response.errorCode && response.errorCode == 'unable_to_connect_to_filesystem' && wp.updates.shouldRequestFilesystemCredentials ) {
254                         wp.updates.credentialError( response, 'update-plugin' );
255                         return;
256                 }
257                 if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
258                         $message = $( '[data-slug="' + response.slug + '"]' ).next().find( '.update-message' );
259                 } else if ( 'plugin-install' === pagenow ) {
260                         $message = $( '.plugin-card-' + response.slug ).find( '.update-now' );
261
262                         name = $message.data( 'name' );
263                         $message.attr( 'aria-label', wp.updates.l10n.updateFailedLabel.replace( '%s', name ) );
264                 }
265                 $message.removeClass( 'updating-message' );
266                 $message.html( wp.updates.l10n.updateFailed + ': ' + response.error );
267                 wp.a11y.speak( wp.updates.l10n.updateFailed );
268
269                 /*
270                  * The lock can be released since this failure was
271                  * after the credentials form.
272                  */
273                 wp.updates.updateLock = false;
274
275                 $(document).trigger( 'wp-plugin-update-error', response );
276
277                 wp.updates.queueChecker();
278         };
279
280         /**
281          * Show an error message in the request for credentials form.
282          *
283          * @param {string} message
284          * @since 4.2.0
285          */
286         wp.updates.showErrorInCredentialsForm = function( message ) {
287                 var $modal = $( '.notification-dialog' );
288
289                 // Remove any existing error.
290                 $modal.find( '.error' ).remove();
291
292                 $modal.find( 'h3' ).after( '<div class="error">' + message + '</div>' );
293         };
294
295         /**
296          * Events that need to happen when there is a credential error
297          *
298          * @since 4.2.0
299          */
300         wp.updates.credentialError = function( response, type ) {
301                 wp.updates.updateQueue.push( {
302                         'type': type,
303                         'data': {
304                                 // Not cool that we're depending on response for this data.
305                                 // This would feel more whole in a view all tied together.
306                                 plugin: response.plugin,
307                                 slug: response.slug
308                         }
309                 } );
310                 wp.updates.showErrorInCredentialsForm( response.error );
311                 wp.updates.requestFilesystemCredentials();
312         };
313
314         /**
315          * If an update job has been placed in the queue, queueChecker pulls it out and runs it.
316          *
317          * @since 4.2.0
318          */
319         wp.updates.queueChecker = function() {
320                 if ( wp.updates.updateLock || wp.updates.updateQueue.length <= 0 ) {
321                         return;
322                 }
323
324                 var job = wp.updates.updateQueue.shift();
325
326                 wp.updates.updatePlugin( job.data.plugin, job.data.slug );
327         };
328
329
330         /**
331          * Request the users filesystem credentials if we don't have them already.
332          *
333          * @since 4.2.0
334          */
335         wp.updates.requestFilesystemCredentials = function( event ) {
336                 if ( wp.updates.updateDoneSuccessfully === false ) {
337                         /*
338                          * For the plugin install screen, return the focus to the install button
339                          * after exiting the credentials request modal.
340                          */
341                         if ( 'plugin-install' === pagenow && event ) {
342                                 wp.updates.$elToReturnFocusToFromCredentialsModal = $( event.target );
343                         }
344
345                         wp.updates.updateLock = true;
346
347                         wp.updates.requestForCredentialsModalOpen();
348                 }
349         };
350
351         /**
352          * Keydown handler for the request for credentials modal.
353          *
354          * Close the modal when the escape key is pressed.
355          * Constrain keyboard navigation to inside the modal.
356          *
357          * @since 4.2.0
358          */
359         wp.updates.keydown = function( event ) {
360                 if ( 27 === event.keyCode ) {
361                         wp.updates.requestForCredentialsModalCancel();
362                 } else if ( 9 === event.keyCode ) {
363                         // #upgrade button must always be the last focusable element in the dialog.
364                         if ( event.target.id === 'upgrade' && ! event.shiftKey ) {
365                                 $( '#hostname' ).focus();
366                                 event.preventDefault();
367                         } else if ( event.target.id === 'hostname' && event.shiftKey ) {
368                                 $( '#upgrade' ).focus();
369                                 event.preventDefault();
370                         }
371                 }
372         };
373
374         /**
375          * Open the request for credentials modal.
376          *
377          * @since 4.2.0
378          */
379         wp.updates.requestForCredentialsModalOpen = function() {
380                 var $modal = $( '#request-filesystem-credentials-dialog' );
381                 $( 'body' ).addClass( 'modal-open' );
382                 $modal.show();
383
384                 $modal.find( 'input:enabled:first' ).focus();
385                 $modal.keydown( wp.updates.keydown );
386         };
387
388         /**
389          * Close the request for credentials modal.
390          *
391          * @since 4.2.0
392          */
393         wp.updates.requestForCredentialsModalClose = function() {
394                 $( '#request-filesystem-credentials-dialog' ).hide();
395                 $( 'body' ).removeClass( 'modal-open' );
396                 wp.updates.$elToReturnFocusToFromCredentialsModal.focus();
397         };
398
399         /**
400          * The steps that need to happen when the modal is canceled out
401          *
402          * @since 4.2.0
403          */
404         wp.updates.requestForCredentialsModalCancel = function() {
405                 // no updateLock and no updateQueue means we already have cleared things up
406                 var slug, $message;
407
408                 if( wp.updates.updateLock === false && wp.updates.updateQueue.length === 0 ){
409                         return;
410                 }
411
412                 slug = wp.updates.updateQueue[0].data.slug,
413
414                 // remove the lock, and clear the queue
415                 wp.updates.updateLock = false;
416                 wp.updates.updateQueue = [];
417
418                 wp.updates.requestForCredentialsModalClose();
419                 if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
420                         $message = $( '[data-slug="' + slug + '"]' ).next().find( '.update-message' );
421                 } else if ( 'plugin-install' === pagenow ) {
422                         $message = $( '.plugin-card-' + slug ).find( '.update-now' );
423                 }
424
425                 $message.removeClass( 'updating-message' );
426                 $message.html( $message.data( 'originaltext' ) );
427                 wp.a11y.speak( wp.updates.l10n.updateCancel );
428         };
429         /**
430          * Potentially add an AYS to a user attempting to leave the page
431          *
432          * If an update is on-going and a user attempts to leave the page,
433          * open an "Are you sure?" alert.
434          *
435          * @since 4.2.0
436          */
437
438         wp.updates.beforeunload = function() {
439                 if ( wp.updates.updateLock ) {
440                         return wp.updates.l10n.beforeunload;
441                 }
442         };
443
444
445         $( document ).ready( function() {
446                 /*
447                  * Check whether a user needs to submit filesystem credentials based on whether
448                  * the form was output on the page server-side.
449                  *
450                  * @see {wp_print_request_filesystem_credentials_modal() in PHP}
451                  */
452                 wp.updates.shouldRequestFilesystemCredentials = ( $( '#request-filesystem-credentials-dialog' ).length <= 0 ) ? false : true;
453
454                 // File system credentials form submit noop-er / handler.
455                 $( '#request-filesystem-credentials-dialog form' ).on( 'submit', function() {
456                         // Persist the credentials input by the user for the duration of the page load.
457                         wp.updates.filesystemCredentials.ftp.hostname = $('#hostname').val();
458                         wp.updates.filesystemCredentials.ftp.username = $('#username').val();
459                         wp.updates.filesystemCredentials.ftp.password = $('#password').val();
460                         wp.updates.filesystemCredentials.ftp.connectionType = $('input[name="connection_type"]:checked').val();
461                         wp.updates.filesystemCredentials.ssh.publicKey = $('#public_key').val();
462                         wp.updates.filesystemCredentials.ssh.privateKey = $('#private_key').val();
463
464                         wp.updates.requestForCredentialsModalClose();
465
466                         // Unlock and invoke the queue.
467                         wp.updates.updateLock = false;
468                         wp.updates.queueChecker();
469
470                         return false;
471                 });
472
473                 // Close the request credentials modal when
474                 $( '#request-filesystem-credentials-dialog [data-js-action="close"], .notification-dialog-background' ).on( 'click', function() {
475                         wp.updates.requestForCredentialsModalCancel();
476                 });
477
478                 // Hide SSH fields when not selected
479                 $( '#request-filesystem-credentials-dialog input[name="connection_type"]' ).on( 'change', function() {
480                         $( this ).parents( 'form' ).find( '#private_key, #public_key' ).parents( 'label' ).toggle( ( 'ssh' == $( this ).val() ) );
481                 }).change();
482
483                 // Click handler for plugin updates in List Table view.
484                 $( '.plugin-update-tr' ).on( 'click', '.update-link', function( e ) {
485                         e.preventDefault();
486                         if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.updateLock ) {
487                                 wp.updates.requestFilesystemCredentials( e );
488                         }
489                         var updateRow = $( e.target ).parents( '.plugin-update-tr' );
490                         // Return the user to the input box of the plugin's table row after closing the modal.
491                         wp.updates.$elToReturnFocusToFromCredentialsModal = $( '#' + updateRow.data( 'slug' ) ).find( '.check-column input' );
492                         wp.updates.updatePlugin( updateRow.data( 'plugin' ), updateRow.data( 'slug' ) );
493                 } );
494
495                 $( '.plugin-card' ).on( 'click', '.update-now', function( e ) {
496                         e.preventDefault();
497                         var $button = $( e.target );
498
499                         if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.updateLock ) {
500                                 wp.updates.requestFilesystemCredentials( e );
501                         }
502
503                         wp.updates.updatePlugin( $button.data( 'plugin' ), $button.data( 'slug' ) );
504                 } );
505
506                 $( '#plugin_update_from_iframe' ).on( 'click' , function( e ) {
507                         var target,     data;
508
509                         target = window.parent == window ? null : window.parent,
510                         $.support.postMessage = !! window.postMessage;
511
512                         if ( $.support.postMessage === false || target === null || window.parent.location.pathname.indexOf( 'update-core.php' ) !== -1 )
513                                 return;
514
515                         e.preventDefault();
516
517                         data = {
518                                 'action' : 'updatePlugin',
519                                 'slug'   : $(this).data('slug')
520                         };
521
522                         target.postMessage( JSON.stringify( data ), window.location.origin );
523                 });
524
525         } );
526
527         $( window ).on( 'message', function( e ) {
528                 var event = e.originalEvent,
529                         message,
530                         loc = document.location,
531                         expectedOrigin = loc.protocol + '//' + loc.hostname;
532
533                 if ( event.origin !== expectedOrigin ) {
534                         return;
535                 }
536
537                 message = $.parseJSON( event.data );
538
539                 if ( typeof message.action === 'undefined' ) {
540                         return;
541                 }
542
543                 switch (message.action){
544                         case 'decrementUpdateCount' :
545                                 wp.updates.decrementCount( message.upgradeType );
546                                 break;
547                         case 'updatePlugin' :
548                                 tb_remove();
549                                 if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
550                                         // Return the user to the input box of the plugin's table row after closing the modal.
551                                         $( '#' + message.slug ).find( '.check-column input' ).focus();
552                                         // trigger the update
553                                         $( '.plugin-update-tr[data-slug="' + message.slug + '"]' ).find( '.update-link' ).trigger( 'click' );
554                                 } else if ( 'plugin-install' === pagenow ) {
555                                         $( '.plugin-card-' + message.slug ).find( 'h4 a' ).focus();
556                                         $( '.plugin-card-' + message.slug ).find( '[data-slug="' + message.slug + '"]' ).trigger( 'click' );
557                                 }
558                                 break;
559                 }
560
561         } );
562
563         $( window ).on( 'beforeunload', wp.updates.beforeunload );
564
565 })( jQuery, window.wp, window.pagenow, window.ajaxurl );