comparison core/modules/ckeditor/js/views/AuralView.es6.js @ 4:a9cd425dd02b

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