]>
git.wh0rd.org - tt-rss.git/blob - lib/dijit/_KeyNavContainer.js.uncompressed.js
1 define("dijit/_KeyNavContainer", [
2 "dojo/_base/kernel", // kernel.deprecated
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
){
14 var _FocusMixin = dijit._FocusMixin;
15 var _Container = dijit._Container;
19 // dijit/_KeyNavContainer
21 // A _Container with keyboard navigation of its children.
23 return declare("dijit._KeyNavContainer", [_FocusMixin
, _Container
], {
26 // A _Container with keyboard navigation of its children.
28 // To use this mixin, call connectKeyNavHandlers() in
30 // It provides normalized keyboard and focusing code for Container
34 // focusedChild: [protected] Widget
35 // The currently focused child widget, or null if there isn't one
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.
45 connectKeyNavHandlers: function(/*keys[]*/ prevKeyCodes
, /*keys[]*/ nextKeyCodes
){
47 // Call in postCreate() to attach the keyboard handlers
49 // preKeyCodes: keys[]
50 // Key codes for navigating to the previous child.
51 // nextKeyCodes: keys[]
52 // Key codes for navigating to the next child.
56 // TODO: call this automatically from my own postCreate()
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");
69 startupKeyNavChildren: function(){
70 kernel
.deprecated("startupKeyNavChildren() call no longer needed", "", "2.0");
74 this.inherited(arguments
);
75 array
.forEach(this.getChildren(), lang
.hitch(this, "_startupChild"));
78 addChild: function(/*dijit._Widget*/ widget
, /*int?*/ insertIndex
){
79 this.inherited(arguments
);
80 this._startupChild(widget
);
85 // Default focus() implementation: focus the first child.
86 this.focusFirstChild();
89 focusFirstChild: function(){
91 // Focus the first focusable child in the container.
94 this.focusChild(this._getFirstFocusableChild());
97 focusLastChild: function(){
99 // Focus the last focusable child in the container.
102 this.focusChild(this._getLastFocusableChild());
105 focusNext: function(){
107 // Focus the next widget
110 this.focusChild(this._getNextFocusableChild(this.focusedChild
, 1));
113 focusPrev: function(){
115 // Focus the last focusable node in the previous widget
116 // (ex: go to the ComboButton icon section rather than button section)
119 this.focusChild(this._getNextFocusableChild(this.focusedChild
, -1), true);
122 focusChild: function(/*dijit._Widget*/ widget
, /*Boolean*/ last
){
124 // Focus specified child widget.
126 // Reference to container's child widget
128 // If true and if widget has multiple focusable nodes, focus the
129 // last one instead of the first one
133 if(!widget
){ return; }
135 if(this.focusedChild
&& widget
!== this.focusedChild
){
136 this._onChildBlur(this.focusedChild
); // used by _MenuBase
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
);
143 _startupChild: function(/*dijit._Widget*/ widget
){
145 // Setup for each child widget
147 // Sets tabIndex=-1 on each child, so that the tab key will
148 // leave the container rather than visiting each child.
152 widget
.set("tabIndex", "-1");
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
);
158 this.connect(widget
, "_onBlur", function(){
159 widget
.set("tabIndex", "-1");
163 _onContainerFocus: function(evt
){
165 // Handler for when the container gets focus
167 // Initially the container itself has a tabIndex, but when it gets
168 // focus, switch focus to first child...
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.
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; }
182 this.focusFirstChild();
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");
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)
197 domAttr
.set(this.domNode
, "tabIndex", this.tabIndex
);
199 this.focusedChild
= null;
200 this.inherited(arguments
);
203 _onContainerKeypress: function(evt
){
205 // When a key is pressed, if it's an arrow key etc. then
206 // it's handled here.
209 if(evt
.ctrlKey
|| evt
.altKey
){ return; }
210 var func
= this._keyNavCodes
[evt
.charOrCode
];
217 _onChildBlur: function(/*dijit._Widget*/ /*===== widget =====*/){
219 // Called when focus leaves a child widget to go
220 // to a sibling widget.
221 // Used by MenuBase.js (TODO: move code there)
226 _getFirstFocusableChild: function(){
228 // Returns first child that can be focused
229 return this._getNextFocusableChild(null, 1); // dijit._Widget
232 _getLastFocusableChild: function(){
234 // Returns last child that can be focused
235 return this._getNextFocusableChild(null, -1); // dijit._Widget
238 _getNextFocusableChild: function(child
, dir
){
240 // Returns the next or previous focusable child, compared
243 // The current widget
248 child
= this._getSiblingOfChild(child
, dir
);
250 var children
= this.getChildren();
251 for(var i
=0; i
< children
.length
; i
++){
253 child
= children
[(dir
>0) ? 0 : (children
.length
-1)];
255 if(child
.isFocusable()){
256 return child
; // dijit._Widget
258 child
= this._getSiblingOfChild(child
, dir
);
260 // no focusable child found
261 return null; // dijit._Widget