]> git.pond.sub.org Git - eow/blob - static/dojo-release-1.1.1/dijit/_Container.js
add Dojo 1.1.1
[eow] / static / dojo-release-1.1.1 / dijit / _Container.js
1 if(!dojo._hasResource["dijit._Container"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2 dojo._hasResource["dijit._Container"] = true;
3 dojo.provide("dijit._Container");
4
5 dojo.declare("dijit._Contained",
6         null,
7         {
8                 // summary
9                 //              Mixin for widgets that are children of a container widget
10                 //
11                 // example:
12                 // |    // make a basic custom widget that knows about it's parents
13                 // |    dojo.declare("my.customClass",[dijit._Widget,dijit._Contained],{});
14                 // 
15                 getParent: function(){
16                         // summary:
17                         //              Returns the parent widget of this widget, assuming the parent
18                         //              implements dijit._Container
19                         for(var p=this.domNode.parentNode; p; p=p.parentNode){
20                                 var id = p.getAttribute && p.getAttribute("widgetId");
21                                 if(id){
22                                         var parent = dijit.byId(id);
23                                         return parent.isContainer ? parent : null;
24                                 }
25                         }
26                         return null;
27                 },
28
29                 _getSibling: function(which){
30                         var node = this.domNode;
31                         do{
32                                 node = node[which+"Sibling"];
33                         }while(node && node.nodeType != 1);
34                         if(!node){ return null; } // null
35                         var id = node.getAttribute("widgetId");
36                         return dijit.byId(id);
37                 },
38
39                 getPreviousSibling: function(){
40                         // summary:
41                         //              Returns null if this is the first child of the parent,
42                         //              otherwise returns the next element sibling to the "left".
43
44                         return this._getSibling("previous"); // Mixed
45                 },
46
47                 getNextSibling: function(){
48                         // summary:
49                         //              Returns null if this is the last child of the parent,
50                         //              otherwise returns the next element sibling to the "right".
51
52                         return this._getSibling("next"); // Mixed
53                 }
54         }
55 );
56
57 dojo.declare("dijit._Container",
58         null,
59         {
60                 // summary:
61                 //              Mixin for widgets that contain a list of children.
62                 // description:
63                 //              Use this mixin when the widget needs to know about and
64                 //              keep track of it's widget children. Widgets like SplitContainer
65                 //              and TabContainer.  
66
67                 isContainer: true,
68
69                 addChild: function(/*Widget*/ widget, /*int?*/ insertIndex){
70                         // summary:
71                         //              Process the given child widget, inserting it's dom node as
72                         //              a child of our dom node
73
74                         if(insertIndex === undefined){
75                                 insertIndex = "last";
76                         }
77                         var refNode = this.containerNode || this.domNode;
78                         if(insertIndex && typeof insertIndex == "number"){
79                                 var children = dojo.query("> [widgetid]", refNode);
80                                 if(children && children.length >= insertIndex){
81                                         refNode = children[insertIndex-1]; insertIndex = "after";
82                                 }
83                         }
84                         dojo.place(widget.domNode, refNode, insertIndex);
85
86                         // If I've been started but the child widget hasn't been started,
87                         // start it now.  Make sure to do this after widget has been
88                         // inserted into the DOM tree, so it can see that it's being controlled by me,
89                         // so it doesn't try to size itself.
90                         if(this._started && !widget._started){
91                                 widget.startup();
92                         }
93                 },
94
95                 removeChild: function(/*Widget*/ widget){
96                         // summary:
97                         //              Removes the passed widget instance from this widget but does
98                         //              not destroy it
99                         var node = widget.domNode;
100                         node.parentNode.removeChild(node);      // detach but don't destroy
101                 },
102
103                 _nextElement: function(node){
104                         do{
105                                 node = node.nextSibling;
106                         }while(node && node.nodeType != 1);
107                         return node;
108                 },
109
110                 _firstElement: function(node){
111                         node = node.firstChild;
112                         if(node && node.nodeType != 1){
113                                 node = this._nextElement(node);
114                         }
115                         return node;
116                 },
117
118                 getChildren: function(){
119                         // summary:
120                         //              Returns array of children widgets
121                         return dojo.query("> [widgetId]", this.containerNode || this.domNode).map(dijit.byNode); // Array
122                 },
123
124                 hasChildren: function(){
125                         // summary:
126                         //              Returns true if widget has children
127                         var cn = this.containerNode || this.domNode;
128                         return !!this._firstElement(cn); // Boolean
129                 },
130
131                 _getSiblingOfChild: function(/*Widget*/ child, /*int*/ dir){
132                         // summary:
133                         //              Get the next or previous widget sibling of child
134                         // dir:
135                         //              if 1, get the next sibling
136                         //              if -1, get the previous sibling
137                         var node = child.domNode;
138                         var which = (dir>0 ? "nextSibling" : "previousSibling");
139                         do{
140                                 node = node[which];
141                         }while(node && (node.nodeType != 1 || !dijit.byNode(node)));
142                         return node ? dijit.byNode(node) : null;
143                 }
144         }
145 );
146
147 dojo.declare("dijit._KeyNavContainer",
148         [dijit._Container],
149         {
150
151                 // summary: A _Container with keyboard navigation of its children.
152                 // decscription:
153                 //              To use this mixin, call connectKeyNavHandlers() in
154                 //              postCreate() and call startupKeyNavChildren() in startup().
155                 //              It provides normalized keyboard and focusing code for Container
156                 //              widgets.
157 /*=====
158                 // focusedChild: Widget
159                 //              The currently focused child widget, or null if there isn't one
160                 focusedChild: null,
161 =====*/
162
163                 _keyNavCodes: {},
164
165                 connectKeyNavHandlers: function(/*Array*/ prevKeyCodes, /*Array*/ nextKeyCodes){
166                         // summary:
167                         //              Call in postCreate() to attach the keyboard handlers
168                         //              to the container.
169                         // preKeyCodes: Array
170                         //              Key codes for navigating to the previous child.
171                         // nextKeyCodes: Array
172                         //              Key codes for navigating to the next child.
173
174                         var keyCodes = this._keyNavCodes = {};
175                         var prev = dojo.hitch(this, this.focusPrev);
176                         var next = dojo.hitch(this, this.focusNext);
177                         dojo.forEach(prevKeyCodes, function(code){ keyCodes[code] = prev });
178                         dojo.forEach(nextKeyCodes, function(code){ keyCodes[code] = next });
179                         this.connect(this.domNode, "onkeypress", "_onContainerKeypress");
180                         this.connect(this.domNode, "onfocus", "_onContainerFocus");
181                 },
182
183                 startupKeyNavChildren: function(){
184                         // summary:
185                         //              Call in startup() to set child tabindexes to -1
186                         dojo.forEach(this.getChildren(), dojo.hitch(this, "_startupChild"));
187                 },
188
189                 addChild: function(/*Widget*/ widget, /*int?*/ insertIndex){
190                         // summary: Add a child to our _Container
191                         dijit._KeyNavContainer.superclass.addChild.apply(this, arguments);
192                         this._startupChild(widget);
193                 },
194
195                 focus: function(){
196                         // summary: Default focus() implementation: focus the first child.
197                         this.focusFirstChild();
198                 },
199
200                 focusFirstChild: function(){
201                         // summary: Focus the first focusable child in the container.
202                         this.focusChild(this._getFirstFocusableChild());
203                 },
204
205                 focusNext: function(){
206                         // summary: Focus the next widget or focal node (for widgets
207                         //              with multiple focal nodes) within this container.
208                         if(this.focusedChild && this.focusedChild.hasNextFocalNode
209                                         && this.focusedChild.hasNextFocalNode()){
210                                 this.focusedChild.focusNext();
211                                 return;
212                         }
213                         var child = this._getNextFocusableChild(this.focusedChild, 1);
214                         if(child.getFocalNodes){
215                                 this.focusChild(child, child.getFocalNodes()[0]);
216                         }else{
217                                 this.focusChild(child);
218                         }
219                 },
220
221                 focusPrev: function(){
222                         // summary: Focus the previous widget or focal node (for widgets
223                         //              with multiple focal nodes) within this container.
224                         if(this.focusedChild && this.focusedChild.hasPrevFocalNode
225                                         && this.focusedChild.hasPrevFocalNode()){
226                                 this.focusedChild.focusPrev();
227                                 return;
228                         }
229                         var child = this._getNextFocusableChild(this.focusedChild, -1);
230                         if(child.getFocalNodes){
231                                 var nodes = child.getFocalNodes();
232                                 this.focusChild(child, nodes[nodes.length-1]);
233                         }else{
234                                 this.focusChild(child);
235                         }
236                 },
237
238                 focusChild: function(/*Widget*/ widget, /*Node?*/ node){
239                         // summary: Focus widget. Optionally focus 'node' within widget.
240                         if(widget){
241                                 if(this.focusedChild && widget !== this.focusedChild){
242                                         this._onChildBlur(this.focusedChild);
243                                 }
244                                 this.focusedChild = widget;
245                                 if(node && widget.focusFocalNode){
246                                         widget.focusFocalNode(node);
247                                 }else{
248                                         widget.focus();
249                                 }
250                         }
251                 },
252
253                 _startupChild: function(/*Widget*/ widget){
254                         // summary:
255                         //              Set tabindex="-1" on focusable widgets so that we
256                         //              can focus them programmatically and by clicking.
257                         //              Connect focus and blur handlers.
258                         if(widget.getFocalNodes){
259                                 dojo.forEach(widget.getFocalNodes(), function(node){
260                                         dojo.attr(node, "tabindex", -1);
261                                         this._connectNode(node);
262                                 }, this);
263                         }else{
264                                 var node = widget.focusNode || widget.domNode;
265                                 if(widget.isFocusable()){
266                                         dojo.attr(node, "tabindex", -1);
267                                 }
268                                 this._connectNode(node);
269                         }
270                 },
271
272                 _connectNode: function(/*Element*/ node){
273                         this.connect(node, "onfocus", "_onNodeFocus");
274                         this.connect(node, "onblur", "_onNodeBlur");
275                 },
276
277                 _onContainerFocus: function(evt){
278                         // focus bubbles on Firefox,
279                         // so just make sure that focus has really gone to the container
280                         if(evt.target === this.domNode){
281                                 this.focusFirstChild();
282                         }
283                 },
284
285                 _onContainerKeypress: function(evt){
286                         if(evt.ctrlKey || evt.altKey){ return; }
287                         var func = this._keyNavCodes[evt.keyCode];
288                         if(func){
289                                 func();
290                                 dojo.stopEvent(evt);
291                         }
292                 },
293
294                 _onNodeFocus: function(evt){
295                         // while focus is on a child,
296                         // take the container out of the tab order so that
297                         // we can shift-tab to the element before the container
298                         dojo.attr(this.domNode, "tabindex", -1);
299                         // record the child that has been focused
300                         var widget = dijit.getEnclosingWidget(evt.target);
301                         if(widget && widget.isFocusable()){
302                                 this.focusedChild = widget;
303                         }
304                         dojo.stopEvent(evt);
305                 },
306
307                 _onNodeBlur: function(evt){
308                         // when focus leaves a child,
309                         // reinstate the container's tabindex
310                         if(this.tabIndex){
311                                 dojo.attr(this.domNode, "tabindex", this.tabIndex);
312                         }
313                         dojo.stopEvent(evt);
314                 },
315
316                 _onChildBlur: function(/*Widget*/ widget){
317                         // summary:
318                         //              Called when focus leaves a child widget to go
319                         //              to a sibling widget.
320                 },
321
322                 _getFirstFocusableChild: function(){
323                         return this._getNextFocusableChild(null, 1);
324                 },
325
326                 _getNextFocusableChild: function(child, dir){
327                         if(child){
328                                 child = this._getSiblingOfChild(child, dir);
329                         }
330                         var children = this.getChildren();
331                         for(var i=0; i < children.length; i++){
332                                 if(!child){
333                                         child = children[(dir>0) ? 0 : (children.length-1)];
334                                 }
335                                 if(child.isFocusable()){
336                                         return child;
337                                 }
338                                 child = this._getSiblingOfChild(child, dir);
339                         }
340                         // no focusable child found
341                         return null;
342                 }
343         }
344 );
345
346 }