2 * KeyboardNavigation.js
4 * Copyright 2011, Moxiecode Systems AB
5 * Released under LGPL License.
7 * License: http://tinymce.moxiecode.com/license
8 * Contributing: http://tinymce.moxiecode.com/contributing
12 var Event = tinymce.dom.Event, each = tinymce.each;
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.
18 * @class tinymce.ui.KeyboardNavigation
20 tinymce.create('tinymce.ui.KeyboardNavigation', {
22 * Create a new KeyboardNavigation instance to handle the focus for a specific element.
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.
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.
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;
43 dom = dom || tinymce.DOM;
45 itemFocussed = function(evt) {
46 focussedId = evt.target.id;
49 itemBlurred = function(evt) {
50 dom.setAttrib(evt.target.id, 'tabindex', '-1');
53 rootFocussed = function(evt) {
54 var item = dom.get(focussedId);
55 dom.setAttrib(item, 'tabindex', '0');
59 t.focus = function() {
60 dom.get(focussedId).focus();
64 * Destroys the KeyboardNavigation and unbinds any focus/blur event handles it might have added.
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);
74 dom.unbind(dom.get(root), 'focus', rootFocussed);
75 dom.unbind(dom.get(root), 'keydown', rootKeydown);
77 items = dom = root = t.focus = itemFocussed = itemBlurred = rootKeydown = rootFocussed = null;
78 t.destroy = function() {};
81 t.moveFocus = function(dir, evt) {
82 var idx = -1, controls = t.controls, newFocus;
87 each(items, function(item, index) {
88 if (item.id === focussedId) {
96 idx = items.length - 1;
97 } else if (idx >= items.length) {
101 newFocus = items[idx];
102 dom.setAttrib(focussedId, 'tabindex', '-1');
103 dom.setAttrib(newFocus.id, 'tabindex', '0');
104 dom.get(newFocus.id).focus();
106 if (settings.actOnFocus) {
107 settings.onAction(newFocus.id);
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;
117 switch (evt.keyCode) {
119 if (enableLeftRight) t.moveFocus(-1);
123 if (enableLeftRight) t.moveFocus(1);
127 if (enableUpDown) t.moveFocus(-1);
131 if (enableUpDown) t.moveFocus(1);
135 if (settings.onCancel) {
144 if (settings.onAction) {
145 settings.onAction(focussedId);
152 // Set up state and listeners for each item.
153 each(items, function(item, idx) {
157 item.id = dom.uniqueId('_mce_item_');
160 if (excludeFromTabOrder) {
161 dom.bind(item.id, 'blur', itemBlurred);
164 tabindex = (idx === 0 ? '0' : '-1');
167 dom.setAttrib(item.id, 'tabindex', tabindex);
168 dom.bind(dom.get(item.id), 'focus', itemFocussed);
171 // Setup initial state for root element.
173 focussedId = items[0].id;
176 dom.setAttrib(root, 'tabindex', '-1');
178 // Setup listeners for root element.
179 dom.bind(dom.get(root), 'focus', rootFocussed);
180 dom.bind(dom.get(root), 'keydown', rootKeydown);