From e40382eed19f46cd7ab8c7f2562aaa2bf4accd0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?"J.=20Rene=CC=81e=20Beach"?= Date: Thu, 29 Nov 2012 11:40:23 -0500 Subject: [PATCH] Issue #1851092 by jessebeach: Added aural application status updates with an ARIA live region. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit cbe8de43e5cda7eb8986ed4c3fa25d1a02c04315 Author: J. Renée Beach Date: Thu Nov 29 11:35:47 2012 -0500 Issue #1851092 by jessebeach: Added aural messaging of the application state with an ARIA live region. Signed-off-by: J. Renée Beach Signed-off-by: J. Renée Beach --- css/edit.css | 3 ++- edit.module | 5 +++++ js/app.js | 3 +++ js/edit.js | 56 +++++++++++++++++++++++++++++++++++++++++++++- js/theme.js | 2 +- js/views/modal-view.js | 2 ++ js/views/toolbar-view.js | 2 +- 7 files changed, 69 insertions(+), 4 deletions(-) diff --git a/css/edit.css b/css/edit.css index 2b615d2..1c88ebb 100644 --- a/css/edit.css +++ b/css/edit.css @@ -352,8 +352,9 @@ display: block; float: left; } -.edit-toolbar button span.close { +.edit-toolbar span.close { background: url('../images/close.png') no-repeat 3px 2px; + text-indent: -999em; } .edit-toolbar button.blank-button { diff --git a/edit.module b/edit.module index dd4feaf..94e7b24 100644 --- a/edit.module +++ b/edit.module @@ -89,6 +89,8 @@ function edit_toolbar() { 'href' => request_path(), 'fragment' => 'view', 'attributes' => array( + 'title' => t('Exit quick edit mode.'), + 'role' => 'button', 'class' => array('edit_view-edit-toggle', 'edit-view'), ), ), @@ -97,6 +99,8 @@ function edit_toolbar() { 'href' => request_path(), 'fragment' => 'quick-edit', 'attributes' => array( + 'title' => t('Enter quick edit mode.'), + 'role' => 'button', 'class' => array('edit_view-edit-toggle', 'edit-edit'), ), ), @@ -218,6 +222,7 @@ function edit_preprocess_field(&$variables) { // Mark this field as editable and provide metadata through data- attributes. $variables['attributes']['data-edit-field-label'] = $instance->definition['label']; $variables['attributes']['data-edit-id'] = $entity->entityType() . ':' . $entity->id() . ':' . $field_name . ':' . $langcode . ':' . $view_mode; + $variables['attributes']['aria-label'] = t('Edit entity @type @id, field @field', array('@type' => $entity->entityType(), '@id' => $entity->id(), '@field' => $instance->definition['label'])); $variables['attributes']['class'][] = 'edit-field'; $variables['attributes']['class'][] = 'edit-allowed'; $variables['attributes']['class'][] = 'edit-type-' . $editor; diff --git a/js/app.js b/js/app.js index d0354e4..c6671ac 100644 --- a/js/app.js +++ b/js/app.js @@ -94,9 +94,11 @@ // Manage the page's tab indexes. if (newState === 'candidate') { this._manageDocumentFocus(); + Drupal.edit.setMessage(Drupal.t('In place edit mode is active'), Drupal.t('Page navigation is limited to editable items.'), Drupal.t('Press escape to exit')); } else { this._releaseDocumentFocusManagement(); + Drupal.edit.setMessage(Drupal.t('Edit mode is inactive.'), Drupal.t('Resume normal page navigation')); } }, @@ -276,6 +278,7 @@ // Keep track of the active editor in the global state. if (_.indexOf(this.activeEditorStates, to) !== -1 && this.model.get('activeEditor') !== editor) { this.model.set('activeEditor', editor); + Drupal.edit.setMessage(Drupal.t('An editor is active')); } else if (this.model.get('activeEditor') === editor && to === 'candidate') { this.model.set('activeEditor', null); diff --git a/js/edit.js b/js/edit.js index 2c42068..e208c34 100644 --- a/js/edit.js +++ b/js/edit.js @@ -6,11 +6,24 @@ "use strict"; +/** + * The edit ARIA live message area. + * + * @todo Eventually the messages area should be converted into a Backbone View + * that will respond to changes in the application's model. For the initial + * implementation, we will call the Drupal.edit.setMessage method when an aural + * message should be read by the user agent. + */ +var $messages; + Drupal.edit = Drupal.edit || {}; Drupal.behaviors.editDiscoverEditables = { attach: function(context) { - // @todo BLOCKED_ON(VIE.js, how to let VIE know that some content was removed and how to scan new content for VIE entities, to make them editable?) + // @todo BLOCKED_ON(VIE.js, how to let VIE know that some content was + // removed and how to scan new content for VIE entities, to make them + // editable?) + // // Also see ToolbarView.save(). // We need to separate the discovery of editables if we want updated // or new content (added by code other than Edit) to be detected @@ -35,6 +48,9 @@ Drupal.behaviors.edit = { }; Drupal.edit.init = function() { + // Append a messages element for appending interaction updates for screen + // readers. + $messages = $(Drupal.theme('editMessageBox')).appendTo(this); // Instantiate EditAppView, which is the controller of it all. EditAppModel // instance tracks global state (viewing/editing in-place). var appModel = new Drupal.edit.models.EditAppModel(); @@ -52,4 +68,42 @@ Drupal.edit.init = function() { Backbone.history.start(); }; +/** + * Places the message in the edit ARIA live message area. + * + * The message will be read by speaking User Agents. + * + * @param {String} message + * A string to be inserted into the message area. + */ +Drupal.edit.setMessage = function (message) { + var args = Array.prototype.slice.call(arguments); + args.unshift('editMessage'); + $messages.html(Drupal.theme.apply(this, args)); +} + +/** + * A region to post messages that a screen reading UA will announce. + * + * @return {String} + * A string representing a DOM fragment. + */ +Drupal.theme.editMessageBox = function () { + return '
'; +}; + +/** + * Wrap message strings in p tags. + * + * @return {String} + * A string representing a DOM fragment. + */ +Drupal.theme.editMessage = function () { + var messages = Array.prototype.slice.call(arguments); + var output = ''; + for (var i = 0; i < messages.length; i++) { + output += '

' + messages[i] + '

'; + } + return output; +}; })(jQuery, Backbone, Drupal); diff --git a/js/theme.js b/js/theme.js index a43bc29..9a72724 100644 --- a/js/theme.js +++ b/js/theme.js @@ -48,7 +48,7 @@ Drupal.theme.editBackstage = function(settings) { Drupal.theme.editModal = function(settings) { var classes = 'edit-animate-slow edit-animate-invisible edit-animate-delay-veryfast'; var html = ''; - html += '
'; + html += ''; diff --git a/js/views/modal-view.js b/js/views/modal-view.js index 7482d31..3989c7e 100644 --- a/js/views/modal-view.js +++ b/js/views/modal-view.js @@ -69,6 +69,8 @@ Drupal.edit.views.ModalView = Backbone.View.extend({ setTimeout(function() { that.$el.removeClass('edit-animate-invisible'); }, 0); + + Drupal.edit.setMessage(Drupal.t('Confirmation dialog open')); }, /** diff --git a/js/views/toolbar-view.js b/js/views/toolbar-view.js index 14d4df1..4e46875 100644 --- a/js/views/toolbar-view.js +++ b/js/views/toolbar-view.js @@ -278,7 +278,7 @@ Drupal.edit.views.ToolbarView = Backbone.View.extend({ classes: 'ops', buttons: [ { label: Drupal.t('Save'), type: 'submit', classes: 'field-save save gray-button' }, - { label: '', classes: 'field-close close gray-button' } + { label: '' + Drupal.t('Close') + '', classes: 'field-close close gray-button' } ] })); this.show('ops'); -- 1.7.10.4