]>
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
){
15 // dijit/_KeyNavContainer
17 return declare("dijit._KeyNavContainer", [_FocusMixin
, _Container
], {
19 // A _Container with keyboard navigation of its children.
21 // To use this mixin, call connectKeyNavHandlers() in
23 // It provides normalized keyboard and focusing code for Container
27 // focusedChild: [protected] Widget
28 // The currently focused child widget, or null if there isn't one
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.
38 connectKeyNavHandlers: function(/*keys[]*/ prevKeyCodes
, /*keys[]*/ nextKeyCodes
){
40 // Call in postCreate() to attach the keyboard handlers
42 // preKeyCodes: keys[]
43 // Key codes for navigating to the previous child.
44 // nextKeyCodes: keys[]
45 // Key codes for navigating to the next child.
49 // TODO: call this automatically from my own postCreate()
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");
62 startupKeyNavChildren: function(){
63 kernel
.deprecated("startupKeyNavChildren() call no longer needed", "", "2.0");
67 this.inherited(arguments
);
68 array
.forEach(this.getChildren(), lang
.hitch(this, "_startupChild"));
71 addChild: function(/*dijit/_WidgetBase*/ widget, /*int?*/ insertIndex
){
72 this.inherited(arguments
);
73 this._startupChild(widget
);
78 // Default focus() implementation: focus the first child.
79 this.focusFirstChild();
82 focusFirstChild: function(){
84 // Focus the first focusable child in the container.
87 this.focusChild(this._getFirstFocusableChild());
90 focusLastChild: function(){
92 // Focus the last focusable child in the container.
95 this.focusChild(this._getLastFocusableChild());
98 focusNext: function(){
100 // Focus the next widget
103 this.focusChild(this._getNextFocusableChild(this.focusedChild
, 1));
106 focusPrev: function(){
108 // Focus the last focusable node in the previous widget
109 // (ex: go to the ComboButton icon section rather than button section)
112 this.focusChild(this._getNextFocusableChild(this.focusedChild
, -1), true);
115 focusChild: function(/*dijit/_WidgetBase*/ widget, /*Boolean*/ last
){
117 // Focus specified child widget.
119 // Reference to container's child widget
121 // If true and if widget has multiple focusable nodes, focus the
122 // last one instead of the first one
126 if(!widget
){ return; }
128 if(this.focusedChild
&& widget
!== this.focusedChild
){
129 this._onChildBlur(this.focusedChild
); // used by _MenuBase
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
);
136 _startupChild: function(/*dijit/_WidgetBase*/ widget){
138 // Setup for each child widget
140 // Sets tabIndex=-1 on each child, so that the tab key will
141 // leave the container rather than visiting each child.
145 widget.set("tabIndex", "-1");
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);
151 this.connect(widget, "_onBlur", function(){
152 widget.set("tabIndex", "-1");
156 _onContainerFocus: function(evt){
158 // Handler for when the container gets focus
160 // Initially the container itself has a tabIndex, but when it gets
161 // focus, switch focus to first child...
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.
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; }
175 this.focusFirstChild();
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");
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)
190 domAttr.set(this.domNode, "tabIndex", this.tabIndex);
192 this.focusedChild = null;
193 this.inherited(arguments);
196 _onContainerKeypress: function(evt){
198 // When a key is pressed, if it's an arrow key etc. then
199 // it's handled here.
202 if(evt.ctrlKey || evt.altKey){ return; }
203 var func = this._keyNavCodes[evt.charOrCode];
210 _onChildBlur: function(/*dijit/_WidgetBase*/ /*===== widget =====*/){
212 // Called when focus leaves a child widget to go
213 // to a sibling widget.
214 // Used by MenuBase.js (TODO: move code there)
219 _getFirstFocusableChild: function(){
221 // Returns first child that can be focused
222 return this._getNextFocusableChild(null, 1); // dijit/_WidgetBase
225 _getLastFocusableChild: function(){
227 // Returns last child that can be focused
228 return this._getNextFocusableChild(null, -1); // dijit/_WidgetBase
231 _getNextFocusableChild: function(child
, dir
){
233 // Returns the next or previous focusable child, compared
236 // The current widget
241 child
= this._getSiblingOfChild(child
, dir
);
243 var children
= this.getChildren();
244 for(var i
=0; i
< children
.length
; i
++){
246 child
= children
[(dir
>0) ? 0 : (children
.length
-1)];
248 if(child
.isFocusable()){
249 return child
; // dijit/_WidgetBase
251 child
= this._getSiblingOfChild(child
, dir
);
253 // no focusable child found
254 return null; // dijit/_WidgetBase