]> git.pond.sub.org Git - eow/blobdiff - static/dojo-release-1.1.1/dijit/_Container.js
add Dojo 1.1.1
[eow] / static / dojo-release-1.1.1 / dijit / _Container.js
diff --git a/static/dojo-release-1.1.1/dijit/_Container.js b/static/dojo-release-1.1.1/dijit/_Container.js
new file mode 100644 (file)
index 0000000..47d9ee8
--- /dev/null
@@ -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;
+               }
+       }
+);
+
+}