comparison core/modules/ckeditor/js/views/KeyboardView.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
1 /** 1 /**
2 * @file 2 * @file
3 * Backbone View providing the aural view of CKEditor keyboard UX configuration. 3 * Backbone View providing the aural view of CKEditor keyboard UX configuration.
4 */ 4 */
5 5
6 (function ($, Drupal, Backbone, _) { 6 (function($, Drupal, Backbone, _) {
7 Drupal.ckeditor.KeyboardView = Backbone.View.extend(/** @lends Drupal.ckeditor.KeyboardView# */{ 7 Drupal.ckeditor.KeyboardView = Backbone.View.extend(
8 8 /** @lends Drupal.ckeditor.KeyboardView# */ {
9 /** 9 /**
10 * Backbone View for CKEditor toolbar configuration; keyboard UX. 10 * Backbone View for CKEditor toolbar configuration; keyboard UX.
11 * 11 *
12 * @constructs 12 * @constructs
13 * 13 *
14 * @augments Backbone.View 14 * @augments Backbone.View
15 */ 15 */
16 initialize() { 16 initialize() {
17 // Add keyboard arrow support. 17 // Add keyboard arrow support.
18 this.$el.on('keydown.ckeditor', '.ckeditor-buttons a, .ckeditor-multiple-buttons a', this.onPressButton.bind(this)); 18 this.$el.on(
19 this.$el.on('keydown.ckeditor', '[data-drupal-ckeditor-type="group"]', this.onPressGroup.bind(this)); 19 'keydown.ckeditor',
20 }, 20 '.ckeditor-buttons a, .ckeditor-multiple-buttons a',
21 21 this.onPressButton.bind(this),
22 /** 22 );
23 * @inheritdoc 23 this.$el.on(
24 */ 24 'keydown.ckeditor',
25 render() { 25 '[data-drupal-ckeditor-type="group"]',
26 }, 26 this.onPressGroup.bind(this),
27 27 );
28 /** 28 },
29 * Handles keypresses on a CKEditor configuration button. 29
30 * 30 /**
31 * @param {jQuery.Event} event 31 * @inheritdoc
32 * The keypress event triggered. 32 */
33 */ 33 render() {},
34 onPressButton(event) { 34
35 const upDownKeys = [ 35 /**
36 38, // Up arrow. 36 * Handles keypresses on a CKEditor configuration button.
37 63232, // Safari up arrow. 37 *
38 40, // Down arrow. 38 * @param {jQuery.Event} event
39 63233, // Safari down arrow. 39 * The keypress event triggered.
40 ]; 40 */
41 const leftRightKeys = [ 41 onPressButton(event) {
42 37, // Left arrow. 42 const upDownKeys = [
43 63234, // Safari left arrow. 43 38, // Up arrow.
44 39, // Right arrow. 44 63232, // Safari up arrow.
45 63235, // Safari right arrow. 45 40, // Down arrow.
46 ]; 46 63233, // Safari down arrow.
47 47 ];
48 // Respond to an enter key press. Prevent the bubbling of the enter key 48 const leftRightKeys = [
49 // press to the button group parent element. 49 37, // Left arrow.
50 if (event.keyCode === 13) { 50 63234, // Safari left arrow.
51 event.stopPropagation(); 51 39, // Right arrow.
52 } 52 63235, // Safari right arrow.
53 53 ];
54 // Only take action when a direction key is pressed. 54
55 if (_.indexOf(_.union(upDownKeys, leftRightKeys), event.keyCode) > -1) { 55 // Respond to an enter key press. Prevent the bubbling of the enter key
56 let view = this; 56 // press to the button group parent element.
57 let $target = $(event.currentTarget); 57 if (event.keyCode === 13) {
58 let $button = $target.parent(); 58 event.stopPropagation();
59 const $container = $button.parent();
60 let $group = $button.closest('.ckeditor-toolbar-group');
61 let $row;
62 const containerType = $container.data('drupal-ckeditor-button-sorting');
63 const $availableButtons = this.$el.find('[data-drupal-ckeditor-button-sorting="source"]');
64 const $activeButtons = this.$el.find('.ckeditor-toolbar-active');
65 // The current location of the button, just in case it needs to be put
66 // back.
67 const $originalGroup = $group;
68 let dir;
69
70 // Move available buttons between their container and the active
71 // toolbar.
72 if (containerType === 'source') {
73 // Move the button to the active toolbar configuration when the down
74 // or up keys are pressed.
75 if (_.indexOf([40, 63233], event.keyCode) > -1) {
76 // Move the button to the first row, first button group index
77 // position.
78 $activeButtons.find('.ckeditor-toolbar-group-buttons').eq(0).prepend($button);
79 }
80 } 59 }
81 else if (containerType === 'target') { 60
82 // Move buttons between sibling buttons in a group and between groups. 61 // Only take action when a direction key is pressed.
83 if (_.indexOf(leftRightKeys, event.keyCode) > -1) { 62 if (_.indexOf(_.union(upDownKeys, leftRightKeys), event.keyCode) > -1) {
84 // Move left. 63 let view = this;
85 const $siblings = $container.children(); 64 let $target = $(event.currentTarget);
86 const index = $siblings.index($button); 65 let $button = $target.parent();
87 if (_.indexOf([37, 63234], event.keyCode) > -1) { 66 const $container = $button.parent();
88 // Move between sibling buttons. 67 let $group = $button.closest('.ckeditor-toolbar-group');
89 if (index > 0) { 68 let $row;
90 $button.insertBefore($container.children().eq(index - 1)); 69 const containerType = $container.data(
91 } 70 'drupal-ckeditor-button-sorting',
92 // Move between button groups and rows. 71 );
93 else { 72 const $availableButtons = this.$el.find(
94 // Move between button groups. 73 '[data-drupal-ckeditor-button-sorting="source"]',
95 $group = $container.parent().prev(); 74 );
96 if ($group.length > 0) { 75 const $activeButtons = this.$el.find('.ckeditor-toolbar-active');
97 $group.find('.ckeditor-toolbar-group-buttons').append($button); 76 // The current location of the button, just in case it needs to be put
98 } 77 // back.
99 // Wrap between rows. 78 const $originalGroup = $group;
79 let dir;
80
81 // Move available buttons between their container and the active
82 // toolbar.
83 if (containerType === 'source') {
84 // Move the button to the active toolbar configuration when the down
85 // or up keys are pressed.
86 if (_.indexOf([40, 63233], event.keyCode) > -1) {
87 // Move the button to the first row, first button group index
88 // position.
89 $activeButtons
90 .find('.ckeditor-toolbar-group-buttons')
91 .eq(0)
92 .prepend($button);
93 }
94 } else if (containerType === 'target') {
95 // Move buttons between sibling buttons in a group and between groups.
96 if (_.indexOf(leftRightKeys, event.keyCode) > -1) {
97 // Move left.
98 const $siblings = $container.children();
99 const index = $siblings.index($button);
100 if (_.indexOf([37, 63234], event.keyCode) > -1) {
101 // Move between sibling buttons.
102 if (index > 0) {
103 $button.insertBefore($container.children().eq(index - 1));
104 }
105 // Move between button groups and rows.
106 else {
107 // Move between button groups.
108 $group = $container.parent().prev();
109 if ($group.length > 0) {
110 $group
111 .find('.ckeditor-toolbar-group-buttons')
112 .append($button);
113 }
114 // Wrap between rows.
115 else {
116 $container
117 .closest('.ckeditor-row')
118 .prev()
119 .find('.ckeditor-toolbar-group')
120 .not('.placeholder')
121 .find('.ckeditor-toolbar-group-buttons')
122 .eq(-1)
123 .append($button);
124 }
125 }
126 }
127 // Move right.
128 else if (_.indexOf([39, 63235], event.keyCode) > -1) {
129 // Move between sibling buttons.
130 if (index < $siblings.length - 1) {
131 $button.insertAfter($container.children().eq(index + 1));
132 }
133 // Move between button groups. Moving right at the end of a row
134 // will create a new group.
100 else { 135 else {
101 $container 136 $container
102 .closest('.ckeditor-row') 137 .parent()
103 .prev() 138 .next()
104 .find('.ckeditor-toolbar-group')
105 .not('.placeholder')
106 .find('.ckeditor-toolbar-group-buttons') 139 .find('.ckeditor-toolbar-group-buttons')
107 .eq(-1) 140 .prepend($button);
108 .append($button); 141 }
109 } 142 }
110 } 143 }
111 } 144 // Move buttons between rows and the available button set.
112 // Move right. 145 else if (_.indexOf(upDownKeys, event.keyCode) > -1) {
113 else if (_.indexOf([39, 63235], event.keyCode) > -1) { 146 dir =
114 // Move between sibling buttons. 147 _.indexOf([38, 63232], event.keyCode) > -1 ? 'prev' : 'next';
115 if (index < ($siblings.length - 1)) { 148 $row = $container.closest('.ckeditor-row')[dir]();
116 $button.insertAfter($container.children().eq(index + 1)); 149 // Move the button back into the available button set.
117 } 150 if (dir === 'prev' && $row.length === 0) {
118 // Move between button groups. Moving right at the end of a row 151 // If this is a divider, just destroy it.
119 // will create a new group. 152 if ($button.data('drupal-ckeditor-type') === 'separator') {
120 else { 153 $button.off().remove();
121 $container.parent().next().find('.ckeditor-toolbar-group-buttons').prepend($button); 154 // Focus on the first button in the active toolbar.
122 } 155 $activeButtons
123 } 156 .find('.ckeditor-toolbar-group-buttons')
124 } 157 .eq(0)
125 // Move buttons between rows and the available button set. 158 .children()
126 else if (_.indexOf(upDownKeys, event.keyCode) > -1) { 159 .eq(0)
127 dir = (_.indexOf([38, 63232], event.keyCode) > -1) ? 'prev' : 'next'; 160 .children()
128 $row = $container.closest('.ckeditor-row')[dir](); 161 .trigger('focus');
129 // Move the button back into the available button set. 162 }
130 if (dir === 'prev' && $row.length === 0) { 163 // Otherwise, move it.
131 // If this is a divider, just destroy it. 164 else {
132 if ($button.data('drupal-ckeditor-type') === 'separator') { 165 $availableButtons.prepend($button);
133 $button 166 }
134 .off() 167 } else {
135 .remove(); 168 $row
136 // Focus on the first button in the active toolbar.
137 $activeButtons
138 .find('.ckeditor-toolbar-group-buttons') 169 .find('.ckeditor-toolbar-group-buttons')
139 .eq(0) 170 .eq(0)
171 .prepend($button);
172 }
173 }
174 }
175 // Move dividers between their container and the active toolbar.
176 else if (containerType === 'dividers') {
177 // Move the button to the active toolbar configuration when the down
178 // or up keys are pressed.
179 if (_.indexOf([40, 63233], event.keyCode) > -1) {
180 // Move the button to the first row, first button group index
181 // position.
182 $button = $button.clone(true);
183 $activeButtons
184 .find('.ckeditor-toolbar-group-buttons')
185 .eq(0)
186 .prepend($button);
187 $target = $button.children();
188 }
189 }
190
191 view = this;
192 // Attempt to move the button to the new toolbar position.
193 Drupal.ckeditor.registerButtonMove(this, $button, result => {
194 // Put the button back if the registration failed.
195 // If the button was in a row, then it was in the active toolbar
196 // configuration. The button was probably placed in a new group, but
197 // that action was canceled.
198 if (!result && $originalGroup) {
199 $originalGroup.find('.ckeditor-buttons').append($button);
200 }
201 // Otherwise refresh the sortables to acknowledge the new button
202 // positions.
203 else {
204 view.$el.find('.ui-sortable').sortable('refresh');
205 }
206 // Refocus the target button so that the user can continue from a
207 // known place.
208 $target.trigger('focus');
209 });
210
211 event.preventDefault();
212 event.stopPropagation();
213 }
214 },
215
216 /**
217 * Handles keypresses on a CKEditor configuration group.
218 *
219 * @param {jQuery.Event} event
220 * The keypress event triggered.
221 */
222 onPressGroup(event) {
223 const upDownKeys = [
224 38, // Up arrow.
225 63232, // Safari up arrow.
226 40, // Down arrow.
227 63233, // Safari down arrow.
228 ];
229 const leftRightKeys = [
230 37, // Left arrow.
231 63234, // Safari left arrow.
232 39, // Right arrow.
233 63235, // Safari right arrow.
234 ];
235
236 // Respond to an enter key press.
237 if (event.keyCode === 13) {
238 const view = this;
239 // Open the group renaming dialog in the next evaluation cycle so that
240 // this event can be cancelled and the bubbling wiped out. Otherwise,
241 // Firefox has issues because the page focus is shifted to the dialog
242 // along with the keydown event.
243 window.setTimeout(() => {
244 Drupal.ckeditor.openGroupNameDialog(view, $(event.currentTarget));
245 }, 0);
246 event.preventDefault();
247 event.stopPropagation();
248 }
249
250 // Respond to direction key presses.
251 if (_.indexOf(_.union(upDownKeys, leftRightKeys), event.keyCode) > -1) {
252 const $group = $(event.currentTarget);
253 const $container = $group.parent();
254 const $siblings = $container.children();
255 let index;
256 let dir;
257 // Move groups between sibling groups.
258 if (_.indexOf(leftRightKeys, event.keyCode) > -1) {
259 index = $siblings.index($group);
260 // Move left between sibling groups.
261 if (_.indexOf([37, 63234], event.keyCode) > -1) {
262 if (index > 0) {
263 $group.insertBefore($siblings.eq(index - 1));
264 }
265 // Wrap between rows. Insert the group before the placeholder group
266 // at the end of the previous row.
267 else {
268 const $rowChildElement = $container
269 .closest('.ckeditor-row')
270 .prev()
271 .find('.ckeditor-toolbar-groups')
140 .children() 272 .children()
141 .eq(0) 273 .eq(-1);
142 .children() 274 $group.insertBefore($rowChildElement);
143 .trigger('focus'); 275 }
144 } 276 }
145 // Otherwise, move it. 277 // Move right between sibling groups.
278 else if (_.indexOf([39, 63235], event.keyCode) > -1) {
279 // Move to the right if the next group is not a placeholder.
280 if (!$siblings.eq(index + 1).hasClass('placeholder')) {
281 $group.insertAfter($container.children().eq(index + 1));
282 }
283 // Wrap group between rows.
146 else { 284 else {
147 $availableButtons.prepend($button); 285 $container
148 } 286 .closest('.ckeditor-row')
149 } 287 .next()
150 else { 288 .find('.ckeditor-toolbar-groups')
151 $row.find('.ckeditor-toolbar-group-buttons').eq(0).prepend($button); 289 .prepend($group);
290 }
152 } 291 }
153 } 292 }
293 // Move groups between rows.
294 else if (_.indexOf(upDownKeys, event.keyCode) > -1) {
295 dir = _.indexOf([38, 63232], event.keyCode) > -1 ? 'prev' : 'next';
296 $group
297 .closest('.ckeditor-row')
298 [dir]()
299 .find('.ckeditor-toolbar-groups')
300 .eq(0)
301 .prepend($group);
302 }
303
304 Drupal.ckeditor.registerGroupMove(this, $group);
305 $group.trigger('focus');
306 event.preventDefault();
307 event.stopPropagation();
154 } 308 }
155 // Move dividers between their container and the active toolbar. 309 },
156 else if (containerType === 'dividers') {
157 // Move the button to the active toolbar configuration when the down
158 // or up keys are pressed.
159 if (_.indexOf([40, 63233], event.keyCode) > -1) {
160 // Move the button to the first row, first button group index
161 // position.
162 $button = $button.clone(true);
163 $activeButtons.find('.ckeditor-toolbar-group-buttons').eq(0).prepend($button);
164 $target = $button.children();
165 }
166 }
167
168 view = this;
169 // Attempt to move the button to the new toolbar position.
170 Drupal.ckeditor.registerButtonMove(this, $button, (result) => {
171 // Put the button back if the registration failed.
172 // If the button was in a row, then it was in the active toolbar
173 // configuration. The button was probably placed in a new group, but
174 // that action was canceled.
175 if (!result && $originalGroup) {
176 $originalGroup.find('.ckeditor-buttons').append($button);
177 }
178 // Otherwise refresh the sortables to acknowledge the new button
179 // positions.
180 else {
181 view.$el.find('.ui-sortable').sortable('refresh');
182 }
183 // Refocus the target button so that the user can continue from a
184 // known place.
185 $target.trigger('focus');
186 });
187
188 event.preventDefault();
189 event.stopPropagation();
190 }
191 }, 310 },
192 311 );
193 /** 312 })(jQuery, Drupal, Backbone, _);
194 * Handles keypresses on a CKEditor configuration group.
195 *
196 * @param {jQuery.Event} event
197 * The keypress event triggered.
198 */
199 onPressGroup(event) {
200 const upDownKeys = [
201 38, // Up arrow.
202 63232, // Safari up arrow.
203 40, // Down arrow.
204 63233, // Safari down arrow.
205 ];
206 const leftRightKeys = [
207 37, // Left arrow.
208 63234, // Safari left arrow.
209 39, // Right arrow.
210 63235, // Safari right arrow.
211 ];
212
213 // Respond to an enter key press.
214 if (event.keyCode === 13) {
215 const view = this;
216 // Open the group renaming dialog in the next evaluation cycle so that
217 // this event can be cancelled and the bubbling wiped out. Otherwise,
218 // Firefox has issues because the page focus is shifted to the dialog
219 // along with the keydown event.
220 window.setTimeout(() => {
221 Drupal.ckeditor.openGroupNameDialog(view, $(event.currentTarget));
222 }, 0);
223 event.preventDefault();
224 event.stopPropagation();
225 }
226
227 // Respond to direction key presses.
228 if (_.indexOf(_.union(upDownKeys, leftRightKeys), event.keyCode) > -1) {
229 const $group = $(event.currentTarget);
230 const $container = $group.parent();
231 const $siblings = $container.children();
232 let index;
233 let dir;
234 // Move groups between sibling groups.
235 if (_.indexOf(leftRightKeys, event.keyCode) > -1) {
236 index = $siblings.index($group);
237 // Move left between sibling groups.
238 if ((_.indexOf([37, 63234], event.keyCode) > -1)) {
239 if (index > 0) {
240 $group.insertBefore($siblings.eq(index - 1));
241 }
242 // Wrap between rows. Insert the group before the placeholder group
243 // at the end of the previous row.
244 else {
245 const $rowChildElement = $container
246 .closest('.ckeditor-row')
247 .prev()
248 .find('.ckeditor-toolbar-groups')
249 .children()
250 .eq(-1);
251 $group.insertBefore($rowChildElement);
252 }
253 }
254 // Move right between sibling groups.
255 else if (_.indexOf([39, 63235], event.keyCode) > -1) {
256 // Move to the right if the next group is not a placeholder.
257 if (!$siblings.eq(index + 1).hasClass('placeholder')) {
258 $group.insertAfter($container.children().eq(index + 1));
259 }
260 // Wrap group between rows.
261 else {
262 $container.closest('.ckeditor-row').next().find('.ckeditor-toolbar-groups').prepend($group);
263 }
264 }
265 }
266 // Move groups between rows.
267 else if (_.indexOf(upDownKeys, event.keyCode) > -1) {
268 dir = (_.indexOf([38, 63232], event.keyCode) > -1) ? 'prev' : 'next';
269 $group
270 .closest('.ckeditor-row')[dir]()
271 .find('.ckeditor-toolbar-groups')
272 .eq(0)
273 .prepend($group);
274 }
275
276 Drupal.ckeditor.registerGroupMove(this, $group);
277 $group.trigger('focus');
278 event.preventDefault();
279 event.stopPropagation();
280 }
281 },
282 });
283 }(jQuery, Drupal, Backbone, _));