diff --git a/core/misc/tabbingmanager.js b/core/misc/tabbingmanager.js index 0507120..d26a410 100644 --- a/core/misc/tabbingmanager.js +++ b/core/misc/tabbingmanager.js @@ -35,7 +35,10 @@ $.extend(TabbingManager.prototype, { * * @return TabbingContext */ - constrain: function (elements) { + constrain: function (elements, expand) { + if (typeof expand === 'undefined') { + expand = true; + } // Deactivate all tabbingContexts to prepare for the new constraint. A // tabbingContext instance will only be reactivated if the stack is unwound // to it in the _unwindStack() method. @@ -45,7 +48,16 @@ $.extend(TabbingManager.prototype, { // The "active tabbing set" are the elements tabbing should be constrained // to. - var $elements = $(elements).find(':tabbable').addBack(':tabbable'); + var $elements; + // Find tabbable elements within the set of supplied elements if expansion + // is requested. + if (expand) { + $elements = $(elements).find(':tabbable').addBack(':tabbable'); + } + // Assume that a list of tabbable elements is provided. + else { + $elements = $(elements); + } var tabbingContext = new TabbingContext({ // The level is the current height of the stack before this new diff --git a/core/modules/edit/css/edit.theme.css b/core/modules/edit/css/edit.theme.css index bf5d0eb..86c5fd1 100644 --- a/core/modules/edit/css/edit.theme.css +++ b/core/modules/edit/css/edit.theme.css @@ -10,6 +10,10 @@ .edit-field .edit-editable { box-shadow: 0 0 0 2px #74b7ff; } +.edit-field.edit-editable:focus, +.edit-field .edit-editable:focus { + box-shadow: 0 0 0 4px #74b7ff; +} /** * Highlighted (hovered) editable. diff --git a/core/modules/edit/edit.module b/core/modules/edit/edit.module index 3eaabcc..31ff007 100644 --- a/core/modules/edit/edit.module +++ b/core/modules/edit/edit.module @@ -74,6 +74,7 @@ function edit_library_info() { $path . '/js/views/ContextualLinkView.js' => $options, $path . '/js/views/FieldToolbarView.js' => $options, $path . '/js/views/EditorView.js' => $options, + $path . '/js/views/FieldAuralView.js' => $options, // Other. $path . '/js/theme.js' => $options, ), @@ -90,6 +91,7 @@ function edit_library_info() { array('system', 'jquery.ui.position'), array('system', 'drupal'), array('system', 'drupal.displace'), + array('system', 'drupal.tabbingmanager'), array('system', 'drupal.form'), array('system', 'drupal.ajax'), array('system', 'drupal.debounce'), diff --git a/core/modules/edit/js/editors/formEditor.js b/core/modules/edit/js/editors/formEditor.js index 7eda4e1..59a3d0d 100644 --- a/core/modules/edit/js/editors/formEditor.js +++ b/core/modules/edit/js/editors/formEditor.js @@ -71,12 +71,21 @@ Drupal.edit.editors.form = Drupal.edit.EditorView.extend({ // Render form container. var $formContainer = this.$formContainer = $(Drupal.theme('editFormContainer', { id: id, + 'aria-label': Drupal.t('Edit form for @aria', {'@aria': fieldModel.get('metadata').aria}), loadingMsg: Drupal.t('Loading…')} )); + // Add this form's id to the list of elements that the entity owns. + var $entity = $(this.fieldModel.get('entity').get('el')); + var owns = $entity.attr('aria-owns'); + if (owns) { + owns = owns.split(' '); + owns.push(id); + $entity.attr('aria-owns', owns.join(' ')); + } + // Mark up the form with state classes. $formContainer .find('.edit-form') - .addClass('edit-editable edit-highlighted edit-editing') - .attr('role', 'dialog'); + .addClass('edit-editable edit-highlighted edit-editing'); // Insert form container in DOM. if (this.$el.css('display') === 'inline') { @@ -129,6 +138,9 @@ Drupal.edit.editors.form = Drupal.edit.EditorView.extend({ } }); + // Set focus on the form, so that the next tab goes to the first field + // in this container. + $formContainer[0].focus(); // The in-place editor has loaded; change state to 'active'. fieldModel.set('state', 'active'); }); @@ -150,6 +162,19 @@ Drupal.edit.editors.form = Drupal.edit.EditorView.extend({ .off('keypress.edit', 'input') .remove(); this.$formContainer = null; + // Remove the form id from the entity's aria-owns attribute. + var $entity = $(this.fieldModel.get('entity').get('el')); + var owns = $entity.attr('aria-owns'); + if (owns) { + owns + .split(' ') + .filter(function (id) { + // Remove id values that start with 'edit-form-for-'. + return (id.indexOf('edit-form-for-') !== 0); + }) + .join(' '); + $entity.attr('aria-owns', owns); + } }, /** diff --git a/core/modules/edit/js/theme.js b/core/modules/edit/js/theme.js index fdd0fbb..b589064 100644 --- a/core/modules/edit/js/theme.js +++ b/core/modules/edit/js/theme.js @@ -33,7 +33,7 @@ Drupal.theme.editBackstage = function (settings) { */ Drupal.theme.editEntityToolbar = function (settings) { var html = ''; - html += '
'; + html += '