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