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