]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/javascript/tiny_mce/classes/ui/KeyboardNavigation.js
Release 6.5.0
[Github/sugarcrm.git] / include / javascript / tiny_mce / classes / ui / KeyboardNavigation.js
1 /**
2  * KeyboardNavigation.js
3  *
4  * Copyright 2011, Moxiecode Systems AB
5  * Released under LGPL License.
6  *
7  * License: http://tinymce.moxiecode.com/license
8  * Contributing: http://tinymce.moxiecode.com/contributing
9  */
10
11 (function(tinymce) {
12         var Event = tinymce.dom.Event, each = tinymce.each;
13
14         /**
15          * This class provides basic keyboard navigation using the arrow keys to children of a component.
16          * For example, this class handles moving between the buttons on the toolbars. 
17          * 
18          * @class tinymce.ui.KeyboardNavigation
19          */
20         tinymce.create('tinymce.ui.KeyboardNavigation', {
21                 /**
22                  * Create a new KeyboardNavigation instance to handle the focus for a specific element.
23                  * 
24                  * @constructor
25                  * @method KeyboardNavigation
26                  * @param {Object} settings the settings object to define how keyboard navigation works.
27                  * @param {DOMUtils} dom the DOMUtils instance to use.
28                  * 
29                  * @setting {Element/String} root the root element or ID of the root element for the control.
30                  * @setting {Array} items an array containing the items to move focus between. Every object in this array must have an id attribute which maps to the actual DOM element. If the actual elements are passed without an ID then one is automatically assigned.
31                  * @setting {Function} onCancel the callback for when the user presses escape or otherwise indicates cancelling.
32                  * @setting {Function} onAction (optional) the action handler to call when the user activates an item.
33                  * @setting {Boolean} enableLeftRight (optional, default) when true, the up/down arrows move through items.
34                  * @setting {Boolean} enableUpDown (optional) when true, the up/down arrows move through items.
35                  * Note for both up/down and left/right explicitly set both enableLeftRight and enableUpDown to true.
36                  */
37                 KeyboardNavigation: function(settings, dom) {
38                         var t = this, root = settings.root, items = settings.items,
39                                         enableUpDown = settings.enableUpDown, enableLeftRight = settings.enableLeftRight || !settings.enableUpDown,
40                                         excludeFromTabOrder = settings.excludeFromTabOrder,
41                                         itemFocussed, itemBlurred, rootKeydown, rootFocussed, focussedId;
42
43                         dom = dom || tinymce.DOM;
44
45                         itemFocussed = function(evt) {
46                                 focussedId = evt.target.id;
47                         };
48                         
49                         itemBlurred = function(evt) {
50                                 dom.setAttrib(evt.target.id, 'tabindex', '-1');
51                         };
52                         
53                         rootFocussed = function(evt) {
54                                 var item = dom.get(focussedId);
55                                 dom.setAttrib(item, 'tabindex', '0');
56                                 item.focus();
57                         };
58                         
59                         t.focus = function() {
60                                 dom.get(focussedId).focus();
61                         };
62
63                         /**
64                          * Destroys the KeyboardNavigation and unbinds any focus/blur event handles it might have added.
65                          *
66                          * @method destroy
67                          */
68                         t.destroy = function() {
69                                 each(items, function(item) {
70                                         dom.unbind(dom.get(item.id), 'focus', itemFocussed);
71                                         dom.unbind(dom.get(item.id), 'blur', itemBlurred);
72                                 });
73
74                                 dom.unbind(dom.get(root), 'focus', rootFocussed);
75                                 dom.unbind(dom.get(root), 'keydown', rootKeydown);
76
77                                 items = dom = root = t.focus = itemFocussed = itemBlurred = rootKeydown = rootFocussed = null;
78                                 t.destroy = function() {};
79                         };
80                         
81                         t.moveFocus = function(dir, evt) {
82                                 var idx = -1, controls = t.controls, newFocus;
83
84                                 if (!focussedId)
85                                         return;
86
87                                 each(items, function(item, index) {
88                                         if (item.id === focussedId) {
89                                                 idx = index;
90                                                 return false;
91                                         }
92                                 });
93
94                                 idx += dir;
95                                 if (idx < 0) {
96                                         idx = items.length - 1;
97                                 } else if (idx >= items.length) {
98                                         idx = 0;
99                                 }
100                                 
101                                 newFocus = items[idx];
102                                 dom.setAttrib(focussedId, 'tabindex', '-1');
103                                 dom.setAttrib(newFocus.id, 'tabindex', '0');
104                                 dom.get(newFocus.id).focus();
105
106                                 if (settings.actOnFocus) {
107                                         settings.onAction(newFocus.id);
108                                 }
109
110                                 if (evt)
111                                         Event.cancel(evt);
112                         };
113                         
114                         rootKeydown = function(evt) {
115                                 var DOM_VK_LEFT = 37, DOM_VK_RIGHT = 39, DOM_VK_UP = 38, DOM_VK_DOWN = 40, DOM_VK_ESCAPE = 27, DOM_VK_ENTER = 14, DOM_VK_RETURN = 13, DOM_VK_SPACE = 32;
116                                 
117                                 switch (evt.keyCode) {
118                                         case DOM_VK_LEFT:
119                                                 if (enableLeftRight) t.moveFocus(-1);
120                                                 break;
121         
122                                         case DOM_VK_RIGHT:
123                                                 if (enableLeftRight) t.moveFocus(1);
124                                                 break;
125         
126                                         case DOM_VK_UP:
127                                                 if (enableUpDown) t.moveFocus(-1);
128                                                 break;
129
130                                         case DOM_VK_DOWN:
131                                                 if (enableUpDown) t.moveFocus(1);
132                                                 break;
133
134                                         case DOM_VK_ESCAPE:
135                                                 if (settings.onCancel) {
136                                                         settings.onCancel();
137                                                         Event.cancel(evt);
138                                                 }
139                                                 break;
140
141                                         case DOM_VK_ENTER:
142                                         case DOM_VK_RETURN:
143                                         case DOM_VK_SPACE:
144                                                 if (settings.onAction) {
145                                                         settings.onAction(focussedId);
146                                                         Event.cancel(evt);
147                                                 }
148                                                 break;
149                                 }
150                         };
151
152                         // Set up state and listeners for each item.
153                         each(items, function(item, idx) {
154                                 var tabindex;
155
156                                 if (!item.id) {
157                                         item.id = dom.uniqueId('_mce_item_');
158                                 }
159
160                                 if (excludeFromTabOrder) {
161                                         dom.bind(item.id, 'blur', itemBlurred);
162                                         tabindex = '-1';
163                                 } else {
164                                         tabindex = (idx === 0 ? '0' : '-1');
165                                 }
166
167                                 dom.setAttrib(item.id, 'tabindex', tabindex);
168                                 dom.bind(dom.get(item.id), 'focus', itemFocussed);
169                         });
170                         
171                         // Setup initial state for root element.
172                         if (items[0]){
173                                 focussedId = items[0].id;
174                         }
175
176                         dom.setAttrib(root, 'tabindex', '-1');
177                         
178                         // Setup listeners for root element.
179                         dom.bind(dom.get(root), 'focus', rootFocussed);
180                         dom.bind(dom.get(root), 'keydown', rootKeydown);
181                 }
182         });
183 })(tinymce);