Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / modules / ckeditor / js / views / AuralView.es6.js
1 /**
2  * @file
3  * A Backbone View that provides the aural view of CKEditor toolbar
4  * configuration.
5  */
6
7 (function(Drupal, Backbone, $) {
8   Drupal.ckeditor.AuralView = Backbone.View.extend(
9     /** @lends Drupal.ckeditor.AuralView# */ {
10       /**
11        * @type {object}
12        */
13       events: {
14         'click .ckeditor-buttons a': 'announceButtonHelp',
15         'click .ckeditor-multiple-buttons a': 'announceSeparatorHelp',
16         'focus .ckeditor-button a': 'onFocus',
17         'focus .ckeditor-button-separator a': 'onFocus',
18         'focus .ckeditor-toolbar-group': 'onFocus',
19       },
20
21       /**
22        * Backbone View for CKEditor toolbar configuration; aural UX (output only).
23        *
24        * @constructs
25        *
26        * @augments Backbone.View
27        */
28       initialize() {
29         // Announce the button and group positions when the model is no longer
30         // dirty.
31         this.listenTo(this.model, 'change:isDirty', this.announceMove);
32       },
33
34       /**
35        * Calls announce on buttons and groups when their position is changed.
36        *
37        * @param {Drupal.ckeditor.ConfigurationModel} model
38        *   The ckeditor configuration model.
39        * @param {bool} isDirty
40        *   A model attribute that indicates if the changed toolbar configuration
41        *   has been stored or not.
42        */
43       announceMove(model, isDirty) {
44         // Announce the position of a button or group after the model has been
45         // updated.
46         if (!isDirty) {
47           const item = document.activeElement || null;
48           if (item) {
49             const $item = $(item);
50             if ($item.hasClass('ckeditor-toolbar-group')) {
51               this.announceButtonGroupPosition($item);
52             } else if ($item.parent().hasClass('ckeditor-button')) {
53               this.announceButtonPosition($item.parent());
54             }
55           }
56         }
57       },
58
59       /**
60        * Handles the focus event of elements in the active and available toolbars.
61        *
62        * @param {jQuery.Event} event
63        *   The focus event that was triggered.
64        */
65       onFocus(event) {
66         event.stopPropagation();
67
68         const $originalTarget = $(event.target);
69         const $currentTarget = $(event.currentTarget);
70         const $parent = $currentTarget.parent();
71         if (
72           $parent.hasClass('ckeditor-button') ||
73           $parent.hasClass('ckeditor-button-separator')
74         ) {
75           this.announceButtonPosition($currentTarget.parent());
76         } else if (
77           $originalTarget.attr('role') !== 'button' &&
78           $currentTarget.hasClass('ckeditor-toolbar-group')
79         ) {
80           this.announceButtonGroupPosition($currentTarget);
81         }
82       },
83
84       /**
85        * Announces the current position of a button group.
86        *
87        * @param {jQuery} $group
88        *   A jQuery set that contains an li element that wraps a group of buttons.
89        */
90       announceButtonGroupPosition($group) {
91         const $groups = $group.parent().children();
92         const $row = $group.closest('.ckeditor-row');
93         const $rows = $row.parent().children();
94         const position = $groups.index($group) + 1;
95         const positionCount = $groups.not('.placeholder').length;
96         const row = $rows.index($row) + 1;
97         const rowCount = $rows.not('.placeholder').length;
98         let text = Drupal.t(
99           '@groupName button group in position @position of @positionCount in row @row of @rowCount.',
100           {
101             '@groupName': $group.attr(
102               'data-drupal-ckeditor-toolbar-group-name',
103             ),
104             '@position': position,
105             '@positionCount': positionCount,
106             '@row': row,
107             '@rowCount': rowCount,
108           },
109         );
110         // If this position is the first in the last row then tell the user that
111         // pressing the down arrow key will create a new row.
112         if (position === 1 && row === rowCount) {
113           text += '\n';
114           text += Drupal.t('Press the down arrow key to create a new row.');
115         }
116         Drupal.announce(text, 'assertive');
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       },
264     },
265   );
266 })(Drupal, Backbone, jQuery);