e44a7e37b6
git-svn-id: https://semanticscuttle.svn.sourceforge.net/svnroot/semanticscuttle/trunk@151 b3834d28-1941-0410-a4f8-b48e95affb8f
346 lines
9.8 KiB
JavaScript
346 lines
9.8 KiB
JavaScript
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
|
|
//
|
|
// example:
|
|
// | // make a basic custom widget that knows about it's parents
|
|
// | dojo.declare("my.customClass",[dijit._Widget,dijit._Contained],{});
|
|
//
|
|
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"); // Mixed
|
|
},
|
|
|
|
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"); // Mixed
|
|
}
|
|
}
|
|
);
|
|
|
|
dojo.declare("dijit._Container",
|
|
null,
|
|
{
|
|
// summary:
|
|
// Mixin for widgets that contain a list of children.
|
|
// description:
|
|
// Use this mixin when the widget needs to know about and
|
|
// keep track of it's widget children. Widgets like SplitContainer
|
|
// and TabContainer.
|
|
|
|
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.
|
|
// decscription:
|
|
// To use this mixin, call connectKeyNavHandlers() in
|
|
// postCreate() and call startupKeyNavChildren() in startup().
|
|
// It provides normalized keyboard and focusing code for Container
|
|
// widgets.
|
|
/*=====
|
|
// 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");
|
|
this.connect(this.domNode, "onfocus", "_onContainerFocus");
|
|
},
|
|
|
|
startupKeyNavChildren: function(){
|
|
// summary:
|
|
// Call in startup() to set child tabindexes to -1
|
|
dojo.forEach(this.getChildren(), dojo.hitch(this, "_startupChild"));
|
|
},
|
|
|
|
addChild: function(/*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.
|
|
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();
|
|
}
|
|
}
|
|
},
|
|
|
|
_startupChild: function(/*Widget*/ widget){
|
|
// summary:
|
|
// Set tabindex="-1" on focusable widgets so that we
|
|
// can focus them programmatically and by clicking.
|
|
// Connect focus and blur handlers.
|
|
if(widget.getFocalNodes){
|
|
dojo.forEach(widget.getFocalNodes(), function(node){
|
|
dojo.attr(node, "tabindex", -1);
|
|
this._connectNode(node);
|
|
}, this);
|
|
}else{
|
|
var node = widget.focusNode || widget.domNode;
|
|
if(widget.isFocusable()){
|
|
dojo.attr(node, "tabindex", -1);
|
|
}
|
|
this._connectNode(node);
|
|
}
|
|
},
|
|
|
|
_connectNode: function(/*Element*/ node){
|
|
this.connect(node, "onfocus", "_onNodeFocus");
|
|
this.connect(node, "onblur", "_onNodeBlur");
|
|
},
|
|
|
|
_onContainerFocus: function(evt){
|
|
// focus bubbles on Firefox,
|
|
// so just make sure that focus has really gone to the container
|
|
if(evt.target === this.domNode){
|
|
this.focusFirstChild();
|
|
}
|
|
},
|
|
|
|
_onContainerKeypress: function(evt){
|
|
if(evt.ctrlKey || evt.altKey){ return; }
|
|
var func = this._keyNavCodes[evt.keyCode];
|
|
if(func){
|
|
func();
|
|
dojo.stopEvent(evt);
|
|
}
|
|
},
|
|
|
|
_onNodeFocus: function(evt){
|
|
// while focus is on a child,
|
|
// take the container out of the tab order so that
|
|
// we can shift-tab to the element before the container
|
|
dojo.attr(this.domNode, "tabindex", -1);
|
|
// record the child that has been focused
|
|
var widget = dijit.getEnclosingWidget(evt.target);
|
|
if(widget && widget.isFocusable()){
|
|
this.focusedChild = widget;
|
|
}
|
|
dojo.stopEvent(evt);
|
|
},
|
|
|
|
_onNodeBlur: function(evt){
|
|
// when focus leaves a child,
|
|
// reinstate the container's tabindex
|
|
if(this.tabIndex){
|
|
dojo.attr(this.domNode, "tabindex", this.tabIndex);
|
|
}
|
|
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);
|
|
}
|
|
// no focusable child found
|
|
return null;
|
|
}
|
|
}
|
|
);
|
|
|
|
}
|