summaryrefslogtreecommitdiff
path: root/lib/dijit/_KeyNavContainer.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dijit/_KeyNavContainer.js')
-rw-r--r--lib/dijit/_KeyNavContainer.js338
1 files changed, 252 insertions, 86 deletions
diff --git a/lib/dijit/_KeyNavContainer.js b/lib/dijit/_KeyNavContainer.js
index 839ba8319..aa1bcad4b 100644
--- a/lib/dijit/_KeyNavContainer.js
+++ b/lib/dijit/_KeyNavContainer.js
@@ -1,95 +1,261 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
-if(!dojo._hasResource["dijit._KeyNavContainer"]){
-dojo._hasResource["dijit._KeyNavContainer"]=true;
+if(!dojo._hasResource["dijit._KeyNavContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._KeyNavContainer"] = true;
dojo.provide("dijit._KeyNavContainer");
dojo.require("dijit._Container");
-dojo.declare("dijit._KeyNavContainer",dijit._Container,{tabIndex:"0",_keyNavCodes:{},connectKeyNavHandlers:function(_1,_2){
-var _3=(this._keyNavCodes={});
-var _4=dojo.hitch(this,this.focusPrev);
-var _5=dojo.hitch(this,this.focusNext);
-dojo.forEach(_1,function(_6){
-_3[_6]=_4;
-});
-dojo.forEach(_2,function(_7){
-_3[_7]=_5;
-});
-this.connect(this.domNode,"onkeypress","_onContainerKeypress");
-this.connect(this.domNode,"onfocus","_onContainerFocus");
-},startupKeyNavChildren:function(){
-dojo.forEach(this.getChildren(),dojo.hitch(this,"_startupChild"));
-},addChild:function(_8,_9){
-dijit._KeyNavContainer.superclass.addChild.apply(this,arguments);
-this._startupChild(_8);
-},focus:function(){
-this.focusFirstChild();
-},focusFirstChild:function(){
-var _a=this._getFirstFocusableChild();
-if(_a){
-this.focusChild(_a);
-}
-},focusNext:function(){
-var _b=this._getNextFocusableChild(this.focusedChild,1);
-this.focusChild(_b);
-},focusPrev:function(){
-var _c=this._getNextFocusableChild(this.focusedChild,-1);
-this.focusChild(_c,true);
-},focusChild:function(_d,_e){
-if(this.focusedChild&&_d!==this.focusedChild){
-this._onChildBlur(this.focusedChild);
-}
-_d.focus(_e?"end":"start");
-this.focusedChild=_d;
-},_startupChild:function(_f){
-_f.set("tabIndex","-1");
-this.connect(_f,"_onFocus",function(){
-_f.set("tabIndex",this.tabIndex);
-});
-this.connect(_f,"_onBlur",function(){
-_f.set("tabIndex","-1");
-});
-},_onContainerFocus:function(evt){
-if(evt.target!==this.domNode){
-return;
-}
-this.focusFirstChild();
-dojo.attr(this.domNode,"tabIndex","-1");
-},_onBlur:function(evt){
-if(this.tabIndex){
-dojo.attr(this.domNode,"tabIndex",this.tabIndex);
-}
-this.inherited(arguments);
-},_onContainerKeypress:function(evt){
-if(evt.ctrlKey||evt.altKey){
-return;
-}
-var _10=this._keyNavCodes[evt.charOrCode];
-if(_10){
-_10();
-dojo.stopEvent(evt);
-}
-},_onChildBlur:function(_11){
-},_getFirstFocusableChild:function(){
-return this._getNextFocusableChild(null,1);
-},_getNextFocusableChild:function(_12,dir){
-if(_12){
-_12=this._getSiblingOfChild(_12,dir);
-}
-var _13=this.getChildren();
-for(var i=0;i<_13.length;i++){
-if(!_12){
-_12=_13[(dir>0)?0:(_13.length-1)];
-}
-if(_12.isFocusable()){
-return _12;
-}
-_12=this._getSiblingOfChild(_12,dir);
-}
-return null;
-}});
+
+
+dojo.declare("dijit._KeyNavContainer",
+ dijit._Container,
+ {
+
+ // summary:
+ // A _Container with keyboard navigation of its children.
+ // description:
+ // To use this mixin, call connectKeyNavHandlers() in
+ // postCreate() and call startupKeyNavChildren() in startup().
+ // It provides normalized keyboard and focusing code for Container
+ // widgets.
+/*=====
+ // focusedChild: [protected] Widget
+ // The currently focused child widget, or null if there isn't one
+ focusedChild: null,
+=====*/
+
+ // tabIndex: Integer
+ // Tab index of the container; same as HTML tabIndex attribute.
+ // Note then when user tabs into the container, focus is immediately
+ // moved to the first item in the container.
+ tabIndex: "0",
+
+ _keyNavCodes: {},
+
+ connectKeyNavHandlers: function(/*dojo.keys[]*/ prevKeyCodes, /*dojo.keys[]*/ nextKeyCodes){
+ // summary:
+ // Call in postCreate() to attach the keyboard handlers
+ // to the container.
+ // preKeyCodes: dojo.keys[]
+ // Key codes for navigating to the previous child.
+ // nextKeyCodes: dojo.keys[]
+ // Key codes for navigating to the next child.
+ // tags:
+ // protected
+
+ var keyCodes = (this._keyNavCodes = {});
+ var prev = dojo.hitch(this, this.focusPrev);
+ var next = dojo.hitch(this, this.focusNext);
+ dojo.forEach(prevKeyCodes, function(code){ keyCodes[code] = prev; });
+ dojo.forEach(nextKeyCodes, function(code){ keyCodes[code] = next; });
+ keyCodes[dojo.keys.HOME] = dojo.hitch(this, "focusFirstChild");
+ keyCodes[dojo.keys.END] = dojo.hitch(this, "focusLastChild");
+ this.connect(this.domNode, "onkeypress", "_onContainerKeypress");
+ this.connect(this.domNode, "onfocus", "_onContainerFocus");
+ },
+
+ startupKeyNavChildren: function(){
+ // summary:
+ // Call in startup() to set child tabindexes to -1
+ // tags:
+ // protected
+ dojo.forEach(this.getChildren(), dojo.hitch(this, "_startupChild"));
+ },
+
+ addChild: function(/*dijit._Widget*/ widget, /*int?*/ insertIndex){
+ // summary:
+ // Add a child to our _Container
+ dijit._KeyNavContainer.superclass.addChild.apply(this, arguments);
+ this._startupChild(widget);
+ },
+
+ focus: function(){
+ // summary:
+ // Default focus() implementation: focus the first child.
+ this.focusFirstChild();
+ },
+
+ focusFirstChild: function(){
+ // summary:
+ // Focus the first focusable child in the container.
+ // tags:
+ // protected
+ var child = this._getFirstFocusableChild();
+ if(child){ // edge case: Menu could be empty or hidden
+ this.focusChild(child);
+ }
+ },
+
+ focusLastChild: function(){
+ // summary:
+ // Focus the last focusable child in the container.
+ // tags:
+ // protected
+ var child = this._getLastFocusableChild();
+ if(child){ // edge case: Menu could be empty or hidden
+ this.focusChild(child);
+ }
+ },
+
+ focusNext: function(){
+ // summary:
+ // Focus the next widget
+ // tags:
+ // protected
+ var child = this._getNextFocusableChild(this.focusedChild, 1);
+ this.focusChild(child);
+ },
+
+ focusPrev: function(){
+ // summary:
+ // Focus the last focusable node in the previous widget
+ // (ex: go to the ComboButton icon section rather than button section)
+ // tags:
+ // protected
+ var child = this._getNextFocusableChild(this.focusedChild, -1);
+ this.focusChild(child, true);
+ },
+
+ focusChild: function(/*dijit._Widget*/ widget, /*Boolean*/ last){
+ // summary:
+ // Focus widget.
+ // widget:
+ // Reference to container's child widget
+ // last:
+ // If true and if widget has multiple focusable nodes, focus the
+ // last one instead of the first one
+ // tags:
+ // protected
+
+ if(this.focusedChild && widget !== this.focusedChild){
+ this._onChildBlur(this.focusedChild);
+ }
+ widget.set("tabIndex", this.tabIndex); // for IE focus outline to appear, must set tabIndex before focs
+ widget.focus(last ? "end" : "start");
+ this._set("focusedChild", widget);
+ },
+
+ _startupChild: function(/*dijit._Widget*/ widget){
+ // summary:
+ // Setup for each child widget
+ // description:
+ // Sets tabIndex=-1 on each child, so that the tab key will
+ // leave the container rather than visiting each child.
+ // tags:
+ // private
+
+ widget.set("tabIndex", "-1");
+
+ this.connect(widget, "_onFocus", function(){
+ // Set valid tabIndex so tabbing away from widget goes to right place, see #10272
+ widget.set("tabIndex", this.tabIndex);
+ });
+ this.connect(widget, "_onBlur", function(){
+ widget.set("tabIndex", "-1");
+ });
+ },
+
+ _onContainerFocus: function(evt){
+ // summary:
+ // Handler for when the container gets focus
+ // description:
+ // Initially the container itself has a tabIndex, but when it gets
+ // focus, switch focus to first child...
+ // tags:
+ // private
+
+ // Note that we can't use _onFocus() because switching focus from the
+ // _onFocus() handler confuses the focus.js code
+ // (because it causes _onFocusNode() to be called recursively)
+
+ // focus bubbles on Firefox,
+ // so just make sure that focus has really gone to the container
+ if(evt.target !== this.domNode){ return; }
+
+ this.focusFirstChild();
+
+ // and then set the container's tabIndex to -1,
+ // (don't remove as that breaks Safari 4)
+ // so that tab or shift-tab will go to the fields after/before
+ // the container, rather than the container itself
+ dojo.attr(this.domNode, "tabIndex", "-1");
+ },
+
+ _onBlur: function(evt){
+ // When focus is moved away the container, and its descendant (popup) widgets,
+ // then restore the container's tabIndex so that user can tab to it again.
+ // Note that using _onBlur() so that this doesn't happen when focus is shifted
+ // to one of my child widgets (typically a popup)
+ if(this.tabIndex){
+ dojo.attr(this.domNode, "tabIndex", this.tabIndex);
+ }
+ this.inherited(arguments);
+ },
+
+ _onContainerKeypress: function(evt){
+ // summary:
+ // When a key is pressed, if it's an arrow key etc. then
+ // it's handled here.
+ // tags:
+ // private
+ if(evt.ctrlKey || evt.altKey){ return; }
+ var func = this._keyNavCodes[evt.charOrCode];
+ if(func){
+ func();
+ dojo.stopEvent(evt);
+ }
+ },
+
+ _onChildBlur: function(/*dijit._Widget*/ widget){
+ // summary:
+ // Called when focus leaves a child widget to go
+ // to a sibling widget.
+ // tags:
+ // protected
+ },
+
+ _getFirstFocusableChild: function(){
+ // summary:
+ // Returns first child that can be focused
+ return this._getNextFocusableChild(null, 1); // dijit._Widget
+ },
+
+ _getLastFocusableChild: function(){
+ // summary:
+ // Returns last child that can be focused
+ return this._getNextFocusableChild(null, -1); // dijit._Widget
+ },
+
+ _getNextFocusableChild: function(child, dir){
+ // summary:
+ // Returns the next or previous focusable child, compared
+ // to "child"
+ // child: Widget
+ // The current widget
+ // dir: Integer
+ // * 1 = after
+ // * -1 = before
+ if(child){
+ child = this._getSiblingOfChild(child, dir);
+ }
+ var children = this.getChildren();
+ for(var i=0; i < children.length; i++){
+ if(!child){
+ child = children[(dir>0) ? 0 : (children.length-1)];
+ }
+ if(child.isFocusable()){
+ return child; // dijit._Widget
+ }
+ child = this._getSiblingOfChild(child, dir);
+ }
+ // no focusable child found
+ return null; // dijit._Widget
+ }
+ }
+);
+
}