New file |
0,0 → 1,315 |
if(!dojo._hasResource["dijit._Container"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
dojo._hasResource["dijit._Container"] = true; |
dojo.provide("dijit._Container"); |
|
dojo.declare("dijit._Contained", |
null, |
{ |
// summary |
// Mixin for widgets that are children of a container widget |
|
getParent: function(){ |
// summary: |
// returns the parent widget of this widget, assuming the parent |
// implements dijit._Container |
for(var p=this.domNode.parentNode; p; p=p.parentNode){ |
var id = p.getAttribute && p.getAttribute("widgetId"); |
if(id){ |
var parent = dijit.byId(id); |
return parent.isContainer ? parent : null; |
} |
} |
return null; |
}, |
|
_getSibling: function(which){ |
var node = this.domNode; |
do{ |
node = node[which+"Sibling"]; |
}while(node && node.nodeType != 1); |
if(!node){ return null; } // null |
var id = node.getAttribute("widgetId"); |
return dijit.byId(id); |
}, |
|
getPreviousSibling: function(){ |
// summary: |
// returns null if this is the first child of the parent, |
// otherwise returns the next element sibling to the "left". |
|
return this._getSibling("previous"); |
}, |
|
getNextSibling: function(){ |
// summary: |
// returns null if this is the last child of the parent, |
// otherwise returns the next element sibling to the "right". |
|
return this._getSibling("next"); |
} |
} |
); |
|
dojo.declare("dijit._Container", |
null, |
{ |
// summary |
// Mixin for widgets that contain a list of children like SplitContainer |
|
isContainer: true, |
|
addChild: function(/*Widget*/ widget, /*int?*/ insertIndex){ |
// summary: |
// Process the given child widget, inserting it's dom node as |
// a child of our dom node |
|
if(insertIndex === undefined){ |
insertIndex = "last"; |
} |
var refNode = this.containerNode || this.domNode; |
if(insertIndex && typeof insertIndex == "number"){ |
var children = dojo.query("> [widgetid]", refNode); |
if(children && children.length >= insertIndex){ |
refNode = children[insertIndex-1]; insertIndex = "after"; |
} |
} |
dojo.place(widget.domNode, refNode, insertIndex); |
|
// If I've been started but the child widget hasn't been started, |
// start it now. Make sure to do this after widget has been |
// inserted into the DOM tree, so it can see that it's being controlled by me, |
// so it doesn't try to size itself. |
if(this._started && !widget._started){ |
widget.startup(); |
} |
}, |
|
removeChild: function(/*Widget*/ widget){ |
// summary: |
// removes the passed widget instance from this widget but does |
// not destroy it |
var node = widget.domNode; |
node.parentNode.removeChild(node); // detach but don't destroy |
}, |
|
_nextElement: function(node){ |
do{ |
node = node.nextSibling; |
}while(node && node.nodeType != 1); |
return node; |
}, |
|
_firstElement: function(node){ |
node = node.firstChild; |
if(node && node.nodeType != 1){ |
node = this._nextElement(node); |
} |
return node; |
}, |
|
getChildren: function(){ |
// summary: |
// Returns array of children widgets |
return dojo.query("> [widgetId]", this.containerNode || this.domNode).map(dijit.byNode); // Array |
}, |
|
hasChildren: function(){ |
// summary: |
// Returns true if widget has children |
var cn = this.containerNode || this.domNode; |
return !!this._firstElement(cn); // Boolean |
}, |
|
_getSiblingOfChild: function(/*Widget*/ child, /*int*/ dir){ |
// summary: |
// get the next or previous widget sibling of child |
// dir: |
// if 1, get the next sibling |
// if -1, get the previous sibling |
var node = child.domNode; |
var which = (dir>0 ? "nextSibling" : "previousSibling"); |
do{ |
node = node[which]; |
}while(node && (node.nodeType != 1 || !dijit.byNode(node))); |
return node ? dijit.byNode(node) : null; |
} |
} |
); |
|
dojo.declare("dijit._KeyNavContainer", |
[dijit._Container], |
{ |
|
// summary: |
// A _Container with keyboard navigation of its children. |
// To use this mixin, call connectKeyNavHandlers() in |
// postCreate() and call startupKeyNavChildren() in startup(). |
|
/*===== |
// focusedChild: Widget |
// The currently focused child widget, or null if there isn't one |
focusedChild: null, |
=====*/ |
|
_keyNavCodes: {}, |
|
connectKeyNavHandlers: function(/*Array*/ prevKeyCodes, /*Array*/ nextKeyCodes){ |
// summary: |
// Call in postCreate() to attach the keyboard handlers |
// to the container. |
// preKeyCodes: Array |
// Key codes for navigating to the previous child. |
// nextKeyCodes: Array |
// Key codes for navigating to the next child. |
|
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 }); |
this.connect(this.domNode, "onkeypress", "_onContainerKeypress"); |
if(dojo.isIE){ |
this.connect(this.domNode, "onactivate", "_onContainerFocus"); |
this.connect(this.domNode, "ondeactivate", "_onContainerBlur"); |
}else{ |
this.connect(this.domNode, "onfocus", "_onContainerFocus"); |
this.connect(this.domNode, "onblur", "_onContainerBlur"); |
} |
}, |
|
startupKeyNavChildren: function(){ |
// summary: |
// Call in startup() to set child tabindexes to -1 |
dojo.forEach(this.getChildren(), dojo.hitch(this, "_setTabIndexMinusOne")); |
}, |
|
addChild: function(/*Widget*/ widget, /*int?*/ insertIndex){ |
// summary: Add a child to our _Container |
dijit._KeyNavContainer.superclass.addChild.apply(this, arguments); |
this._setTabIndexMinusOne(widget); |
}, |
|
focus: function(){ |
// summary: Default focus() implementation: focus the first child. |
this.focusFirstChild(); |
}, |
|
focusFirstChild: function(){ |
// summary: Focus the first focusable child in the container. |
this.focusChild(this._getFirstFocusableChild()); |
}, |
|
focusNext: function(){ |
// summary: Focus the next widget or focal node (for widgets |
// with multiple focal nodes) within this container. |
if(this.focusedChild && this.focusedChild.hasNextFocalNode |
&& this.focusedChild.hasNextFocalNode()){ |
this.focusedChild.focusNext(); |
return; |
} |
var child = this._getNextFocusableChild(this.focusedChild, 1); |
if(child.getFocalNodes){ |
this.focusChild(child, child.getFocalNodes()[0]); |
}else{ |
this.focusChild(child); |
} |
}, |
|
focusPrev: function(){ |
// summary: Focus the previous widget or focal node (for widgets |
// with multiple focal nodes) within this container. |
if(this.focusedChild && this.focusedChild.hasPrevFocalNode |
&& this.focusedChild.hasPrevFocalNode()){ |
this.focusedChild.focusPrev(); |
return; |
} |
var child = this._getNextFocusableChild(this.focusedChild, -1); |
if(child.getFocalNodes){ |
var nodes = child.getFocalNodes(); |
this.focusChild(child, nodes[nodes.length-1]); |
}else{ |
this.focusChild(child); |
} |
}, |
|
focusChild: function(/*Widget*/ widget, /*Node?*/ node){ |
// summary: Focus widget. Optionally focus 'node' within widget. |
if(widget){ |
if(this.focusedChild && widget !== this.focusedChild){ |
this._onChildBlur(this.focusedChild); |
} |
this.focusedChild = widget; |
if(node && widget.focusFocalNode){ |
widget.focusFocalNode(node); |
}else{ |
widget.focus(); |
} |
} |
}, |
|
_setTabIndexMinusOne: function(/*Widget*/ widget){ |
if(widget.getFocalNodes){ |
dojo.forEach(widget.getFocalNodes(), function(node){ |
node.setAttribute("tabIndex", -1); |
}); |
}else{ |
(widget.focusNode || widget.domNode).setAttribute("tabIndex", -1); |
} |
}, |
|
_onContainerFocus: function(evt){ |
this.domNode.setAttribute("tabIndex", -1); |
if(evt.target === this.domNode){ |
this.focusFirstChild(); |
}else{ |
var widget = dijit.getEnclosingWidget(evt.target); |
if(widget && widget.isFocusable()){ |
this.focusedChild = widget; |
} |
} |
}, |
|
_onContainerBlur: function(evt){ |
if(this.tabIndex){ |
this.domNode.setAttribute("tabIndex", this.tabIndex); |
} |
}, |
|
_onContainerKeypress: function(evt){ |
if(evt.ctrlKey || evt.altKey){ return; } |
var func = this._keyNavCodes[evt.keyCode]; |
if(func){ |
func(); |
dojo.stopEvent(evt); |
} |
}, |
|
_onChildBlur: function(/*Widget*/ widget){ |
// summary: |
// Called when focus leaves a child widget to go |
// to a sibling widget. |
}, |
|
_getFirstFocusableChild: function(){ |
return this._getNextFocusableChild(null, 1); |
}, |
|
_getNextFocusableChild: function(child, dir){ |
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; |
} |
child = this._getSiblingOfChild(child, dir); |
} |
} |
} |
); |
|
} |