aboutsummaryrefslogtreecommitdiff
path: root/includes/js/dijit/_Container.js
diff options
context:
space:
mode:
Diffstat (limited to 'includes/js/dijit/_Container.js')
-rw-r--r--includes/js/dijit/_Container.js346
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;
+ }
+ }
+);
+
+}