Mercurial > hg > cmmr2012-drupal-site
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, _)); |