]> git.wh0rd.org Git - tt-rss.git/blob - lib/dijit/_KeyNavContainer.js.uncompressed.js
update dojo to 1.7.3
[tt-rss.git] / lib / dijit / _KeyNavContainer.js.uncompressed.js
1 define("dijit/_KeyNavContainer", [
2         "dojo/_base/kernel", // kernel.deprecated
3         "./_Container",
4         "./_FocusMixin",
5         "dojo/_base/array", // array.forEach
6         "dojo/keys", // keys.END keys.HOME
7         "dojo/_base/declare", // declare
8         "dojo/_base/event", // event.stop
9         "dojo/dom-attr", // domAttr.set
10         "dojo/_base/lang" // lang.hitch
11 ], function(kernel, _Container, _FocusMixin, array, keys, declare, event, domAttr, lang){
12
13 /*=====
14         var _FocusMixin = dijit._FocusMixin;
15         var _Container = dijit._Container;
16 =====*/
17
18         // module:
19         //              dijit/_KeyNavContainer
20         // summary:
21         //              A _Container with keyboard navigation of its children.
22
23         return declare("dijit._KeyNavContainer", [_FocusMixin, _Container], {
24
25                 // summary:
26                 //              A _Container with keyboard navigation of its children.
27                 // description:
28                 //              To use this mixin, call connectKeyNavHandlers() in
29                 //              postCreate().
30                 //              It provides normalized keyboard and focusing code for Container
31                 //              widgets.
32
33 /*=====
34                 // focusedChild: [protected] Widget
35                 //              The currently focused child widget, or null if there isn't one
36                 focusedChild: null,
37 =====*/
38
39                 // tabIndex: Integer
40                 //              Tab index of the container; same as HTML tabIndex attribute.
41                 //              Note then when user tabs into the container, focus is immediately
42                 //              moved to the first item in the container.
43                 tabIndex: "0",
44
45                 connectKeyNavHandlers: function(/*keys[]*/ prevKeyCodes, /*keys[]*/ nextKeyCodes){
46                         // summary:
47                         //              Call in postCreate() to attach the keyboard handlers
48                         //              to the container.
49                         // preKeyCodes: keys[]
50                         //              Key codes for navigating to the previous child.
51                         // nextKeyCodes: keys[]
52                         //              Key codes for navigating to the next child.
53                         // tags:
54                         //              protected
55
56                         // TODO: call this automatically from my own postCreate()
57
58                         var keyCodes = (this._keyNavCodes = {});
59                         var prev = lang.hitch(this, "focusPrev");
60                         var next = lang.hitch(this, "focusNext");
61                         array.forEach(prevKeyCodes, function(code){ keyCodes[code] = prev; });
62                         array.forEach(nextKeyCodes, function(code){ keyCodes[code] = next; });
63                         keyCodes[keys.HOME] = lang.hitch(this, "focusFirstChild");
64                         keyCodes[keys.END] = lang.hitch(this, "focusLastChild");
65                         this.connect(this.domNode, "onkeypress", "_onContainerKeypress");
66                         this.connect(this.domNode, "onfocus", "_onContainerFocus");
67                 },
68
69                 startupKeyNavChildren: function(){
70                         kernel.deprecated("startupKeyNavChildren() call no longer needed", "", "2.0");
71                 },
72
73                 startup: function(){
74                         this.inherited(arguments);
75                         array.forEach(this.getChildren(), lang.hitch(this, "_startupChild"));
76                 },
77
78                 addChild: function(/*dijit._Widget*/ widget, /*int?*/ insertIndex){
79                         this.inherited(arguments);
80                         this._startupChild(widget);
81                 },
82
83                 focus: function(){
84                         // summary:
85                         //              Default focus() implementation: focus the first child.
86                         this.focusFirstChild();
87                 },
88
89                 focusFirstChild: function(){
90                         // summary:
91                         //              Focus the first focusable child in the container.
92                         // tags:
93                         //              protected
94                         this.focusChild(this._getFirstFocusableChild());
95                 },
96
97                 focusLastChild: function(){
98                         // summary:
99                         //              Focus the last focusable child in the container.
100                         // tags:
101                         //              protected
102                         this.focusChild(this._getLastFocusableChild());
103                 },
104
105                 focusNext: function(){
106                         // summary:
107                         //              Focus the next widget
108                         // tags:
109                         //              protected
110                         this.focusChild(this._getNextFocusableChild(this.focusedChild, 1));
111                 },
112
113                 focusPrev: function(){
114                         // summary:
115                         //              Focus the last focusable node in the previous widget
116                         //              (ex: go to the ComboButton icon section rather than button section)
117                         // tags:
118                         //              protected
119                         this.focusChild(this._getNextFocusableChild(this.focusedChild, -1), true);
120                 },
121
122                 focusChild: function(/*dijit._Widget*/ widget, /*Boolean*/ last){
123                         // summary:
124                         //              Focus specified child widget.
125                         // widget:
126                         //              Reference to container's child widget
127                         // last:
128                         //              If true and if widget has multiple focusable nodes, focus the
129                         //              last one instead of the first one
130                         // tags:
131                         //              protected
132
133                         if(!widget){ return; }
134
135                         if(this.focusedChild && widget !== this.focusedChild){
136                                 this._onChildBlur(this.focusedChild);   // used by _MenuBase
137                         }
138                         widget.set("tabIndex", this.tabIndex);  // for IE focus outline to appear, must set tabIndex before focs
139                         widget.focus(last ? "end" : "start");
140                         this._set("focusedChild", widget);
141                 },
142
143                 _startupChild: function(/*dijit._Widget*/ widget){
144                         // summary:
145                         //              Setup for each child widget
146                         // description:
147                         //              Sets tabIndex=-1 on each child, so that the tab key will
148                         //              leave the container rather than visiting each child.
149                         // tags:
150                         //              private
151
152                         widget.set("tabIndex", "-1");
153
154                         this.connect(widget, "_onFocus", function(){
155                                 // Set valid tabIndex so tabbing away from widget goes to right place, see #10272
156                                 widget.set("tabIndex", this.tabIndex);
157                         });
158                         this.connect(widget, "_onBlur", function(){
159                                 widget.set("tabIndex", "-1");
160                         });
161                 },
162
163                 _onContainerFocus: function(evt){
164                         // summary:
165                         //              Handler for when the container gets focus
166                         // description:
167                         //              Initially the container itself has a tabIndex, but when it gets
168                         //              focus, switch focus to first child...
169                         // tags:
170                         //              private
171
172                         // Note that we can't use _onFocus() because switching focus from the
173                         // _onFocus() handler confuses the focus.js code
174                         // (because it causes _onFocusNode() to be called recursively)
175                         // Also, _onFocus() would fire when focus went directly to a child widget due to mouse click.
176
177                         // Ignore spurious focus events:
178                         //      1. focus on a child widget bubbles on FF
179                         //      2. on IE, clicking the scrollbar of a select dropdown moves focus from the focused child item to me
180                         if(evt.target !== this.domNode || this.focusedChild){ return; }
181
182                         this.focusFirstChild();
183
184                         // and then set the container's tabIndex to -1,
185                         // (don't remove as that breaks Safari 4)
186                         // so that tab or shift-tab will go to the fields after/before
187                         // the container, rather than the container itself
188                         domAttr.set(this.domNode, "tabIndex", "-1");
189                 },
190
191                 _onBlur: function(evt){
192                         // When focus is moved away the container, and its descendant (popup) widgets,
193                         // then restore the container's tabIndex so that user can tab to it again.
194                         // Note that using _onBlur() so that this doesn't happen when focus is shifted
195                         // to one of my child widgets (typically a popup)
196                         if(this.tabIndex){
197                                 domAttr.set(this.domNode, "tabIndex", this.tabIndex);
198                         }
199                         this.focusedChild = null;
200                         this.inherited(arguments);
201                 },
202
203                 _onContainerKeypress: function(evt){
204                         // summary:
205                         //              When a key is pressed, if it's an arrow key etc. then
206                         //              it's handled here.
207                         // tags:
208                         //              private
209                         if(evt.ctrlKey || evt.altKey){ return; }
210                         var func = this._keyNavCodes[evt.charOrCode];
211                         if(func){
212                                 func();
213                                 event.stop(evt);
214                         }
215                 },
216
217                 _onChildBlur: function(/*dijit._Widget*/ /*===== widget =====*/){
218                         // summary:
219                         //              Called when focus leaves a child widget to go
220                         //              to a sibling widget.
221                         //              Used by MenuBase.js (TODO: move code there)
222                         // tags:
223                         //              protected
224                 },
225
226                 _getFirstFocusableChild: function(){
227                         // summary:
228                         //              Returns first child that can be focused
229                         return this._getNextFocusableChild(null, 1);    // dijit._Widget
230                 },
231
232                 _getLastFocusableChild: function(){
233                         // summary:
234                         //              Returns last child that can be focused
235                         return this._getNextFocusableChild(null, -1);   // dijit._Widget
236                 },
237
238                 _getNextFocusableChild: function(child, dir){
239                         // summary:
240                         //              Returns the next or previous focusable child, compared
241                         //              to "child"
242                         // child: Widget
243                         //              The current widget
244                         // dir: Integer
245                         //              * 1 = after
246                         //              * -1 = before
247                         if(child){
248                                 child = this._getSiblingOfChild(child, dir);
249                         }
250                         var children = this.getChildren();
251                         for(var i=0; i < children.length; i++){
252                                 if(!child){
253                                         child = children[(dir>0) ? 0 : (children.length-1)];
254                                 }
255                                 if(child.isFocusable()){
256                                         return child;   // dijit._Widget
257                                 }
258                                 child = this._getSiblingOfChild(child, dir);
259                         }
260                         // no focusable child found
261                         return null;    // dijit._Widget
262                 }
263         });
264 });