diff options
Diffstat (limited to 'includes/js/dijit/_Container.js')
-rw-r--r-- | includes/js/dijit/_Container.js | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/includes/js/dijit/_Container.js b/includes/js/dijit/_Container.js new file mode 100644 index 0000000..47d9ee8 --- /dev/null +++ b/includes/js/dijit/_Container.js @@ -0,0 +1,346 @@ +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; + } + } +); + +} |