diff --git a/src/wp-admin/js/updates.js b/src/wp-admin/js/updates.js
index dd93e7f433..08b43c2c3c 100644
--- a/src/wp-admin/js/updates.js
+++ b/src/wp-admin/js/updates.js
@@ -78,6 +78,15 @@ window.wp = window.wp || {};
*/
wp.updates.updateQueue = [];
+ /**
+ * Store a jQuery reference to return focus to when exiting the request credentials modal.
+ *
+ * @since 4.2.0
+ *
+ * @var jQuery object
+ */
+ wp.updates.$elToReturnFocusToFromCredentialsModal = null;
+
/**
* Decrement update counts throughout the various menus.
*
@@ -144,6 +153,10 @@ window.wp = window.wp || {};
}
$message.addClass( 'updating-message' );
+ if ( $message.html() !== wp.updates.l10n.updating ){
+ $message.data( 'originaltext', $message.html() );
+ }
+
$message.text( wp.updates.l10n.updating );
wp.a11y.speak( wp.updates.l10n.updatingMsg );
@@ -247,12 +260,12 @@ window.wp = window.wp || {};
* @since 4.2.0
*/
wp.updates.showErrorInCredentialsForm = function( message ) {
- var $notificationDialog = $( '.notification-dialog' );
+ var $modal = $( '.notification-dialog' );
- // Remove any existing error
- $notificationDialog.find( '.error' ).remove();
+ // Remove any existing error.
+ $modal.find( '.error' ).remove();
- $notificationDialog.find( 'h3' ).after( '
' + message + '
' );
+ $modal.find( 'h3' ).after( '
' + message + '
' );
};
/**
@@ -291,18 +304,105 @@ window.wp = window.wp || {};
/**
- * Request the users filesystem credentials if we don't have them already
+ * Request the users filesystem credentials if we don't have them already.
*
* @since 4.2.0
*/
- wp.updates.requestFilesystemCredentials = function() {
+ wp.updates.requestFilesystemCredentials = function( event ) {
if ( wp.updates.updateDoneSuccessfully === false ) {
+ /*
+ * For the plugin install screen, return the focus to the install button
+ * after exiting the credentials request modal.
+ */
+ if ( 'plugin-install' === pagenow && event ) {
+ wp.updates.$elToReturnFocusToFromCredentialsModal = $( event.target );
+ }
+
wp.updates.updateLock = true;
- $( 'body' ).addClass( 'modal-open' );
- $( '#request-filesystem-credentials-dialog' ).show();
+
+ wp.updates.requestForCredentialsModalOpen();
}
};
+ /**
+ * Keydown handler for the request for credentials modal.
+ *
+ * Close the modal when the escape key is pressed.
+ * Constrain keyboard navigation to inside the modal.
+ *
+ * @since 4.2.0
+ */
+ wp.updates.keydown = function( event ) {
+ if ( 27 === event.keyCode ) {
+ wp.updates.requestForCredentialsModalCancel();
+ } else if ( 9 === event.keyCode ) {
+ // #upgrade button must always be the last focusable element in the dialog.
+ if ( event.target.id === 'upgrade' && ! event.shiftKey ) {
+ $( '#hostname' ).focus();
+ event.preventDefault();
+ } else if ( event.target.id === 'hostname' && event.shiftKey ) {
+ $( '#upgrade' ).focus();
+ event.preventDefault();
+ }
+ }
+ };
+
+ /**
+ * Open the request for credentials modal.
+ *
+ * @since 4.2.0
+ */
+ wp.updates.requestForCredentialsModalOpen = function() {
+ var $modal = $( '#request-filesystem-credentials-dialog' );
+ $( 'body' ).addClass( 'modal-open' );
+ $modal.show();
+
+ $modal.find( '#hostname' ).focus();
+ $modal.keydown( wp.updates.keydown );
+ };
+
+ /**
+ * Close the request for credentials modal.
+ *
+ * @since 4.2.0
+ */
+ wp.updates.requestForCredentialsModalClose = function() {
+ $( '#request-filesystem-credentials-dialog' ).hide();
+ $( 'body' ).removeClass( 'modal-open' );
+ wp.updates.$elToReturnFocusToFromCredentialsModal.focus();
+ };
+
+ /**
+ * The steps that need to happen when the modal is canceled out
+ *
+ * @since 4.2.0
+ */
+ wp.updates.requestForCredentialsModalCancel = function() {
+ // no updateLock and no updateQueue means we already have cleared things up
+ var slug, $message;
+
+ if( wp.updates.updateLock === false && wp.updates.updateQueue.length === 0 ){
+ return;
+ }
+
+ slug = wp.updates.updateQueue[0].data.slug,
+
+ // remove the lock, and clear the queue
+ wp.updates.updateLock = false;
+ wp.updates.updateQueue = [];
+
+ wp.updates.requestForCredentialsModalClose();
+ if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
+ $message = $( '[data-slug="' + slug + '"]' ).next().find( '.update-message' );
+ } else if ( 'plugin-install' === pagenow ) {
+ $message = $( '.plugin-card-' + slug ).find( '.update-now' );
+ }
+
+ $message.removeClass( 'updating-message' );
+ $message.html( $message.data( 'originaltext' ) );
+ wp.a11y.speak( wp.updates.l10n.updateCancel );
+ };
+
$( document ).ready( function() {
/*
* Check whether a user needs to submit filesystem credentials based on whether
@@ -322,8 +422,7 @@ window.wp = window.wp || {};
wp.updates.filesystemCredentials.ssh.publicKey = $('#public_key').val();
wp.updates.filesystemCredentials.ssh.privateKey = $('#private_key').val();
- $( '#request-filesystem-credentials-dialog' ).hide();
- $( 'body' ).removeClass( 'modal-open' );
+ wp.updates.requestForCredentialsModalClose();
// Unlock and invoke the queue.
wp.updates.updateLock = false;
@@ -332,14 +431,21 @@ window.wp = window.wp || {};
return false;
});
+ // Close the request credentials modal when
+ $( '#request-filesystem-credentials-dialog [data-js-action="close"], .notification-dialog-background' ).on( 'click', function() {
+ wp.updates.requestForCredentialsModalCancel();
+ });
+
// Click handler for plugin updates in List Table view.
- $( '.plugin-update-tr .update-link' ).on( 'click', function( e ) {
+ $( '.plugin-update-tr' ).on( 'click', '.update-link', function( e ) {
e.preventDefault();
if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.updateLock ) {
- wp.updates.requestFilesystemCredentials();
+ wp.updates.requestFilesystemCredentials( e );
}
- var $row = $( e.target ).parents( '.plugin-update-tr' );
- wp.updates.updatePlugin( $row.data( 'plugin' ), $row.data( 'slug' ) );
+ var updateRow = $( e.target ).parents( '.plugin-update-tr' );
+ // Return the user to the input box of the plugin's table row after closing the modal.
+ wp.updates.$elToReturnFocusToFromCredentialsModal = $( '#' + updateRow.data( 'slug' ) ).find( '.check-column input' );
+ wp.updates.updatePlugin( updateRow.data( 'plugin' ), updateRow.data( 'slug' ) );
} );
$( '#bulk-action-form' ).on( 'submit', function( e ) {
@@ -360,9 +466,14 @@ window.wp = window.wp || {};
}
} );
- $( '.plugin-card .update-now' ).on( 'click', function( e ) {
+ $( '.plugin-card' ).on( 'click', '.update-now', function( e ) {
e.preventDefault();
var $button = $( e.target );
+
+ if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.updateLock ) {
+ wp.updates.requestFilesystemCredentials( e );
+ }
+
wp.updates.updatePlugin( $button.data( 'plugin' ), $button.data( 'slug' ) );
} );
diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php
index 90ef7996ca..ebb072e3ba 100644
--- a/src/wp-includes/script-loader.php
+++ b/src/wp-includes/script-loader.php
@@ -529,6 +529,7 @@ function wp_default_scripts( &$scripts ) {
'updateFailed' => __( 'Update failed.' ),
'updatingMsg' => __( 'Updating... please wait.' ),
'updatedMsg' => __( 'Update completed successfully.' ),
+ 'updateCancel' => __( 'Update canceled' ),
)
) );