summaryrefslogtreecommitdiff
path: root/www/crm/wp-includes/js/media-views.js
diff options
context:
space:
mode:
Diffstat (limited to 'www/crm/wp-includes/js/media-views.js')
-rw-r--r--www/crm/wp-includes/js/media-views.js163
1 files changed, 141 insertions, 22 deletions
diff --git a/www/crm/wp-includes/js/media-views.js b/www/crm/wp-includes/js/media-views.js
index 9563b053..a7cdbdd6 100644
--- a/www/crm/wp-includes/js/media-views.js
+++ b/www/crm/wp-includes/js/media-views.js
@@ -4318,9 +4318,10 @@ Modal = wp.media.View.extend(/** @lends wp.media.view.Modal.prototype */{
initialize: function() {
_.defaults( this.options, {
- container: document.body,
- title: '',
- propagate: true
+ container: document.body,
+ title: '',
+ propagate: true,
+ hasCloseButton: true
});
this.focusManager = new wp.media.view.FocusManager({
@@ -4332,7 +4333,8 @@ Modal = wp.media.View.extend(/** @lends wp.media.view.Modal.prototype */{
*/
prepare: function() {
return {
- title: this.options.title
+ title: this.options.title,
+ hasCloseButton: this.options.hasCloseButton
};
},
@@ -4407,6 +4409,9 @@ Modal = wp.media.View.extend(/** @lends wp.media.view.Modal.prototype */{
// Set initial focus on the content instead of this view element, to avoid page scrolling.
this.$( '.media-modal' ).focus();
+ // Hide the page content from assistive technologies.
+ this.focusManager.setAriaHiddenOnBodyChildren( $el );
+
return this.propagate('open');
},
@@ -4425,6 +4430,12 @@ Modal = wp.media.View.extend(/** @lends wp.media.view.Modal.prototype */{
// Hide modal and remove restricted media modal tab focus once it's closed
this.$el.hide().undelegate( 'keydown' );
+ /*
+ * Make visible again to assistive technologies all body children that
+ * have been made hidden when the modal opened.
+ */
+ this.focusManager.removeAriaHiddenFromBodyChildren();
+
// Put focus back in useful location once modal is closed.
if ( null !== this.clickedOpenerEl ) {
this.clickedOpenerEl.focus();
@@ -4516,11 +4527,24 @@ var FocusManager = wp.media.View.extend(/** @lends wp.media.view.FocusManager.pr
'keydown': 'constrainTabbing'
},
- focus: function() { // Reset focus on first left menu item
- this.$('.media-menu-item').first().focus();
+ /**
+ * Moves focus to the first visible menu item in the modal.
+ *
+ * @since 3.5.0
+ *
+ * @returns {void}
+ */
+ focus: function() {
+ this.$( '.media-menu-item' ).filter( ':visible' ).first().focus();
},
/**
- * @param {Object} event
+ * Constrains navigation with the Tab key within the media view element.
+ *
+ * @since 4.0.0
+ *
+ * @param {Object} event A keydown jQuery event.
+ *
+ * @returns {void}
*/
constrainTabbing: function( event ) {
var tabbables;
@@ -4541,8 +4565,107 @@ var FocusManager = wp.media.View.extend(/** @lends wp.media.view.FocusManager.pr
tabbables.last().focus();
return false;
}
- }
+ },
+
+ /**
+ * Hides from assistive technologies all the body children except the
+ * provided element and other elements that should not be hidden.
+ *
+ * The reason why we use `aria-hidden` is that `aria-modal="true"` is buggy
+ * in Safari 11.1 and support is spotty in other browsers. In the future we
+ * should consider to remove this helper function and only use `aria-modal="true"`.
+ *
+ * @since 5.2.3
+ *
+ * @param {object} visibleElement The jQuery object representing the element that should not be hidden.
+ *
+ * @returns {void}
+ */
+ setAriaHiddenOnBodyChildren: function( visibleElement ) {
+ var bodyChildren,
+ self = this;
+
+ if ( this.isBodyAriaHidden ) {
+ return;
+ }
+ // Get all the body children.
+ bodyChildren = document.body.children;
+
+ // Loop through the body children and hide the ones that should be hidden.
+ _.each( bodyChildren, function( element ) {
+ // Don't hide the modal element.
+ if ( element === visibleElement[0] ) {
+ return;
+ }
+
+ // Determine the body children to hide.
+ if ( self.elementShouldBeHidden( element ) ) {
+ element.setAttribute( 'aria-hidden', 'true' );
+ // Store the hidden elements.
+ self.ariaHiddenElements.push( element );
+ }
+ } );
+
+ this.isBodyAriaHidden = true;
+ },
+
+ /**
+ * Makes visible again to assistive technologies all body children
+ * previously hidden and stored in this.ariaHiddenElements.
+ *
+ * @since 5.2.3
+ *
+ * @returns {void}
+ */
+ removeAriaHiddenFromBodyChildren: function() {
+ _.each( this.ariaHiddenElements, function( element ) {
+ element.removeAttribute( 'aria-hidden' );
+ } );
+
+ this.ariaHiddenElements = [];
+ this.isBodyAriaHidden = false;
+ },
+
+ /**
+ * Determines if the passed element should not be hidden from assistive technologies.
+ *
+ * @since 5.2.3
+ *
+ * @param {object} element The DOM element that should be checked.
+ *
+ * @returns {boolean} Whether the element should not be hidden from assistive technologies.
+ */
+ elementShouldBeHidden: function( element ) {
+ var role = element.getAttribute( 'role' ),
+ liveRegionsRoles = [ 'alert', 'status', 'log', 'marquee', 'timer' ];
+
+ /*
+ * Don't hide scripts, elements that already have `aria-hidden`, and
+ * ARIA live regions.
+ */
+ return ! (
+ element.tagName === 'SCRIPT' ||
+ element.hasAttribute( 'aria-hidden' ) ||
+ element.hasAttribute( 'aria-live' ) ||
+ liveRegionsRoles.indexOf( role ) !== -1
+ );
+ },
+
+ /**
+ * Whether the body children are hidden from assistive technologies.
+ *
+ * @since 5.2.3
+ */
+ isBodyAriaHidden: false,
+
+ /**
+ * Stores an array of DOM elements that should be hidden from assistive
+ * technologies, for example when the media modal dialog opens.
+ *
+ * @since 5.2.3
+ */
+ ariaHiddenElements: []
});
module.exports = FocusManager;
@@ -5165,18 +5288,15 @@ UploaderStatus = View.extend(/** @lends wp.media.view.UploaderStatus.prototype *
}), { at: 0 });
},
- /**
- * @param {Object} event
- */
- dismiss: function( event ) {
+ dismiss: function() {
var errors = this.views.get('.upload-errors');
- event.preventDefault();
-
if ( errors ) {
_.invoke( errors, 'remove' );
}
wp.Uploader.errors.reset();
+ // Keep focus within the modal after the dismiss button gets removed from the DOM.
+ this.controller.modal.focusManager.focus();
}
});
@@ -7685,7 +7805,7 @@ AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.pro
disabled: true,
text: mediaTrash ? l10n.trashSelected : l10n.deletePermanently,
controller: this.controller,
- priority: -60,
+ priority: -80,
click: function() {
var changed = [], removed = [],
selection = this.controller.state().get( 'selection' ),
@@ -7741,7 +7861,7 @@ AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.pro
if ( mediaTrash ) {
this.toolbar.set( 'deleteSelectedPermanentlyButton', new wp.media.view.DeleteSelectedPermanentlyButton({
filters: Filters,
- style: 'primary',
+ style: 'link button-link-delete',
disabled: true,
text: l10n.deletePermanently,
controller: this.controller,
@@ -8459,12 +8579,11 @@ Details = Attachment.extend(/** @lends wp.media.view.Attachment.Details.prototyp
className: 'attachment-details',
template: wp.template('attachment-details'),
- attributes: function() {
- return {
- 'tabIndex': 0,
- 'data-id': this.model.get( 'id' )
- };
- },
+ /*
+ * Reset all the attributes inherited from Attachment including role=checkbox,
+ * tabindex, etc., as they are inappropriate for this view. See #47458 and [30483] / #30390.
+ */
+ attributes: {},
events: {
'change [data-setting]': 'updateSetting',