annotate core/modules/ckeditor/js/views/AuralView.es6.js @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 /**
Chris@0 2 * @file
Chris@0 3 * A Backbone View that provides the aural view of CKEditor toolbar
Chris@0 4 * configuration.
Chris@0 5 */
Chris@0 6
Chris@17 7 (function(Drupal, Backbone, $) {
Chris@17 8 Drupal.ckeditor.AuralView = Backbone.View.extend(
Chris@17 9 /** @lends Drupal.ckeditor.AuralView# */ {
Chris@17 10 /**
Chris@17 11 * @type {object}
Chris@17 12 */
Chris@17 13 events: {
Chris@17 14 'click .ckeditor-buttons a': 'announceButtonHelp',
Chris@17 15 'click .ckeditor-multiple-buttons a': 'announceSeparatorHelp',
Chris@17 16 'focus .ckeditor-button a': 'onFocus',
Chris@17 17 'focus .ckeditor-button-separator a': 'onFocus',
Chris@17 18 'focus .ckeditor-toolbar-group': 'onFocus',
Chris@17 19 },
Chris@0 20
Chris@17 21 /**
Chris@17 22 * Backbone View for CKEditor toolbar configuration; aural UX (output only).
Chris@17 23 *
Chris@17 24 * @constructs
Chris@17 25 *
Chris@17 26 * @augments Backbone.View
Chris@17 27 */
Chris@17 28 initialize() {
Chris@17 29 // Announce the button and group positions when the model is no longer
Chris@17 30 // dirty.
Chris@17 31 this.listenTo(this.model, 'change:isDirty', this.announceMove);
Chris@17 32 },
Chris@0 33
Chris@17 34 /**
Chris@17 35 * Calls announce on buttons and groups when their position is changed.
Chris@17 36 *
Chris@17 37 * @param {Drupal.ckeditor.ConfigurationModel} model
Chris@17 38 * The ckeditor configuration model.
Chris@17 39 * @param {bool} isDirty
Chris@17 40 * A model attribute that indicates if the changed toolbar configuration
Chris@17 41 * has been stored or not.
Chris@17 42 */
Chris@17 43 announceMove(model, isDirty) {
Chris@17 44 // Announce the position of a button or group after the model has been
Chris@17 45 // updated.
Chris@17 46 if (!isDirty) {
Chris@17 47 const item = document.activeElement || null;
Chris@17 48 if (item) {
Chris@17 49 const $item = $(item);
Chris@17 50 if ($item.hasClass('ckeditor-toolbar-group')) {
Chris@17 51 this.announceButtonGroupPosition($item);
Chris@17 52 } else if ($item.parent().hasClass('ckeditor-button')) {
Chris@17 53 this.announceButtonPosition($item.parent());
Chris@17 54 }
Chris@0 55 }
Chris@0 56 }
Chris@17 57 },
Chris@0 58
Chris@17 59 /**
Chris@17 60 * Handles the focus event of elements in the active and available toolbars.
Chris@17 61 *
Chris@17 62 * @param {jQuery.Event} event
Chris@17 63 * The focus event that was triggered.
Chris@17 64 */
Chris@17 65 onFocus(event) {
Chris@17 66 event.stopPropagation();
Chris@0 67
Chris@17 68 const $originalTarget = $(event.target);
Chris@17 69 const $currentTarget = $(event.currentTarget);
Chris@17 70 const $parent = $currentTarget.parent();
Chris@17 71 if (
Chris@17 72 $parent.hasClass('ckeditor-button') ||
Chris@17 73 $parent.hasClass('ckeditor-button-separator')
Chris@17 74 ) {
Chris@17 75 this.announceButtonPosition($currentTarget.parent());
Chris@17 76 } else if (
Chris@17 77 $originalTarget.attr('role') !== 'button' &&
Chris@17 78 $currentTarget.hasClass('ckeditor-toolbar-group')
Chris@17 79 ) {
Chris@17 80 this.announceButtonGroupPosition($currentTarget);
Chris@17 81 }
Chris@17 82 },
Chris@0 83
Chris@17 84 /**
Chris@17 85 * Announces the current position of a button group.
Chris@17 86 *
Chris@17 87 * @param {jQuery} $group
Chris@17 88 * A jQuery set that contains an li element that wraps a group of buttons.
Chris@17 89 */
Chris@17 90 announceButtonGroupPosition($group) {
Chris@17 91 const $groups = $group.parent().children();
Chris@17 92 const $row = $group.closest('.ckeditor-row');
Chris@17 93 const $rows = $row.parent().children();
Chris@17 94 const position = $groups.index($group) + 1;
Chris@17 95 const positionCount = $groups.not('.placeholder').length;
Chris@17 96 const row = $rows.index($row) + 1;
Chris@17 97 const rowCount = $rows.not('.placeholder').length;
Chris@17 98 let text = Drupal.t(
Chris@17 99 '@groupName button group in position @position of @positionCount in row @row of @rowCount.',
Chris@17 100 {
Chris@17 101 '@groupName': $group.attr(
Chris@17 102 'data-drupal-ckeditor-toolbar-group-name',
Chris@17 103 ),
Chris@17 104 '@position': position,
Chris@17 105 '@positionCount': positionCount,
Chris@17 106 '@row': row,
Chris@17 107 '@rowCount': rowCount,
Chris@17 108 },
Chris@17 109 );
Chris@0 110 // If this position is the first in the last row then tell the user that
Chris@0 111 // pressing the down arrow key will create a new row.
Chris@17 112 if (position === 1 && row === rowCount) {
Chris@0 113 text += '\n';
Chris@17 114 text += Drupal.t('Press the down arrow key to create a new row.');
Chris@0 115 }
Chris@0 116 Drupal.announce(text, 'assertive');
Chris@17 117 },
Chris@17 118
Chris@17 119 /**
Chris@17 120 * Announces current button position.
Chris@17 121 *
Chris@17 122 * @param {jQuery} $button
Chris@17 123 * A jQuery set that contains an li element that wraps a button.
Chris@17 124 */
Chris@17 125 announceButtonPosition($button) {
Chris@17 126 const $row = $button.closest('.ckeditor-row');
Chris@17 127 const $rows = $row.parent().children();
Chris@17 128 const $buttons = $button.closest('.ckeditor-buttons').children();
Chris@17 129 const $group = $button.closest('.ckeditor-toolbar-group');
Chris@17 130 const $groups = $group.parent().children();
Chris@17 131 const groupPosition = $groups.index($group) + 1;
Chris@17 132 const groupPositionCount = $groups.not('.placeholder').length;
Chris@17 133 const position = $buttons.index($button) + 1;
Chris@17 134 const positionCount = $buttons.length;
Chris@17 135 const row = $rows.index($row) + 1;
Chris@17 136 const rowCount = $rows.not('.placeholder').length;
Chris@17 137 // The name of the button separator is 'button separator' and its type
Chris@17 138 // is 'separator', so we do not want to print the type of this item,
Chris@17 139 // otherwise the UA will speak 'button separator separator'.
Chris@17 140 const type =
Chris@17 141 $button.attr('data-drupal-ckeditor-type') === 'separator'
Chris@17 142 ? ''
Chris@17 143 : Drupal.t('button');
Chris@17 144 let text;
Chris@17 145 // The button is located in the available button set.
Chris@17 146 if ($button.closest('.ckeditor-toolbar-disabled').length > 0) {
Chris@17 147 text = Drupal.t('@name @type.', {
Chris@17 148 '@name': $button.children().attr('aria-label'),
Chris@17 149 '@type': type,
Chris@17 150 });
Chris@17 151 text += `\n${Drupal.t('Press the down arrow key to activate.')}`;
Chris@17 152
Chris@17 153 Drupal.announce(text, 'assertive');
Chris@17 154 }
Chris@17 155 // The button is in the active toolbar.
Chris@17 156 else if ($group.not('.placeholder').length === 1) {
Chris@17 157 text = Drupal.t(
Chris@17 158 '@name @type in position @position of @positionCount in @groupName button group in row @row of @rowCount.',
Chris@17 159 {
Chris@17 160 '@name': $button.children().attr('aria-label'),
Chris@17 161 '@type': type,
Chris@17 162 '@position': position,
Chris@17 163 '@positionCount': positionCount,
Chris@17 164 '@groupName': $group.attr(
Chris@17 165 'data-drupal-ckeditor-toolbar-group-name',
Chris@17 166 ),
Chris@17 167 '@row': row,
Chris@17 168 '@rowCount': rowCount,
Chris@17 169 },
Chris@17 170 );
Chris@17 171 // If this position is the first in the last row then tell the user that
Chris@17 172 // pressing the down arrow key will create a new row.
Chris@17 173 if (groupPosition === 1 && position === 1 && row === rowCount) {
Chris@17 174 text += '\n';
Chris@17 175 text += Drupal.t(
Chris@17 176 'Press the down arrow key to create a new button group in a new row.',
Chris@17 177 );
Chris@17 178 }
Chris@17 179 // If this position is the last one in this row then tell the user that
Chris@17 180 // moving the button to the next group will create a new group.
Chris@17 181 if (
Chris@17 182 groupPosition === groupPositionCount &&
Chris@17 183 position === positionCount
Chris@17 184 ) {
Chris@17 185 text += '\n';
Chris@17 186 text += Drupal.t(
Chris@17 187 'This is the last group. Move the button forward to create a new group.',
Chris@17 188 );
Chris@17 189 }
Chris@17 190 Drupal.announce(text, 'assertive');
Chris@17 191 }
Chris@17 192 },
Chris@17 193
Chris@17 194 /**
Chris@17 195 * Provides help information when a button is clicked.
Chris@17 196 *
Chris@17 197 * @param {jQuery.Event} event
Chris@17 198 * The click event for the button click.
Chris@17 199 */
Chris@17 200 announceButtonHelp(event) {
Chris@17 201 const $link = $(event.currentTarget);
Chris@17 202 const $button = $link.parent();
Chris@17 203 const enabled = $button.closest('.ckeditor-toolbar-active').length > 0;
Chris@17 204 let message;
Chris@17 205
Chris@17 206 if (enabled) {
Chris@17 207 message = Drupal.t('The "@name" button is currently enabled.', {
Chris@17 208 '@name': $link.attr('aria-label'),
Chris@17 209 });
Chris@17 210 message += `\n${Drupal.t(
Chris@17 211 'Use the keyboard arrow keys to change the position of this button.',
Chris@17 212 )}`;
Chris@17 213 message += `\n${Drupal.t(
Chris@17 214 'Press the up arrow key on the top row to disable the button.',
Chris@17 215 )}`;
Chris@17 216 } else {
Chris@17 217 message = Drupal.t('The "@name" button is currently disabled.', {
Chris@17 218 '@name': $link.attr('aria-label'),
Chris@17 219 });
Chris@17 220 message += `\n${Drupal.t(
Chris@17 221 'Use the down arrow key to move this button into the active toolbar.',
Chris@17 222 )}`;
Chris@17 223 }
Chris@17 224 Drupal.announce(message);
Chris@17 225 event.preventDefault();
Chris@17 226 },
Chris@17 227
Chris@17 228 /**
Chris@17 229 * Provides help information when a separator is clicked.
Chris@17 230 *
Chris@17 231 * @param {jQuery.Event} event
Chris@17 232 * The click event for the separator click.
Chris@17 233 */
Chris@17 234 announceSeparatorHelp(event) {
Chris@17 235 const $link = $(event.currentTarget);
Chris@17 236 const $button = $link.parent();
Chris@17 237 const enabled = $button.closest('.ckeditor-toolbar-active').length > 0;
Chris@17 238 let message;
Chris@17 239
Chris@17 240 if (enabled) {
Chris@17 241 message = Drupal.t('This @name is currently enabled.', {
Chris@17 242 '@name': $link.attr('aria-label'),
Chris@17 243 });
Chris@17 244 message += `\n${Drupal.t(
Chris@17 245 'Use the keyboard arrow keys to change the position of this separator.',
Chris@17 246 )}`;
Chris@17 247 } else {
Chris@17 248 message = Drupal.t(
Chris@17 249 'Separators are used to visually split individual buttons.',
Chris@17 250 );
Chris@17 251 message += `\n${Drupal.t('This @name is currently disabled.', {
Chris@17 252 '@name': $link.attr('aria-label'),
Chris@17 253 })}`;
Chris@17 254 message += `\n${Drupal.t(
Chris@17 255 'Use the down arrow key to move this separator into the active toolbar.',
Chris@17 256 )}`;
Chris@17 257 message += `\n${Drupal.t(
Chris@17 258 'You may add multiple separators to each button group.',
Chris@17 259 )}`;
Chris@17 260 }
Chris@17 261 Drupal.announce(message);
Chris@17 262 event.preventDefault();
Chris@17 263 },
Chris@0 264 },
Chris@17 265 );
Chris@17 266 })(Drupal, Backbone, jQuery);