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