2150 |
mathias |
1 |
/*
|
|
|
2 |
Copyright (c) 2004-2007, The Dojo Foundation
|
|
|
3 |
All Rights Reserved.
|
|
|
4 |
|
|
|
5 |
Licensed under the Academic Free License version 2.1 or above OR the
|
|
|
6 |
modified BSD license. For more information on Dojo licensing, see:
|
|
|
7 |
|
|
|
8 |
http://dojotoolkit.org/book/dojo-book-0-9/introduction/licensing
|
|
|
9 |
*/
|
|
|
10 |
|
|
|
11 |
/*
|
|
|
12 |
This is a compiled version of Dojo, built for deployment and not for
|
|
|
13 |
development. To get an editable version, please visit:
|
|
|
14 |
|
|
|
15 |
http://dojotoolkit.org
|
|
|
16 |
|
|
|
17 |
for documentation and information on getting the source.
|
|
|
18 |
*/
|
|
|
19 |
|
|
|
20 |
if(!dojo._hasResource["dijit._base.focus"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
21 |
dojo._hasResource["dijit._base.focus"] = true;
|
|
|
22 |
dojo.provide("dijit._base.focus");
|
|
|
23 |
|
|
|
24 |
// summary:
|
|
|
25 |
// These functions are used to query or set the focus and selection.
|
|
|
26 |
//
|
|
|
27 |
// Also, they trace when widgets become actived/deactivated,
|
|
|
28 |
// so that the widget can fire _onFocus/_onBlur events.
|
|
|
29 |
// "Active" here means something similar to "focused", but
|
|
|
30 |
// "focus" isn't quite the right word because we keep track of
|
|
|
31 |
// a whole stack of "active" widgets. Example: Combobutton --> Menu -->
|
|
|
32 |
// MenuItem. The onBlur event for Combobutton doesn't fire due to focusing
|
|
|
33 |
// on the Menu or a MenuItem, since they are considered part of the
|
|
|
34 |
// Combobutton widget. It only happens when focus is shifted
|
|
|
35 |
// somewhere completely different.
|
|
|
36 |
|
|
|
37 |
dojo.mixin(dijit,
|
|
|
38 |
{
|
|
|
39 |
// _curFocus: DomNode
|
|
|
40 |
// Currently focused item on screen
|
|
|
41 |
_curFocus: null,
|
|
|
42 |
|
|
|
43 |
// _prevFocus: DomNode
|
|
|
44 |
// Previously focused item on screen
|
|
|
45 |
_prevFocus: null,
|
|
|
46 |
|
|
|
47 |
isCollapsed: function(){
|
|
|
48 |
// summary: tests whether the current selection is empty
|
|
|
49 |
var _window = dojo.global;
|
|
|
50 |
var _document = dojo.doc;
|
|
|
51 |
if(_document.selection){ // IE
|
|
|
52 |
return !_document.selection.createRange().text; // Boolean
|
|
|
53 |
}else if(_window.getSelection){
|
|
|
54 |
var selection = _window.getSelection();
|
|
|
55 |
if(dojo.isString(selection)){ // Safari
|
|
|
56 |
return !selection; // Boolean
|
|
|
57 |
}else{ // Mozilla/W3
|
|
|
58 |
return selection.isCollapsed || !selection.toString(); // Boolean
|
|
|
59 |
}
|
|
|
60 |
}
|
|
|
61 |
},
|
|
|
62 |
|
|
|
63 |
getBookmark: function(){
|
|
|
64 |
// summary: Retrieves a bookmark that can be used with moveToBookmark to return to the same range
|
|
|
65 |
var bookmark, selection = dojo.doc.selection;
|
|
|
66 |
if(selection){ // IE
|
|
|
67 |
var range = selection.createRange();
|
|
|
68 |
if(selection.type.toUpperCase()=='CONTROL'){
|
|
|
69 |
bookmark = range.length ? dojo._toArray(range) : null;
|
|
|
70 |
}else{
|
|
|
71 |
bookmark = range.getBookmark();
|
|
|
72 |
}
|
|
|
73 |
}else{
|
|
|
74 |
if(dojo.global.getSelection){
|
|
|
75 |
selection = dojo.global.getSelection();
|
|
|
76 |
if(selection){
|
|
|
77 |
var range = selection.getRangeAt(0);
|
|
|
78 |
bookmark = range.cloneRange();
|
|
|
79 |
}
|
|
|
80 |
}else{
|
|
|
81 |
console.debug("No idea how to store the current selection for this browser!");
|
|
|
82 |
}
|
|
|
83 |
}
|
|
|
84 |
return bookmark; // Array
|
|
|
85 |
},
|
|
|
86 |
|
|
|
87 |
moveToBookmark: function(/*Object*/bookmark){
|
|
|
88 |
// summary: Moves current selection to a bookmark
|
|
|
89 |
// bookmark: this should be a returned object from dojo.html.selection.getBookmark()
|
|
|
90 |
var _document = dojo.doc;
|
|
|
91 |
if(_document.selection){ // IE
|
|
|
92 |
var range;
|
|
|
93 |
if(dojo.isArray(bookmark)){
|
|
|
94 |
range = _document.body.createControlRange();
|
|
|
95 |
dojo.forEach(bookmark, range.addElement);
|
|
|
96 |
}else{
|
|
|
97 |
range = _document.selection.createRange();
|
|
|
98 |
range.moveToBookmark(bookmark);
|
|
|
99 |
}
|
|
|
100 |
range.select();
|
|
|
101 |
}else{ //Moz/W3C
|
|
|
102 |
var selection = dojo.global.getSelection && dojo.global.getSelection();
|
|
|
103 |
if(selection && selection.removeAllRanges){
|
|
|
104 |
selection.removeAllRanges();
|
|
|
105 |
selection.addRange(bookmark);
|
|
|
106 |
}else{
|
|
|
107 |
console.debug("No idea how to restore selection for this browser!");
|
|
|
108 |
}
|
|
|
109 |
}
|
|
|
110 |
},
|
|
|
111 |
|
|
|
112 |
getFocus: function(/*Widget*/menu, /*Window*/ openedForWindow){
|
|
|
113 |
// summary:
|
|
|
114 |
// Returns the current focus and selection.
|
|
|
115 |
// Called when a popup appears (either a top level menu or a dialog),
|
|
|
116 |
// or when a toolbar/menubar receives focus
|
|
|
117 |
//
|
|
|
118 |
// menu:
|
|
|
119 |
// the menu that's being opened
|
|
|
120 |
//
|
|
|
121 |
// openedForWindow:
|
|
|
122 |
// iframe in which menu was opened
|
|
|
123 |
//
|
|
|
124 |
// returns:
|
|
|
125 |
// a handle to restore focus/selection
|
|
|
126 |
|
|
|
127 |
return {
|
|
|
128 |
// Node to return focus to
|
|
|
129 |
node: menu && dojo.isDescendant(dijit._curFocus, menu.domNode) ? dijit._prevFocus : dijit._curFocus,
|
|
|
130 |
|
|
|
131 |
// Previously selected text
|
|
|
132 |
bookmark:
|
|
|
133 |
!dojo.withGlobal(openedForWindow||dojo.global, dijit.isCollapsed) ?
|
|
|
134 |
dojo.withGlobal(openedForWindow||dojo.global, dijit.getBookmark) :
|
|
|
135 |
null,
|
|
|
136 |
|
|
|
137 |
openedForWindow: openedForWindow
|
|
|
138 |
}; // Object
|
|
|
139 |
},
|
|
|
140 |
|
|
|
141 |
focus: function(/*Object || DomNode */ handle){
|
|
|
142 |
// summary:
|
|
|
143 |
// Sets the focused node and the selection according to argument.
|
|
|
144 |
// To set focus to an iframe's content, pass in the iframe itself.
|
|
|
145 |
// handle:
|
|
|
146 |
// object returned by get(), or a DomNode
|
|
|
147 |
|
|
|
148 |
if(!handle){ return; }
|
|
|
149 |
|
|
|
150 |
var node = "node" in handle ? handle.node : handle, // because handle is either DomNode or a composite object
|
|
|
151 |
bookmark = handle.bookmark,
|
|
|
152 |
openedForWindow = handle.openedForWindow;
|
|
|
153 |
|
|
|
154 |
// Set the focus
|
|
|
155 |
// Note that for iframe's we need to use the <iframe> to follow the parentNode chain,
|
|
|
156 |
// but we need to set focus to iframe.contentWindow
|
|
|
157 |
if(node){
|
|
|
158 |
var focusNode = (node.tagName.toLowerCase()=="iframe") ? node.contentWindow : node;
|
|
|
159 |
if(focusNode && focusNode.focus){
|
|
|
160 |
try{
|
|
|
161 |
// Gecko throws sometimes if setting focus is impossible,
|
|
|
162 |
// node not displayed or something like that
|
|
|
163 |
focusNode.focus();
|
|
|
164 |
}catch(e){/*quiet*/}
|
|
|
165 |
}
|
|
|
166 |
dijit._onFocusNode(node);
|
|
|
167 |
}
|
|
|
168 |
|
|
|
169 |
// set the selection
|
|
|
170 |
// do not need to restore if current selection is not empty
|
|
|
171 |
// (use keyboard to select a menu item)
|
|
|
172 |
if(bookmark && dojo.withGlobal(openedForWindow||dojo.global, dijit.isCollapsed)){
|
|
|
173 |
if(openedForWindow){
|
|
|
174 |
openedForWindow.focus();
|
|
|
175 |
}
|
|
|
176 |
try{
|
|
|
177 |
dojo.withGlobal(openedForWindow||dojo.global, moveToBookmark, null, [bookmark]);
|
|
|
178 |
}catch(e){
|
|
|
179 |
/*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */
|
|
|
180 |
}
|
|
|
181 |
}
|
|
|
182 |
},
|
|
|
183 |
|
|
|
184 |
// List of currently active widgets (focused widget and it's ancestors)
|
|
|
185 |
_activeStack: [],
|
|
|
186 |
|
|
|
187 |
registerWin: function(/*Window?*/targetWindow){
|
|
|
188 |
// summary:
|
|
|
189 |
// Registers listeners on the specified window (either the main
|
|
|
190 |
// window or an iframe) to detect when the user has clicked somewhere.
|
|
|
191 |
// Anyone that creates an iframe should call this function.
|
|
|
192 |
|
|
|
193 |
if(!targetWindow){
|
|
|
194 |
targetWindow = window;
|
|
|
195 |
}
|
|
|
196 |
|
|
|
197 |
dojo.connect(targetWindow.document, "onmousedown", null, function(evt){
|
|
|
198 |
dijit._justMouseDowned = true;
|
|
|
199 |
setTimeout(function(){ dijit._justMouseDowned = false; }, 0);
|
|
|
200 |
dijit._onTouchNode(evt.target||evt.srcElement);
|
|
|
201 |
});
|
|
|
202 |
//dojo.connect(targetWindow, "onscroll", ???);
|
|
|
203 |
|
|
|
204 |
// Listen for blur and focus events on targetWindow's body
|
|
|
205 |
var body = targetWindow.document.body || targetWindow.document.getElementsByTagName("body")[0];
|
|
|
206 |
if(body){
|
|
|
207 |
if(dojo.isIE){
|
|
|
208 |
body.attachEvent('onactivate', function(evt){
|
|
|
209 |
if(evt.srcElement.tagName.toLowerCase() != "body"){
|
|
|
210 |
dijit._onFocusNode(evt.srcElement);
|
|
|
211 |
}
|
|
|
212 |
});
|
|
|
213 |
body.attachEvent('ondeactivate', function(evt){ dijit._onBlurNode(evt.srcElement); });
|
|
|
214 |
}else{
|
|
|
215 |
body.addEventListener('focus', function(evt){ dijit._onFocusNode(evt.target); }, true);
|
|
|
216 |
body.addEventListener('blur', function(evt){ dijit._onBlurNode(evt.target); }, true);
|
|
|
217 |
}
|
|
|
218 |
}
|
|
|
219 |
body = null; // prevent memory leak (apparent circular reference via closure)
|
|
|
220 |
},
|
|
|
221 |
|
|
|
222 |
_onBlurNode: function(/*DomNode*/ node){
|
|
|
223 |
// summary:
|
|
|
224 |
// Called when focus leaves a node.
|
|
|
225 |
// Usually ignored, _unless_ it *isn't* follwed by touching another node,
|
|
|
226 |
// which indicates that we tabbed off the last field on the page,
|
|
|
227 |
// in which case every widget is marked inactive
|
|
|
228 |
dijit._prevFocus = dijit._curFocus;
|
|
|
229 |
dijit._curFocus = null;
|
|
|
230 |
|
|
|
231 |
var w = dijit.getEnclosingWidget(node);
|
|
|
232 |
if (w && w._setStateClass){
|
|
|
233 |
w._focused = false;
|
|
|
234 |
w._setStateClass();
|
|
|
235 |
}
|
|
|
236 |
if(dijit._justMouseDowned){
|
|
|
237 |
// the mouse down caused a new widget to be marked as active; this blur event
|
|
|
238 |
// is coming late, so ignore it.
|
|
|
239 |
return;
|
|
|
240 |
}
|
|
|
241 |
|
|
|
242 |
// if the blur event isn't followed by a focus event then mark all widgets as inactive.
|
|
|
243 |
if(dijit._clearActiveWidgetsTimer){
|
|
|
244 |
clearTimeout(dijit._clearActiveWidgetsTimer);
|
|
|
245 |
}
|
|
|
246 |
dijit._clearActiveWidgetsTimer = setTimeout(function(){
|
|
|
247 |
delete dijit._clearActiveWidgetsTimer; dijit._setStack([]); }, 100);
|
|
|
248 |
},
|
|
|
249 |
|
|
|
250 |
_onTouchNode: function(/*DomNode*/ node){
|
|
|
251 |
// summary
|
|
|
252 |
// Callback when node is focused or mouse-downed
|
|
|
253 |
|
|
|
254 |
// ignore the recent blurNode event
|
|
|
255 |
if(dijit._clearActiveWidgetsTimer){
|
|
|
256 |
clearTimeout(dijit._clearActiveWidgetsTimer);
|
|
|
257 |
delete dijit._clearActiveWidgetsTimer;
|
|
|
258 |
}
|
|
|
259 |
|
|
|
260 |
// compute stack of active widgets (ex: ComboButton --> Menu --> MenuItem)
|
|
|
261 |
var newStack=[];
|
|
|
262 |
try{
|
|
|
263 |
while(node){
|
|
|
264 |
if(node.dijitPopupParent){
|
|
|
265 |
node=dijit.byId(node.dijitPopupParent).domNode;
|
|
|
266 |
}else if(node.tagName && node.tagName.toLowerCase()=="body"){
|
|
|
267 |
// is this the root of the document or just the root of an iframe?
|
|
|
268 |
if(node===dojo.body()){
|
|
|
269 |
// node is the root of the main document
|
|
|
270 |
break;
|
|
|
271 |
}
|
|
|
272 |
// otherwise, find the iframe this node refers to (can't access it via parentNode,
|
|
|
273 |
// need to do this trick instead) and continue tracing up the document
|
|
|
274 |
node=dojo.query("iframe").filter(function(iframe){ return iframe.contentDocument.body===node; })[0];
|
|
|
275 |
}else{
|
|
|
276 |
var id = node.getAttribute && node.getAttribute("widgetId");
|
|
|
277 |
if(id){
|
|
|
278 |
newStack.unshift(id);
|
|
|
279 |
}
|
|
|
280 |
node=node.parentNode;
|
|
|
281 |
}
|
|
|
282 |
}
|
|
|
283 |
}catch(e){ /* squelch */ }
|
|
|
284 |
|
|
|
285 |
dijit._setStack(newStack);
|
|
|
286 |
},
|
|
|
287 |
|
|
|
288 |
_onFocusNode: function(/*DomNode*/ node){
|
|
|
289 |
// summary
|
|
|
290 |
// Callback when node is focused
|
|
|
291 |
if(node && node.tagName && node.tagName.toLowerCase() == "body"){
|
|
|
292 |
return;
|
|
|
293 |
}
|
|
|
294 |
dijit._onTouchNode(node);
|
|
|
295 |
if(node==dijit._curFocus){ return; }
|
|
|
296 |
dijit._prevFocus = dijit._curFocus;
|
|
|
297 |
dijit._curFocus = node;
|
|
|
298 |
dojo.publish("focusNode", [node]);
|
|
|
299 |
|
|
|
300 |
// handle focus/blur styling
|
|
|
301 |
var w = dijit.getEnclosingWidget(node);
|
|
|
302 |
if (w && w._setStateClass){
|
|
|
303 |
w._focused = true;
|
|
|
304 |
w._setStateClass();
|
|
|
305 |
}
|
|
|
306 |
},
|
|
|
307 |
|
|
|
308 |
_setStack: function(newStack){
|
|
|
309 |
// summary
|
|
|
310 |
// The stack of active widgets has changed. Send out appropriate events and record new stack
|
|
|
311 |
|
|
|
312 |
var oldStack = dijit._activeStack;
|
|
|
313 |
dijit._activeStack = newStack;
|
|
|
314 |
|
|
|
315 |
// compare old stack to new stack to see how many elements they have in common
|
|
|
316 |
for(var nCommon=0; nCommon<Math.min(oldStack.length, newStack.length); nCommon++){
|
|
|
317 |
if(oldStack[nCommon] != newStack[nCommon]){
|
|
|
318 |
break;
|
|
|
319 |
}
|
|
|
320 |
}
|
|
|
321 |
|
|
|
322 |
// for all elements that have gone out of focus, send blur event
|
|
|
323 |
for(var i=oldStack.length-1; i>=nCommon; i--){
|
|
|
324 |
var widget = dijit.byId(oldStack[i]);
|
|
|
325 |
if(widget){
|
|
|
326 |
dojo.publish("widgetBlur", [widget]);
|
|
|
327 |
if(widget._onBlur){
|
|
|
328 |
widget._onBlur();
|
|
|
329 |
}
|
|
|
330 |
}
|
|
|
331 |
}
|
|
|
332 |
|
|
|
333 |
// for all element that have come into focus, send focus event
|
|
|
334 |
for(var i=nCommon; i<newStack.length; i++){
|
|
|
335 |
var widget = dijit.byId(newStack[i]);
|
|
|
336 |
if(widget){
|
|
|
337 |
dojo.publish("widgetFocus", [widget]);
|
|
|
338 |
if(widget._onFocus){
|
|
|
339 |
widget._onFocus();
|
|
|
340 |
}
|
|
|
341 |
}
|
|
|
342 |
}
|
|
|
343 |
}
|
|
|
344 |
});
|
|
|
345 |
|
|
|
346 |
// register top window and all the iframes it contains
|
|
|
347 |
dojo.addOnLoad(dijit.registerWin);
|
|
|
348 |
|
|
|
349 |
}
|
|
|
350 |
|
|
|
351 |
if(!dojo._hasResource["dijit._base.manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
352 |
dojo._hasResource["dijit._base.manager"] = true;
|
|
|
353 |
dojo.provide("dijit._base.manager");
|
|
|
354 |
|
|
|
355 |
dojo.declare("dijit.WidgetSet", null, {
|
|
|
356 |
constructor: function(){
|
|
|
357 |
// summary:
|
|
|
358 |
// A set of widgets indexed by id
|
|
|
359 |
this._hash={};
|
|
|
360 |
},
|
|
|
361 |
|
|
|
362 |
add: function(/*Widget*/ widget){
|
|
|
363 |
if(this._hash[widget.id]){
|
|
|
364 |
throw new Error("Tried to register widget with id==" + widget.id + " but that id is already registered");
|
|
|
365 |
}
|
|
|
366 |
this._hash[widget.id]=widget;
|
|
|
367 |
},
|
|
|
368 |
|
|
|
369 |
remove: function(/*String*/ id){
|
|
|
370 |
delete this._hash[id];
|
|
|
371 |
},
|
|
|
372 |
|
|
|
373 |
forEach: function(/*Function*/ func){
|
|
|
374 |
for(var id in this._hash){
|
|
|
375 |
func(this._hash[id]);
|
|
|
376 |
}
|
|
|
377 |
},
|
|
|
378 |
|
|
|
379 |
filter: function(/*Function*/ filter){
|
|
|
380 |
var res = new dijit.WidgetSet();
|
|
|
381 |
this.forEach(function(widget){
|
|
|
382 |
if(filter(widget)){ res.add(widget); }
|
|
|
383 |
});
|
|
|
384 |
return res; // dijit.WidgetSet
|
|
|
385 |
},
|
|
|
386 |
|
|
|
387 |
byId: function(/*String*/ id){
|
|
|
388 |
return this._hash[id];
|
|
|
389 |
},
|
|
|
390 |
|
|
|
391 |
byClass: function(/*String*/ cls){
|
|
|
392 |
return this.filter(function(widget){ return widget.declaredClass==cls; }); // dijit.WidgetSet
|
|
|
393 |
}
|
|
|
394 |
});
|
|
|
395 |
|
|
|
396 |
// registry: list of all widgets on page
|
|
|
397 |
dijit.registry = new dijit.WidgetSet();
|
|
|
398 |
|
|
|
399 |
dijit._widgetTypeCtr = {};
|
|
|
400 |
|
|
|
401 |
dijit.getUniqueId = function(/*String*/widgetType){
|
|
|
402 |
// summary
|
|
|
403 |
// Generates a unique id for a given widgetType
|
|
|
404 |
|
|
|
405 |
var id;
|
|
|
406 |
do{
|
|
|
407 |
id = widgetType + "_" +
|
|
|
408 |
(dijit._widgetTypeCtr[widgetType] !== undefined ?
|
|
|
409 |
++dijit._widgetTypeCtr[widgetType] : dijit._widgetTypeCtr[widgetType] = 0);
|
|
|
410 |
}while(dijit.byId(id));
|
|
|
411 |
return id; // String
|
|
|
412 |
};
|
|
|
413 |
|
|
|
414 |
|
|
|
415 |
if(dojo.isIE){
|
|
|
416 |
// Only run this for IE because we think it's only necessary in that case,
|
|
|
417 |
// and because it causes problems on FF. See bug #3531 for details.
|
|
|
418 |
dojo.addOnUnload(function(){
|
|
|
419 |
dijit.registry.forEach(function(widget){ widget.destroy(); });
|
|
|
420 |
});
|
|
|
421 |
}
|
|
|
422 |
|
|
|
423 |
dijit.byId = function(/*String|Widget*/id){
|
|
|
424 |
// summary:
|
|
|
425 |
// Returns a widget by its id, or if passed a widget, no-op (like dojo.byId())
|
|
|
426 |
return (dojo.isString(id)) ? dijit.registry.byId(id) : id; // Widget
|
|
|
427 |
};
|
|
|
428 |
|
|
|
429 |
dijit.byNode = function(/* DOMNode */ node){
|
|
|
430 |
// summary:
|
|
|
431 |
// Returns the widget as referenced by node
|
|
|
432 |
return dijit.registry.byId(node.getAttribute("widgetId")); // Widget
|
|
|
433 |
};
|
|
|
434 |
|
|
|
435 |
dijit.getEnclosingWidget = function(/* DOMNode */ node){
|
|
|
436 |
// summary:
|
|
|
437 |
// Returns the widget whose dom tree contains node or null if
|
|
|
438 |
// the node is not contained within the dom tree of any widget
|
|
|
439 |
while(node){
|
|
|
440 |
if(node.getAttribute && node.getAttribute("widgetId")){
|
|
|
441 |
return dijit.registry.byId(node.getAttribute("widgetId"));
|
|
|
442 |
}
|
|
|
443 |
node = node.parentNode;
|
|
|
444 |
}
|
|
|
445 |
return null;
|
|
|
446 |
};
|
|
|
447 |
|
|
|
448 |
}
|
|
|
449 |
|
|
|
450 |
if(!dojo._hasResource["dijit._base.place"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
451 |
dojo._hasResource["dijit._base.place"] = true;
|
|
|
452 |
dojo.provide("dijit._base.place");
|
|
|
453 |
|
|
|
454 |
// ported from dojo.html.util
|
|
|
455 |
|
|
|
456 |
dijit.getViewport = function(){
|
|
|
457 |
// summary
|
|
|
458 |
// Returns the dimensions and scroll position of the viewable area of a browser window
|
|
|
459 |
|
|
|
460 |
var _window = dojo.global;
|
|
|
461 |
var _document = dojo.doc;
|
|
|
462 |
|
|
|
463 |
// get viewport size
|
|
|
464 |
var w = 0, h = 0;
|
|
|
465 |
if(dojo.isMozilla){
|
|
|
466 |
// mozilla
|
|
|
467 |
// _window.innerHeight includes the height taken by the scroll bar
|
|
|
468 |
// clientHeight is ideal but has DTD issues:
|
|
|
469 |
// #4539: FF reverses the roles of body.clientHeight/Width and documentElement.clientHeight/Width based on the DTD!
|
|
|
470 |
// check DTD to see whether body or documentElement returns the viewport dimensions using this algorithm:
|
|
|
471 |
var minw, minh, maxw, maxh;
|
|
|
472 |
if(_document.body.clientWidth>_document.documentElement.clientWidth){
|
|
|
473 |
minw = _document.documentElement.clientWidth;
|
|
|
474 |
maxw = _document.body.clientWidth;
|
|
|
475 |
}else{
|
|
|
476 |
maxw = _document.documentElement.clientWidth;
|
|
|
477 |
minw = _document.body.clientWidth;
|
|
|
478 |
}
|
|
|
479 |
if(_document.body.clientHeight>_document.documentElement.clientHeight){
|
|
|
480 |
minh = _document.documentElement.clientHeight;
|
|
|
481 |
maxh = _document.body.clientHeight;
|
|
|
482 |
}else{
|
|
|
483 |
maxh = _document.documentElement.clientHeight;
|
|
|
484 |
minh = _document.body.clientHeight;
|
|
|
485 |
}
|
|
|
486 |
w = (maxw > _window.innerWidth) ? minw : maxw;
|
|
|
487 |
h = (maxh > _window.innerHeight) ? minh : maxh;
|
|
|
488 |
}else if(!dojo.isOpera && _window.innerWidth){
|
|
|
489 |
//in opera9, dojo.body().clientWidth should be used, instead
|
|
|
490 |
//of window.innerWidth/document.documentElement.clientWidth
|
|
|
491 |
//so we have to check whether it is opera
|
|
|
492 |
w = _window.innerWidth;
|
|
|
493 |
h = _window.innerHeight;
|
|
|
494 |
}else if(dojo.isIE && _document.documentElement && _document.documentElement.clientHeight){
|
|
|
495 |
w = _document.documentElement.clientWidth;
|
|
|
496 |
h = _document.documentElement.clientHeight;
|
|
|
497 |
}else if(dojo.body().clientWidth){
|
|
|
498 |
// IE5, Opera
|
|
|
499 |
w = dojo.body().clientWidth;
|
|
|
500 |
h = dojo.body().clientHeight;
|
|
|
501 |
}
|
|
|
502 |
|
|
|
503 |
// get scroll position
|
|
|
504 |
var scroll = dojo._docScroll();
|
|
|
505 |
|
|
|
506 |
return { w: w, h: h, l: scroll.x, t: scroll.y }; // object
|
|
|
507 |
};
|
|
|
508 |
|
|
|
509 |
dijit.placeOnScreen = function(
|
|
|
510 |
/* DomNode */ node,
|
|
|
511 |
/* Object */ pos,
|
|
|
512 |
/* Object */ corners,
|
|
|
513 |
/* boolean? */ tryOnly){
|
|
|
514 |
// summary:
|
|
|
515 |
// Keeps 'node' in the visible area of the screen while trying to
|
|
|
516 |
// place closest to pos.x, pos.y. The input coordinates are
|
|
|
517 |
// expected to be the desired document position.
|
|
|
518 |
//
|
|
|
519 |
// Set which corner(s) you want to bind to, such as
|
|
|
520 |
//
|
|
|
521 |
// placeOnScreen(node, {x: 10, y: 20}, ["TR", "BL"])
|
|
|
522 |
//
|
|
|
523 |
// The desired x/y will be treated as the topleft(TL)/topright(TR) or
|
|
|
524 |
// BottomLeft(BL)/BottomRight(BR) corner of the node. Each corner is tested
|
|
|
525 |
// and if a perfect match is found, it will be used. Otherwise, it goes through
|
|
|
526 |
// all of the specified corners, and choose the most appropriate one.
|
|
|
527 |
//
|
|
|
528 |
// NOTE: node is assumed to be absolutely or relatively positioned.
|
|
|
529 |
|
|
|
530 |
var choices = dojo.map(corners, function(corner){ return { corner: corner, pos: pos }; });
|
|
|
531 |
|
|
|
532 |
return dijit._place(node, choices);
|
|
|
533 |
}
|
|
|
534 |
|
|
|
535 |
dijit._place = function(/*DomNode*/ node, /* Array */ choices, /* Function */ layoutNode){
|
|
|
536 |
// summary:
|
|
|
537 |
// Given a list of spots to put node, put it at the first spot where it fits,
|
|
|
538 |
// of if it doesn't fit anywhere then the place with the least overflow
|
|
|
539 |
// choices: Array
|
|
|
540 |
// Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} }
|
|
|
541 |
// Above example says to put the top-left corner of the node at (10,20)
|
|
|
542 |
// layoutNode: Function(node, orient)
|
|
|
543 |
// for things like tooltip, they are displayed differently (and have different dimensions)
|
|
|
544 |
// based on their orientation relative to the parent. This adjusts the popup based on orientation.
|
|
|
545 |
|
|
|
546 |
// get {x: 10, y: 10, w: 100, h:100} type obj representing position of
|
|
|
547 |
// viewport over document
|
|
|
548 |
var view = dijit.getViewport();
|
|
|
549 |
|
|
|
550 |
// This won't work if the node is inside a <div style="position: relative">,
|
|
|
551 |
// so reattach it to document.body. (Otherwise, the positioning will be wrong
|
|
|
552 |
// and also it might get cutoff)
|
|
|
553 |
if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){
|
|
|
554 |
dojo.body().appendChild(node);
|
|
|
555 |
}
|
|
|
556 |
|
|
|
557 |
var best=null;
|
|
|
558 |
for(var i=0; i<choices.length; i++){
|
|
|
559 |
var corner = choices[i].corner;
|
|
|
560 |
var pos = choices[i].pos;
|
|
|
561 |
|
|
|
562 |
// configure node to be displayed in given position relative to button
|
|
|
563 |
// (need to do this in order to get an accurate size for the node, because
|
|
|
564 |
// a tooltips size changes based on position, due to triangle)
|
|
|
565 |
if(layoutNode){
|
|
|
566 |
layoutNode(corner);
|
|
|
567 |
}
|
|
|
568 |
|
|
|
569 |
// get node's size
|
|
|
570 |
var oldDisplay = node.style.display;
|
|
|
571 |
var oldVis = node.style.visibility;
|
|
|
572 |
node.style.visibility = "hidden";
|
|
|
573 |
node.style.display = "";
|
|
|
574 |
var mb = dojo.marginBox(node);
|
|
|
575 |
node.style.display = oldDisplay;
|
|
|
576 |
node.style.visibility = oldVis;
|
|
|
577 |
|
|
|
578 |
// coordinates and size of node with specified corner placed at pos,
|
|
|
579 |
// and clipped by viewport
|
|
|
580 |
var startX = (corner.charAt(1)=='L' ? pos.x : Math.max(view.l, pos.x - mb.w)),
|
|
|
581 |
startY = (corner.charAt(0)=='T' ? pos.y : Math.max(view.t, pos.y - mb.h)),
|
|
|
582 |
endX = (corner.charAt(1)=='L' ? Math.min(view.l+view.w, startX+mb.w) : pos.x),
|
|
|
583 |
endY = (corner.charAt(0)=='T' ? Math.min(view.t+view.h, startY+mb.h) : pos.y),
|
|
|
584 |
width = endX-startX,
|
|
|
585 |
height = endY-startY,
|
|
|
586 |
overflow = (mb.w-width) + (mb.h-height);
|
|
|
587 |
|
|
|
588 |
if(best==null || overflow<best.overflow){
|
|
|
589 |
best = {
|
|
|
590 |
corner: corner,
|
|
|
591 |
aroundCorner: choices[i].aroundCorner,
|
|
|
592 |
x: startX,
|
|
|
593 |
y: startY,
|
|
|
594 |
w: width,
|
|
|
595 |
h: height,
|
|
|
596 |
overflow: overflow
|
|
|
597 |
};
|
|
|
598 |
}
|
|
|
599 |
if(overflow==0){
|
|
|
600 |
break;
|
|
|
601 |
}
|
|
|
602 |
}
|
|
|
603 |
|
|
|
604 |
node.style.left = best.x + "px";
|
|
|
605 |
node.style.top = best.y + "px";
|
|
|
606 |
return best;
|
|
|
607 |
}
|
|
|
608 |
|
|
|
609 |
dijit.placeOnScreenAroundElement = function(
|
|
|
610 |
/* DomNode */ node,
|
|
|
611 |
/* DomNode */ aroundNode,
|
|
|
612 |
/* Object */ aroundCorners,
|
|
|
613 |
/* Function */ layoutNode){
|
|
|
614 |
|
|
|
615 |
// summary
|
|
|
616 |
// Like placeOnScreen, except it accepts aroundNode instead of x,y
|
|
|
617 |
// and attempts to place node around it. Uses margin box dimensions.
|
|
|
618 |
//
|
|
|
619 |
// aroundCorners
|
|
|
620 |
// specify Which corner of aroundNode should be
|
|
|
621 |
// used to place the node => which corner(s) of node to use (see the
|
|
|
622 |
// corners parameter in dijit.placeOnScreen)
|
|
|
623 |
// e.g. {'TL': 'BL', 'BL': 'TL'}
|
|
|
624 |
//
|
|
|
625 |
// layoutNode: Function(node, orient)
|
|
|
626 |
// for things like tooltip, they are displayed differently (and have different dimensions)
|
|
|
627 |
// based on their orientation relative to the parent. This adjusts the popup based on orientation.
|
|
|
628 |
|
|
|
629 |
|
|
|
630 |
// get coordinates of aroundNode
|
|
|
631 |
aroundNode = dojo.byId(aroundNode);
|
|
|
632 |
var oldDisplay = aroundNode.style.display;
|
|
|
633 |
aroundNode.style.display="";
|
|
|
634 |
// #3172: use the slightly tighter border box instead of marginBox
|
|
|
635 |
var aroundNodeW = aroundNode.offsetWidth; //mb.w;
|
|
|
636 |
var aroundNodeH = aroundNode.offsetHeight; //mb.h;
|
|
|
637 |
var aroundNodePos = dojo.coords(aroundNode, true);
|
|
|
638 |
aroundNode.style.display=oldDisplay;
|
|
|
639 |
|
|
|
640 |
// Generate list of possible positions for node
|
|
|
641 |
var choices = [];
|
|
|
642 |
for(var nodeCorner in aroundCorners){
|
|
|
643 |
choices.push( {
|
|
|
644 |
aroundCorner: nodeCorner,
|
|
|
645 |
corner: aroundCorners[nodeCorner],
|
|
|
646 |
pos: {
|
|
|
647 |
x: aroundNodePos.x + (nodeCorner.charAt(1)=='L' ? 0 : aroundNodeW),
|
|
|
648 |
y: aroundNodePos.y + (nodeCorner.charAt(0)=='T' ? 0 : aroundNodeH)
|
|
|
649 |
}
|
|
|
650 |
});
|
|
|
651 |
}
|
|
|
652 |
|
|
|
653 |
return dijit._place(node, choices, layoutNode);
|
|
|
654 |
}
|
|
|
655 |
|
|
|
656 |
}
|
|
|
657 |
|
|
|
658 |
if(!dojo._hasResource["dijit._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
659 |
dojo._hasResource["dijit._base.window"] = true;
|
|
|
660 |
dojo.provide("dijit._base.window");
|
|
|
661 |
|
|
|
662 |
dijit.getDocumentWindow = function(doc){
|
|
|
663 |
// summary
|
|
|
664 |
// Get window object associated with document doc
|
|
|
665 |
|
|
|
666 |
// With Safari, there is not way to retrieve the window from the document, so we must fix it.
|
|
|
667 |
if(dojo.isSafari && !doc._parentWindow){
|
|
|
668 |
/*
|
|
|
669 |
This is a Safari specific function that fix the reference to the parent
|
|
|
670 |
window from the document object.
|
|
|
671 |
*/
|
|
|
672 |
var fix=function(win){
|
|
|
673 |
win.document._parentWindow=win;
|
|
|
674 |
for(var i=0; i<win.frames.length; i++){
|
|
|
675 |
fix(win.frames[i]);
|
|
|
676 |
}
|
|
|
677 |
}
|
|
|
678 |
fix(window.top);
|
|
|
679 |
}
|
|
|
680 |
|
|
|
681 |
//In some IE versions (at least 6.0), document.parentWindow does not return a
|
|
|
682 |
//reference to the real window object (maybe a copy), so we must fix it as well
|
|
|
683 |
//We use IE specific execScript to attach the real window reference to
|
|
|
684 |
//document._parentWindow for later use
|
|
|
685 |
if(dojo.isIE && window !== document.parentWindow && !doc._parentWindow){
|
|
|
686 |
/*
|
|
|
687 |
In IE 6, only the variable "window" can be used to connect events (others
|
|
|
688 |
may be only copies).
|
|
|
689 |
*/
|
|
|
690 |
doc.parentWindow.execScript("document._parentWindow = window;", "Javascript");
|
|
|
691 |
//to prevent memory leak, unset it after use
|
|
|
692 |
//another possibility is to add an onUnload handler which seems overkill to me (liucougar)
|
|
|
693 |
var win = doc._parentWindow;
|
|
|
694 |
doc._parentWindow = null;
|
|
|
695 |
return win; // Window
|
|
|
696 |
}
|
|
|
697 |
|
|
|
698 |
return doc._parentWindow || doc.parentWindow || doc.defaultView; // Window
|
|
|
699 |
}
|
|
|
700 |
|
|
|
701 |
}
|
|
|
702 |
|
|
|
703 |
if(!dojo._hasResource["dijit._base.popup"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
704 |
dojo._hasResource["dijit._base.popup"] = true;
|
|
|
705 |
dojo.provide("dijit._base.popup");
|
|
|
706 |
|
|
|
707 |
|
|
|
708 |
|
|
|
709 |
|
|
|
710 |
|
|
|
711 |
dijit.popup = new function(){
|
|
|
712 |
// summary:
|
|
|
713 |
// This class is used to show/hide widgets as popups.
|
|
|
714 |
//
|
|
|
715 |
|
|
|
716 |
var stack = [],
|
|
|
717 |
beginZIndex=1000,
|
|
|
718 |
idGen = 1;
|
|
|
719 |
|
|
|
720 |
this.open = function(/*Object*/ args){
|
|
|
721 |
// summary:
|
|
|
722 |
// Popup the widget at the specified position
|
|
|
723 |
//
|
|
|
724 |
// args: Object
|
|
|
725 |
// popup: Widget
|
|
|
726 |
// widget to display,
|
|
|
727 |
// parent: Widget
|
|
|
728 |
// the button etc. that is displaying this popup
|
|
|
729 |
// around: DomNode
|
|
|
730 |
// DOM node (typically a button); place popup relative to this node
|
|
|
731 |
// orient: Object
|
|
|
732 |
// structure specifying possible positions of popup relative to "around" node
|
|
|
733 |
// onCancel: Function
|
|
|
734 |
// callback when user has canceled the popup by
|
|
|
735 |
// 1. hitting ESC or
|
|
|
736 |
// 2. by using the popup widget's proprietary cancel mechanism (like a cancel button in a dialog);
|
|
|
737 |
// ie: whenever popupWidget.onCancel() is called, args.onCancel is called
|
|
|
738 |
// onClose: Function
|
|
|
739 |
// callback whenever this popup is closed
|
|
|
740 |
// onExecute: Function
|
|
|
741 |
// callback when user "executed" on the popup/sub-popup by selecting a menu choice, etc. (top menu only)
|
|
|
742 |
//
|
|
|
743 |
// examples:
|
|
|
744 |
// 1. opening at the mouse position
|
|
|
745 |
// dijit.popup.open({popup: menuWidget, x: evt.pageX, y: evt.pageY});
|
|
|
746 |
// 2. opening the widget as a dropdown
|
|
|
747 |
// dijit.popup.open({parent: this, popup: menuWidget, around: this.domNode, onClose: function(){...} });
|
|
|
748 |
//
|
|
|
749 |
// Note that whatever widget called dijit.popup.open() should also listen to it's own _onBlur callback
|
|
|
750 |
// (fired from _base/focus.js) to know that focus has moved somewhere else and thus the popup should be closed.
|
|
|
751 |
|
|
|
752 |
var widget = args.popup,
|
|
|
753 |
orient = args.orient || {'BL':'TL', 'TL':'BL'},
|
|
|
754 |
around = args.around,
|
|
|
755 |
id = (args.around && args.around.id) ? (args.around.id+"_dropdown") : ("popup_"+idGen++);
|
|
|
756 |
|
|
|
757 |
// make wrapper div to hold widget and possibly hold iframe behind it.
|
|
|
758 |
// we can't attach the iframe as a child of the widget.domNode because
|
|
|
759 |
// widget.domNode might be a <table>, <ul>, etc.
|
|
|
760 |
var wrapper = dojo.doc.createElement("div");
|
|
|
761 |
wrapper.id = id;
|
|
|
762 |
wrapper.className="dijitPopup";
|
|
|
763 |
wrapper.style.zIndex = beginZIndex + stack.length;
|
|
|
764 |
wrapper.style.visibility = "hidden";
|
|
|
765 |
if(args.parent){
|
|
|
766 |
wrapper.dijitPopupParent=args.parent.id;
|
|
|
767 |
}
|
|
|
768 |
dojo.body().appendChild(wrapper);
|
|
|
769 |
|
|
|
770 |
widget.domNode.style.display="";
|
|
|
771 |
wrapper.appendChild(widget.domNode);
|
|
|
772 |
|
|
|
773 |
var iframe = new dijit.BackgroundIframe(wrapper);
|
|
|
774 |
|
|
|
775 |
// position the wrapper node
|
|
|
776 |
var best = around ?
|
|
|
777 |
dijit.placeOnScreenAroundElement(wrapper, around, orient, widget.orient ? dojo.hitch(widget, "orient") : null) :
|
|
|
778 |
dijit.placeOnScreen(wrapper, args, orient == 'R' ? ['TR','BR','TL','BL'] : ['TL','BL','TR','BR']);
|
|
|
779 |
|
|
|
780 |
wrapper.style.visibility = "visible";
|
|
|
781 |
// TODO: use effects to fade in wrapper
|
|
|
782 |
|
|
|
783 |
var handlers = [];
|
|
|
784 |
|
|
|
785 |
// Compute the closest ancestor popup that's *not* a child of another popup.
|
|
|
786 |
// Ex: For a TooltipDialog with a button that spawns a tree of menus, find the popup of the button.
|
|
|
787 |
function getTopPopup(){
|
|
|
788 |
for(var pi=stack.length-1; pi > 0 && stack[pi].parent === stack[pi-1].widget; pi--);
|
|
|
789 |
return stack[pi];
|
|
|
790 |
}
|
|
|
791 |
|
|
|
792 |
// provide default escape and tab key handling
|
|
|
793 |
// (this will work for any widget, not just menu)
|
|
|
794 |
handlers.push(dojo.connect(wrapper, "onkeypress", this, function(evt){
|
|
|
795 |
if(evt.keyCode == dojo.keys.ESCAPE && args.onCancel){
|
|
|
796 |
args.onCancel();
|
|
|
797 |
}else if(evt.keyCode == dojo.keys.TAB){
|
|
|
798 |
dojo.stopEvent(evt);
|
|
|
799 |
var topPopup = getTopPopup();
|
|
|
800 |
if(topPopup && topPopup.onCancel){
|
|
|
801 |
topPopup.onCancel();
|
|
|
802 |
}
|
|
|
803 |
}
|
|
|
804 |
}));
|
|
|
805 |
|
|
|
806 |
// watch for cancel/execute events on the popup and notify the caller
|
|
|
807 |
// (for a menu, "execute" means clicking an item)
|
|
|
808 |
if(widget.onCancel){
|
|
|
809 |
handlers.push(dojo.connect(widget, "onCancel", null, args.onCancel));
|
|
|
810 |
}
|
|
|
811 |
|
|
|
812 |
handlers.push(dojo.connect(widget, widget.onExecute ? "onExecute" : "onChange", null, function(){
|
|
|
813 |
var topPopup = getTopPopup();
|
|
|
814 |
if(topPopup && topPopup.onExecute){
|
|
|
815 |
topPopup.onExecute();
|
|
|
816 |
}
|
|
|
817 |
}));
|
|
|
818 |
|
|
|
819 |
stack.push({
|
|
|
820 |
wrapper: wrapper,
|
|
|
821 |
iframe: iframe,
|
|
|
822 |
widget: widget,
|
|
|
823 |
parent: args.parent,
|
|
|
824 |
onExecute: args.onExecute,
|
|
|
825 |
onCancel: args.onCancel,
|
|
|
826 |
onClose: args.onClose,
|
|
|
827 |
handlers: handlers
|
|
|
828 |
});
|
|
|
829 |
|
|
|
830 |
if(widget.onOpen){
|
|
|
831 |
widget.onOpen(best);
|
|
|
832 |
}
|
|
|
833 |
|
|
|
834 |
return best;
|
|
|
835 |
};
|
|
|
836 |
|
|
|
837 |
this.close = function(/*Widget*/ popup){
|
|
|
838 |
// summary:
|
|
|
839 |
// Close specified popup and any popups that it parented
|
|
|
840 |
while(dojo.some(stack, function(elem){return elem.widget == popup;})){
|
|
|
841 |
var top = stack.pop(),
|
|
|
842 |
wrapper = top.wrapper,
|
|
|
843 |
iframe = top.iframe,
|
|
|
844 |
widget = top.widget,
|
|
|
845 |
onClose = top.onClose;
|
|
|
846 |
|
|
|
847 |
if(widget.onClose){
|
|
|
848 |
widget.onClose();
|
|
|
849 |
}
|
|
|
850 |
dojo.forEach(top.handlers, dojo.disconnect);
|
|
|
851 |
|
|
|
852 |
// #2685: check if the widget still has a domNode so ContentPane can change its URL without getting an error
|
|
|
853 |
if(!widget||!widget.domNode){ return; }
|
|
|
854 |
dojo.style(widget.domNode, "display", "none");
|
|
|
855 |
dojo.body().appendChild(widget.domNode);
|
|
|
856 |
iframe.destroy();
|
|
|
857 |
dojo._destroyElement(wrapper);
|
|
|
858 |
|
|
|
859 |
if(onClose){
|
|
|
860 |
onClose();
|
|
|
861 |
}
|
|
|
862 |
}
|
|
|
863 |
};
|
|
|
864 |
}();
|
|
|
865 |
|
|
|
866 |
dijit._frames = new function(){
|
|
|
867 |
// summary: cache of iframes
|
|
|
868 |
var queue = [];
|
|
|
869 |
|
|
|
870 |
this.pop = function(){
|
|
|
871 |
var iframe;
|
|
|
872 |
if(queue.length){
|
|
|
873 |
iframe = queue.pop();
|
|
|
874 |
iframe.style.display="";
|
|
|
875 |
}else{
|
|
|
876 |
if(dojo.isIE){
|
|
|
877 |
var html="<iframe src='javascript:\"\"'"
|
|
|
878 |
+ " style='position: absolute; left: 0px; top: 0px;"
|
|
|
879 |
+ "z-index: -1; filter:Alpha(Opacity=\"0\");'>";
|
|
|
880 |
iframe = dojo.doc.createElement(html);
|
|
|
881 |
}else{
|
|
|
882 |
var iframe = dojo.doc.createElement("iframe");
|
|
|
883 |
iframe.src = 'javascript:""';
|
|
|
884 |
iframe.className = "dijitBackgroundIframe";
|
|
|
885 |
}
|
|
|
886 |
iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didnt work.
|
|
|
887 |
dojo.body().appendChild(iframe);
|
|
|
888 |
}
|
|
|
889 |
return iframe;
|
|
|
890 |
};
|
|
|
891 |
|
|
|
892 |
this.push = function(iframe){
|
|
|
893 |
iframe.style.display="";
|
|
|
894 |
if(dojo.isIE){
|
|
|
895 |
iframe.style.removeExpression("width");
|
|
|
896 |
iframe.style.removeExpression("height");
|
|
|
897 |
}
|
|
|
898 |
queue.push(iframe);
|
|
|
899 |
}
|
|
|
900 |
}();
|
|
|
901 |
|
|
|
902 |
// fill the queue
|
|
|
903 |
if(dojo.isIE && dojo.isIE < 7){
|
|
|
904 |
dojo.addOnLoad(function(){
|
|
|
905 |
var f = dijit._frames;
|
|
|
906 |
dojo.forEach([f.pop()], f.push);
|
|
|
907 |
});
|
|
|
908 |
}
|
|
|
909 |
|
|
|
910 |
|
|
|
911 |
dijit.BackgroundIframe = function(/* DomNode */node){
|
|
|
912 |
// summary:
|
|
|
913 |
// For IE z-index schenanigans. id attribute is required.
|
|
|
914 |
//
|
|
|
915 |
// description:
|
|
|
916 |
// new dijit.BackgroundIframe(node)
|
|
|
917 |
// Makes a background iframe as a child of node, that fills
|
|
|
918 |
// area (and position) of node
|
|
|
919 |
|
|
|
920 |
if(!node.id){ throw new Error("no id"); }
|
|
|
921 |
if((dojo.isIE && dojo.isIE < 7) || (dojo.isFF && dojo.isFF < 3 && dojo.hasClass(dojo.body(), "dijit_a11y"))){
|
|
|
922 |
var iframe = dijit._frames.pop();
|
|
|
923 |
node.appendChild(iframe);
|
|
|
924 |
if(dojo.isIE){
|
|
|
925 |
iframe.style.setExpression("width", "document.getElementById('" + node.id + "').offsetWidth");
|
|
|
926 |
iframe.style.setExpression("height", "document.getElementById('" + node.id + "').offsetHeight");
|
|
|
927 |
}
|
|
|
928 |
this.iframe = iframe;
|
|
|
929 |
}
|
|
|
930 |
};
|
|
|
931 |
|
|
|
932 |
dojo.extend(dijit.BackgroundIframe, {
|
|
|
933 |
destroy: function(){
|
|
|
934 |
// summary: destroy the iframe
|
|
|
935 |
if(this.iframe){
|
|
|
936 |
dijit._frames.push(this.iframe);
|
|
|
937 |
delete this.iframe;
|
|
|
938 |
}
|
|
|
939 |
}
|
|
|
940 |
});
|
|
|
941 |
|
|
|
942 |
}
|
|
|
943 |
|
|
|
944 |
if(!dojo._hasResource["dijit._base.scroll"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
945 |
dojo._hasResource["dijit._base.scroll"] = true;
|
|
|
946 |
dojo.provide("dijit._base.scroll");
|
|
|
947 |
|
|
|
948 |
dijit.scrollIntoView = function(/* DomNode */node){
|
|
|
949 |
// summary
|
|
|
950 |
// Scroll the passed node into view, if it is not.
|
|
|
951 |
|
|
|
952 |
// don't rely on that node.scrollIntoView works just because the function is there
|
|
|
953 |
// it doesnt work in Konqueror or Opera even though the function is there and probably
|
|
|
954 |
// not safari either
|
|
|
955 |
// dont like browser sniffs implementations but sometimes you have to use it
|
|
|
956 |
if(dojo.isIE){
|
|
|
957 |
//only call scrollIntoView if there is a scrollbar for this menu,
|
|
|
958 |
//otherwise, scrollIntoView will scroll the window scrollbar
|
|
|
959 |
if(dojo.marginBox(node.parentNode).h <= node.parentNode.scrollHeight){ //PORT was getBorderBox
|
|
|
960 |
node.scrollIntoView(false);
|
|
|
961 |
}
|
|
|
962 |
}else if(dojo.isMozilla){
|
|
|
963 |
node.scrollIntoView(false);
|
|
|
964 |
}else{
|
|
|
965 |
var parent = node.parentNode;
|
|
|
966 |
var parentBottom = parent.scrollTop + dojo.marginBox(parent).h; //PORT was getBorderBox
|
|
|
967 |
var nodeBottom = node.offsetTop + dojo.marginBox(node).h;
|
|
|
968 |
if(parentBottom < nodeBottom){
|
|
|
969 |
parent.scrollTop += (nodeBottom - parentBottom);
|
|
|
970 |
}else if(parent.scrollTop > node.offsetTop){
|
|
|
971 |
parent.scrollTop -= (parent.scrollTop - node.offsetTop);
|
|
|
972 |
}
|
|
|
973 |
}
|
|
|
974 |
};
|
|
|
975 |
|
|
|
976 |
}
|
|
|
977 |
|
|
|
978 |
if(!dojo._hasResource["dijit._base.sniff"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
979 |
dojo._hasResource["dijit._base.sniff"] = true;
|
|
|
980 |
dojo.provide("dijit._base.sniff");
|
|
|
981 |
|
|
|
982 |
// ported from dojo.html.applyBrowserClass (style.js)
|
|
|
983 |
|
|
|
984 |
// summary:
|
|
|
985 |
// Applies pre-set class names based on browser & version to the
|
|
|
986 |
// top-level HTML node. Simply doing a require on this module will
|
|
|
987 |
// establish this CSS. Modified version of Morris' CSS hack.
|
|
|
988 |
(function(){
|
|
|
989 |
var d = dojo;
|
|
|
990 |
var ie = d.isIE;
|
|
|
991 |
var opera = d.isOpera;
|
|
|
992 |
var maj = Math.floor;
|
|
|
993 |
var classes = {
|
|
|
994 |
dj_ie: ie,
|
|
|
995 |
// dj_ie55: ie == 5.5,
|
|
|
996 |
dj_ie6: maj(ie) == 6,
|
|
|
997 |
dj_ie7: maj(ie) == 7,
|
|
|
998 |
dj_iequirks: ie && d.isQuirks,
|
|
|
999 |
// NOTE: Opera not supported by dijit
|
|
|
1000 |
dj_opera: opera,
|
|
|
1001 |
dj_opera8: maj(opera) == 8,
|
|
|
1002 |
dj_opera9: maj(opera) == 9,
|
|
|
1003 |
dj_khtml: d.isKhtml,
|
|
|
1004 |
dj_safari: d.isSafari,
|
|
|
1005 |
dj_gecko: d.isMozilla
|
|
|
1006 |
}; // no dojo unsupported browsers
|
|
|
1007 |
|
|
|
1008 |
for(var p in classes){
|
|
|
1009 |
if(classes[p]){
|
|
|
1010 |
var html = dojo.doc.documentElement; //TODO browser-specific DOM magic needed?
|
|
|
1011 |
if(html.className){
|
|
|
1012 |
html.className += " " + p;
|
|
|
1013 |
}else{
|
|
|
1014 |
html.className = p;
|
|
|
1015 |
}
|
|
|
1016 |
}
|
|
|
1017 |
}
|
|
|
1018 |
})();
|
|
|
1019 |
|
|
|
1020 |
}
|
|
|
1021 |
|
|
|
1022 |
if(!dojo._hasResource["dijit._base.bidi"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
1023 |
dojo._hasResource["dijit._base.bidi"] = true;
|
|
|
1024 |
dojo.provide("dijit._base.bidi");
|
|
|
1025 |
|
|
|
1026 |
// summary: applies a class to the top of the document for right-to-left stylesheet rules
|
|
|
1027 |
|
|
|
1028 |
dojo.addOnLoad(function(){
|
|
|
1029 |
if(!dojo._isBodyLtr()){
|
|
|
1030 |
dojo.addClass(dojo.body(), "dijitRtl");
|
|
|
1031 |
}
|
|
|
1032 |
});
|
|
|
1033 |
|
|
|
1034 |
}
|
|
|
1035 |
|
|
|
1036 |
if(!dojo._hasResource["dijit._base.typematic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
1037 |
dojo._hasResource["dijit._base.typematic"] = true;
|
|
|
1038 |
dojo.provide("dijit._base.typematic");
|
|
|
1039 |
|
|
|
1040 |
dijit.typematic = {
|
|
|
1041 |
// summary:
|
|
|
1042 |
// These functions are used to repetitively call a user specified callback
|
|
|
1043 |
// method when a specific key or mouse click over a specific DOM node is
|
|
|
1044 |
// held down for a specific amount of time.
|
|
|
1045 |
// Only 1 such event is allowed to occur on the browser page at 1 time.
|
|
|
1046 |
|
|
|
1047 |
_fireEventAndReload: function(){
|
|
|
1048 |
this._timer = null;
|
|
|
1049 |
this._callback(++this._count, this._node, this._evt);
|
|
|
1050 |
this._currentTimeout = (this._currentTimeout < 0) ? this._initialDelay : ((this._subsequentDelay > 1) ? this._subsequentDelay : Math.round(this._currentTimeout * this._subsequentDelay));
|
|
|
1051 |
this._timer = setTimeout(dojo.hitch(this, "_fireEventAndReload"), this._currentTimeout);
|
|
|
1052 |
},
|
|
|
1053 |
|
|
|
1054 |
trigger: function(/*Event*/ evt, /* Object */ _this, /*DOMNode*/ node, /* Function */ callback, /* Object */ obj, /* Number */ subsequentDelay, /* Number */ initialDelay){
|
|
|
1055 |
// summary:
|
|
|
1056 |
// Start a timed, repeating callback sequence.
|
|
|
1057 |
// If already started, the function call is ignored.
|
|
|
1058 |
// This method is not normally called by the user but can be
|
|
|
1059 |
// when the normal listener code is insufficient.
|
|
|
1060 |
// Parameters:
|
|
|
1061 |
// evt: key or mouse event object to pass to the user callback
|
|
|
1062 |
// _this: pointer to the user's widget space.
|
|
|
1063 |
// node: the DOM node object to pass the the callback function
|
|
|
1064 |
// callback: function to call until the sequence is stopped called with 3 parameters:
|
|
|
1065 |
// count: integer representing number of repeated calls (0..n) with -1 indicating the iteration has stopped
|
|
|
1066 |
// node: the DOM node object passed in
|
|
|
1067 |
// evt: key or mouse event object
|
|
|
1068 |
// obj: user space object used to uniquely identify each typematic sequence
|
|
|
1069 |
// subsequentDelay: if > 1, the number of milliseconds until the 3->n events occur
|
|
|
1070 |
// or else the fractional time multiplier for the next event's delay, default=0.9
|
|
|
1071 |
// initialDelay: the number of milliseconds until the 2nd event occurs, default=500ms
|
|
|
1072 |
if(obj != this._obj){
|
|
|
1073 |
this.stop();
|
|
|
1074 |
this._initialDelay = initialDelay || 500;
|
|
|
1075 |
this._subsequentDelay = subsequentDelay || 0.90;
|
|
|
1076 |
this._obj = obj;
|
|
|
1077 |
this._evt = evt;
|
|
|
1078 |
this._node = node;
|
|
|
1079 |
this._currentTimeout = -1;
|
|
|
1080 |
this._count = -1;
|
|
|
1081 |
this._callback = dojo.hitch(_this, callback);
|
|
|
1082 |
this._fireEventAndReload();
|
|
|
1083 |
}
|
|
|
1084 |
},
|
|
|
1085 |
|
|
|
1086 |
stop: function(){
|
|
|
1087 |
// summary:
|
|
|
1088 |
// Stop an ongoing timed, repeating callback sequence.
|
|
|
1089 |
if(this._timer){
|
|
|
1090 |
clearTimeout(this._timer);
|
|
|
1091 |
this._timer = null;
|
|
|
1092 |
}
|
|
|
1093 |
if(this._obj){
|
|
|
1094 |
this._callback(-1, this._node, this._evt);
|
|
|
1095 |
this._obj = null;
|
|
|
1096 |
}
|
|
|
1097 |
},
|
|
|
1098 |
|
|
|
1099 |
addKeyListener: function(/*DOMNode*/ node, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay){
|
|
|
1100 |
// summary: Start listening for a specific typematic key.
|
|
|
1101 |
// keyObject: an object defining the key to listen for.
|
|
|
1102 |
// key: (mandatory) the keyCode (number) or character (string) to listen for.
|
|
|
1103 |
// ctrlKey: desired ctrl key state to initiate the calback sequence:
|
|
|
1104 |
// pressed (true)
|
|
|
1105 |
// released (false)
|
|
|
1106 |
// either (unspecified)
|
|
|
1107 |
// altKey: same as ctrlKey but for the alt key
|
|
|
1108 |
// shiftKey: same as ctrlKey but for the shift key
|
|
|
1109 |
// See the trigger method for other parameters.
|
|
|
1110 |
// Returns an array of dojo.connect handles
|
|
|
1111 |
return [
|
|
|
1112 |
dojo.connect(node, "onkeypress", this, function(evt){
|
|
|
1113 |
if(evt.keyCode == keyObject.keyCode && (!keyObject.charCode || keyObject.charCode == evt.charCode) &&
|
|
|
1114 |
(keyObject.ctrlKey === undefined || keyObject.ctrlKey == evt.ctrlKey) &&
|
|
|
1115 |
(keyObject.altKey === undefined || keyObject.altKey == evt.ctrlKey) &&
|
|
|
1116 |
(keyObject.shiftKey === undefined || keyObject.shiftKey == evt.ctrlKey)){
|
|
|
1117 |
dojo.stopEvent(evt);
|
|
|
1118 |
dijit.typematic.trigger(keyObject, _this, node, callback, keyObject, subsequentDelay, initialDelay);
|
|
|
1119 |
}else if(dijit.typematic._obj == keyObject){
|
|
|
1120 |
dijit.typematic.stop();
|
|
|
1121 |
}
|
|
|
1122 |
}),
|
|
|
1123 |
dojo.connect(node, "onkeyup", this, function(evt){
|
|
|
1124 |
if(dijit.typematic._obj == keyObject){
|
|
|
1125 |
dijit.typematic.stop();
|
|
|
1126 |
}
|
|
|
1127 |
})
|
|
|
1128 |
];
|
|
|
1129 |
},
|
|
|
1130 |
|
|
|
1131 |
addMouseListener: function(/*DOMNode*/ node, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay){
|
|
|
1132 |
// summary: Start listening for a typematic mouse click.
|
|
|
1133 |
// See the trigger method for other parameters.
|
|
|
1134 |
// Returns an array of dojo.connect handles
|
|
|
1135 |
var dc = dojo.connect;
|
|
|
1136 |
return [
|
|
|
1137 |
dc(node, "mousedown", this, function(evt){
|
|
|
1138 |
dojo.stopEvent(evt);
|
|
|
1139 |
dijit.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay);
|
|
|
1140 |
}),
|
|
|
1141 |
dc(node, "mouseup", this, function(evt){
|
|
|
1142 |
dojo.stopEvent(evt);
|
|
|
1143 |
dijit.typematic.stop();
|
|
|
1144 |
}),
|
|
|
1145 |
dc(node, "mouseout", this, function(evt){
|
|
|
1146 |
dojo.stopEvent(evt);
|
|
|
1147 |
dijit.typematic.stop();
|
|
|
1148 |
}),
|
|
|
1149 |
dc(node, "mousemove", this, function(evt){
|
|
|
1150 |
dojo.stopEvent(evt);
|
|
|
1151 |
}),
|
|
|
1152 |
dc(node, "dblclick", this, function(evt){
|
|
|
1153 |
dojo.stopEvent(evt);
|
|
|
1154 |
if(dojo.isIE){
|
|
|
1155 |
dijit.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay);
|
|
|
1156 |
setTimeout(dijit.typematic.stop, 50);
|
|
|
1157 |
}
|
|
|
1158 |
})
|
|
|
1159 |
];
|
|
|
1160 |
},
|
|
|
1161 |
|
|
|
1162 |
addListener: function(/*Node*/ mouseNode, /*Node*/ keyNode, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay){
|
|
|
1163 |
// summary: Start listening for a specific typematic key and mouseclick.
|
|
|
1164 |
// This is a thin wrapper to addKeyListener and addMouseListener.
|
|
|
1165 |
// mouseNode: the DOM node object to listen on for mouse events.
|
|
|
1166 |
// keyNode: the DOM node object to listen on for key events.
|
|
|
1167 |
// See the addMouseListener and addKeyListener methods for other parameters.
|
|
|
1168 |
// Returns an array of dojo.connect handles
|
|
|
1169 |
return this.addKeyListener(keyNode, keyObject, _this, callback, subsequentDelay, initialDelay).concat(
|
|
|
1170 |
this.addMouseListener(mouseNode, _this, callback, subsequentDelay, initialDelay));
|
|
|
1171 |
}
|
|
|
1172 |
};
|
|
|
1173 |
|
|
|
1174 |
}
|
|
|
1175 |
|
|
|
1176 |
if(!dojo._hasResource["dijit._base.wai"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
1177 |
dojo._hasResource["dijit._base.wai"] = true;
|
|
|
1178 |
dojo.provide("dijit._base.wai");
|
|
|
1179 |
|
|
|
1180 |
dijit.wai = {
|
|
|
1181 |
onload: function(){
|
|
|
1182 |
// summary:
|
|
|
1183 |
// Function that detects if we are in high-contrast mode or not,
|
|
|
1184 |
// and sets up a timer to periodically confirm the value.
|
|
|
1185 |
// figure out the background-image style property
|
|
|
1186 |
// and apply that to the image.src property.
|
|
|
1187 |
// description:
|
|
|
1188 |
// This must be a named function and not an anonymous
|
|
|
1189 |
// function, so that the widget parsing code can make sure it
|
|
|
1190 |
// registers its onload function after this function.
|
|
|
1191 |
// DO NOT USE "this" within this function.
|
|
|
1192 |
|
|
|
1193 |
// create div for testing if high contrast mode is on or images are turned off
|
|
|
1194 |
var div = document.createElement("div");
|
|
|
1195 |
div.id = "a11yTestNode";
|
|
|
1196 |
div.style.cssText = 'border: 1px solid;'
|
|
|
1197 |
+ 'border-color:red green;'
|
|
|
1198 |
+ 'position: absolute;'
|
|
|
1199 |
+ 'height: 5px;'
|
|
|
1200 |
+ 'top: -999px;'
|
|
|
1201 |
+ 'background-image: url("' + dojo.moduleUrl("dijit", "form/templates/blank.gif") + '");';
|
|
|
1202 |
dojo.body().appendChild(div);
|
|
|
1203 |
|
|
|
1204 |
// test it
|
|
|
1205 |
function check(){
|
|
|
1206 |
var cs = dojo.getComputedStyle(div);
|
|
|
1207 |
if(cs){
|
|
|
1208 |
var bkImg = cs.backgroundImage;
|
|
|
1209 |
var needsA11y = (cs.borderTopColor==cs.borderRightColor) || (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)" ));
|
|
|
1210 |
dojo[needsA11y ? "addClass" : "removeClass"](dojo.body(), "dijit_a11y");
|
|
|
1211 |
}
|
|
|
1212 |
}
|
|
|
1213 |
check();
|
|
|
1214 |
if(dojo.isIE){
|
|
|
1215 |
setInterval(check, 4000);
|
|
|
1216 |
}
|
|
|
1217 |
}
|
|
|
1218 |
};
|
|
|
1219 |
|
|
|
1220 |
// Test if computer is in high contrast mode.
|
|
|
1221 |
// Make sure the a11y test runs first, before widgets are instantiated.
|
|
|
1222 |
if(dojo.isIE || dojo.isMoz){ // NOTE: checking in Safari messes things up
|
|
|
1223 |
dojo._loaders.unshift(dijit.wai.onload);
|
|
|
1224 |
}
|
|
|
1225 |
|
|
|
1226 |
dojo.mixin(dijit,
|
|
|
1227 |
{
|
|
|
1228 |
hasWaiRole: function(/*Element*/ elem){
|
|
|
1229 |
// Summary: Return true if elem has a role attribute and false if not.
|
|
|
1230 |
if(elem.hasAttribute){
|
|
|
1231 |
return elem.hasAttribute("role");
|
|
|
1232 |
}else{
|
|
|
1233 |
return elem.getAttribute("role") ? true : false;
|
|
|
1234 |
}
|
|
|
1235 |
},
|
|
|
1236 |
|
|
|
1237 |
getWaiRole: function(/*Element*/ elem){
|
|
|
1238 |
// Summary: Return the role of elem or an empty string if
|
|
|
1239 |
// elem does not have a role.
|
|
|
1240 |
var value = elem.getAttribute("role");
|
|
|
1241 |
if(value){
|
|
|
1242 |
var prefixEnd = value.indexOf(":");
|
|
|
1243 |
return prefixEnd == -1 ? value : value.substring(prefixEnd+1);
|
|
|
1244 |
}else{
|
|
|
1245 |
return "";
|
|
|
1246 |
}
|
|
|
1247 |
},
|
|
|
1248 |
|
|
|
1249 |
setWaiRole: function(/*Element*/ elem, /*String*/ role){
|
|
|
1250 |
// Summary: Set the role on elem. On Firefox 2 and below, "wairole:" is
|
|
|
1251 |
// prepended to the provided role value.
|
|
|
1252 |
if(dojo.isFF && dojo.isFF < 3){
|
|
|
1253 |
elem.setAttribute("role", "wairole:"+role);
|
|
|
1254 |
}else{
|
|
|
1255 |
elem.setAttribute("role", role);
|
|
|
1256 |
}
|
|
|
1257 |
},
|
|
|
1258 |
|
|
|
1259 |
removeWaiRole: function(/*Element*/ elem){
|
|
|
1260 |
// Summary: Removes the role attribute from elem.
|
|
|
1261 |
elem.removeAttribute("role");
|
|
|
1262 |
},
|
|
|
1263 |
|
|
|
1264 |
hasWaiState: function(/*Element*/ elem, /*String*/ state){
|
|
|
1265 |
// Summary: Return true if elem has a value for the given state and
|
|
|
1266 |
// false if it does not.
|
|
|
1267 |
// On Firefox 2 and below, we check for an attribute in namespace
|
|
|
1268 |
// "http://www.w3.org/2005/07/aaa" with a name of the given state.
|
|
|
1269 |
// On all other browsers, we check for an attribute called
|
|
|
1270 |
// "aria-"+state.
|
|
|
1271 |
if(dojo.isFF && dojo.isFF < 3){
|
|
|
1272 |
return elem.hasAttributeNS("http://www.w3.org/2005/07/aaa", state);
|
|
|
1273 |
}else{
|
|
|
1274 |
if(elem.hasAttribute){
|
|
|
1275 |
return elem.hasAttribute("aria-"+state);
|
|
|
1276 |
}else{
|
|
|
1277 |
return elem.getAttribute("aria-"+state) ? true : false;
|
|
|
1278 |
}
|
|
|
1279 |
}
|
|
|
1280 |
},
|
|
|
1281 |
|
|
|
1282 |
getWaiState: function(/*Element*/ elem, /*String*/ state){
|
|
|
1283 |
// Summary: Return the value of the requested state on elem
|
|
|
1284 |
// or an empty string if elem has no value for state.
|
|
|
1285 |
// On Firefox 2 and below, we check for an attribute in namespace
|
|
|
1286 |
// "http://www.w3.org/2005/07/aaa" with a name of the given state.
|
|
|
1287 |
// On all other browsers, we check for an attribute called
|
|
|
1288 |
// "aria-"+state.
|
|
|
1289 |
if(dojo.isFF && dojo.isFF < 3){
|
|
|
1290 |
return elem.getAttributeNS("http://www.w3.org/2005/07/aaa", state);
|
|
|
1291 |
}else{
|
|
|
1292 |
var value = elem.getAttribute("aria-"+state);
|
|
|
1293 |
return value ? value : "";
|
|
|
1294 |
}
|
|
|
1295 |
},
|
|
|
1296 |
|
|
|
1297 |
setWaiState: function(/*Element*/ elem, /*String*/ state, /*String*/ value){
|
|
|
1298 |
// Summary: Set state on elem to value.
|
|
|
1299 |
// On Firefox 2 and below, we set an attribute in namespace
|
|
|
1300 |
// "http://www.w3.org/2005/07/aaa" with a name of the given state.
|
|
|
1301 |
// On all other browsers, we set an attribute called
|
|
|
1302 |
// "aria-"+state.
|
|
|
1303 |
if(dojo.isFF && dojo.isFF < 3){
|
|
|
1304 |
elem.setAttributeNS("http://www.w3.org/2005/07/aaa",
|
|
|
1305 |
"aaa:"+state, value);
|
|
|
1306 |
}else{
|
|
|
1307 |
elem.setAttribute("aria-"+state, value);
|
|
|
1308 |
}
|
|
|
1309 |
},
|
|
|
1310 |
|
|
|
1311 |
removeWaiState: function(/*Element*/ elem, /*String*/ state){
|
|
|
1312 |
// Summary: Removes the given state from elem.
|
|
|
1313 |
// On Firefox 2 and below, we remove the attribute in namespace
|
|
|
1314 |
// "http://www.w3.org/2005/07/aaa" with a name of the given state.
|
|
|
1315 |
// On all other browsers, we remove the attribute called
|
|
|
1316 |
// "aria-"+state.
|
|
|
1317 |
if(dojo.isFF && dojo.isFF < 3){
|
|
|
1318 |
elem.removeAttributeNS("http://www.w3.org/2005/07/aaa", state);
|
|
|
1319 |
}else{
|
|
|
1320 |
elem.removeAttribute("aria-"+state);
|
|
|
1321 |
}
|
|
|
1322 |
}
|
|
|
1323 |
});
|
|
|
1324 |
|
|
|
1325 |
}
|
|
|
1326 |
|
|
|
1327 |
if(!dojo._hasResource["dijit._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
1328 |
dojo._hasResource["dijit._base"] = true;
|
|
|
1329 |
dojo.provide("dijit._base");
|
|
|
1330 |
|
|
|
1331 |
|
|
|
1332 |
|
|
|
1333 |
|
|
|
1334 |
|
|
|
1335 |
|
|
|
1336 |
|
|
|
1337 |
|
|
|
1338 |
|
|
|
1339 |
|
|
|
1340 |
|
|
|
1341 |
|
|
|
1342 |
}
|
|
|
1343 |
|
|
|
1344 |
if(!dojo._hasResource["dojo.date.stamp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
1345 |
dojo._hasResource["dojo.date.stamp"] = true;
|
|
|
1346 |
dojo.provide("dojo.date.stamp");
|
|
|
1347 |
|
|
|
1348 |
// Methods to convert dates to or from a wire (string) format using well-known conventions
|
|
|
1349 |
|
|
|
1350 |
dojo.date.stamp.fromISOString = function(/*String*/formattedString, /*Number?*/defaultTime){
|
|
|
1351 |
// summary:
|
|
|
1352 |
// Returns a Date object given a string formatted according to a subset of the ISO-8601 standard.
|
|
|
1353 |
//
|
|
|
1354 |
// description:
|
|
|
1355 |
// Accepts a string formatted according to a profile of ISO8601 as defined by
|
|
|
1356 |
// RFC3339 (http://www.ietf.org/rfc/rfc3339.txt), except that partial input is allowed.
|
|
|
1357 |
// Can also process dates as specified by http://www.w3.org/TR/NOTE-datetime
|
|
|
1358 |
// The following combinations are valid:
|
|
|
1359 |
// * dates only
|
|
|
1360 |
// yyyy
|
|
|
1361 |
// yyyy-MM
|
|
|
1362 |
// yyyy-MM-dd
|
|
|
1363 |
// * times only, with an optional time zone appended
|
|
|
1364 |
// THH:mm
|
|
|
1365 |
// THH:mm:ss
|
|
|
1366 |
// THH:mm:ss.SSS
|
|
|
1367 |
// * and "datetimes" which could be any combination of the above
|
|
|
1368 |
// timezones may be specified as Z (for UTC) or +/- followed by a time expression HH:mm
|
|
|
1369 |
// Assumes the local time zone if not specified. Does not validate. Improperly formatted
|
|
|
1370 |
// input may return null. Arguments which are out of bounds will be handled
|
|
|
1371 |
// by the Date constructor (e.g. January 32nd typically gets resolved to February 1st)
|
|
|
1372 |
//
|
|
|
1373 |
// formattedString:
|
|
|
1374 |
// A string such as 2005-06-30T08:05:00-07:00 or 2005-06-30 or T08:05:00
|
|
|
1375 |
//
|
|
|
1376 |
// defaultTime:
|
|
|
1377 |
// Used for defaults for fields omitted in the formattedString.
|
|
|
1378 |
// Uses 1970-01-01T00:00:00.0Z by default.
|
|
|
1379 |
|
|
|
1380 |
if(!dojo.date.stamp._isoRegExp){
|
|
|
1381 |
dojo.date.stamp._isoRegExp =
|
|
|
1382 |
//TODO: could be more restrictive and check for 00-59, etc.
|
|
|
1383 |
/^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(.\d+)?)?((?:[+-](\d{2}):(\d{2}))|Z)?)?$/;
|
|
|
1384 |
}
|
|
|
1385 |
|
|
|
1386 |
var match = dojo.date.stamp._isoRegExp.exec(formattedString);
|
|
|
1387 |
var result = null;
|
|
|
1388 |
|
|
|
1389 |
if(match){
|
|
|
1390 |
match.shift();
|
|
|
1391 |
match[1] && match[1]--; // Javascript Date months are 0-based
|
|
|
1392 |
match[6] && (match[6] *= 1000); // Javascript Date expects fractional seconds as milliseconds
|
|
|
1393 |
|
|
|
1394 |
if(defaultTime){
|
|
|
1395 |
// mix in defaultTime. Relatively expensive, so use || operators for the fast path of defaultTime === 0
|
|
|
1396 |
defaultTime = new Date(defaultTime);
|
|
|
1397 |
dojo.map(["FullYear", "Month", "Date", "Hours", "Minutes", "Seconds", "Milliseconds"], function(prop){
|
|
|
1398 |
return defaultTime["get" + prop]();
|
|
|
1399 |
}).forEach(function(value, index){
|
|
|
1400 |
if(match[index] === undefined){
|
|
|
1401 |
match[index] = value;
|
|
|
1402 |
}
|
|
|
1403 |
});
|
|
|
1404 |
}
|
|
|
1405 |
result = new Date(match[0]||1970, match[1]||0, match[2]||0, match[3]||0, match[4]||0, match[5]||0, match[6]||0);
|
|
|
1406 |
|
|
|
1407 |
var offset = 0;
|
|
|
1408 |
var zoneSign = match[7] && match[7].charAt(0);
|
|
|
1409 |
if(zoneSign != 'Z'){
|
|
|
1410 |
offset = ((match[8] || 0) * 60) + (Number(match[9]) || 0);
|
|
|
1411 |
if(zoneSign != '-'){ offset *= -1; }
|
|
|
1412 |
}
|
|
|
1413 |
if(zoneSign){
|
|
|
1414 |
offset -= result.getTimezoneOffset();
|
|
|
1415 |
}
|
|
|
1416 |
if(offset){
|
|
|
1417 |
result.setTime(result.getTime() + offset * 60000);
|
|
|
1418 |
}
|
|
|
1419 |
}
|
|
|
1420 |
|
|
|
1421 |
return result; // Date or null
|
|
|
1422 |
}
|
|
|
1423 |
|
|
|
1424 |
dojo.date.stamp.toISOString = function(/*Date*/dateObject, /*Object?*/options){
|
|
|
1425 |
// summary:
|
|
|
1426 |
// Format a Date object as a string according a subset of the ISO-8601 standard
|
|
|
1427 |
//
|
|
|
1428 |
// description:
|
|
|
1429 |
// When options.selector is omitted, output follows RFC3339 (http://www.ietf.org/rfc/rfc3339.txt)
|
|
|
1430 |
// The local time zone is included as an offset from GMT, except when selector=='time' (time without a date)
|
|
|
1431 |
// Does not check bounds.
|
|
|
1432 |
//
|
|
|
1433 |
// dateObject:
|
|
|
1434 |
// A Date object
|
|
|
1435 |
//
|
|
|
1436 |
// object {selector: string, zulu: boolean, milliseconds: boolean}
|
|
|
1437 |
// selector- "date" or "time" for partial formatting of the Date object.
|
|
|
1438 |
// Both date and time will be formatted by default.
|
|
|
1439 |
// zulu- if true, UTC/GMT is used for a timezone
|
|
|
1440 |
// milliseconds- if true, output milliseconds
|
|
|
1441 |
|
|
|
1442 |
var _ = function(n){ return (n < 10) ? "0" + n : n; }
|
|
|
1443 |
options = options || {};
|
|
|
1444 |
var formattedDate = [];
|
|
|
1445 |
var getter = options.zulu ? "getUTC" : "get";
|
|
|
1446 |
var date = "";
|
|
|
1447 |
if(options.selector != "time"){
|
|
|
1448 |
date = [dateObject[getter+"FullYear"](), _(dateObject[getter+"Month"]()+1), _(dateObject[getter+"Date"]())].join('-');
|
|
|
1449 |
}
|
|
|
1450 |
formattedDate.push(date);
|
|
|
1451 |
if(options.selector != "date"){
|
|
|
1452 |
var time = [_(dateObject[getter+"Hours"]()), _(dateObject[getter+"Minutes"]()), _(dateObject[getter+"Seconds"]())].join(':');
|
|
|
1453 |
var millis = dateObject[getter+"Milliseconds"]();
|
|
|
1454 |
if(options.milliseconds){
|
|
|
1455 |
time += "."+ (millis < 100 ? "0" : "") + _(millis);
|
|
|
1456 |
}
|
|
|
1457 |
if(options.zulu){
|
|
|
1458 |
time += "Z";
|
|
|
1459 |
}else if(options.selector != "time"){
|
|
|
1460 |
var timezoneOffset = dateObject.getTimezoneOffset();
|
|
|
1461 |
var absOffset = Math.abs(timezoneOffset);
|
|
|
1462 |
time += (timezoneOffset > 0 ? "-" : "+") +
|
|
|
1463 |
_(Math.floor(absOffset/60)) + ":" + _(absOffset%60);
|
|
|
1464 |
}
|
|
|
1465 |
formattedDate.push(time);
|
|
|
1466 |
}
|
|
|
1467 |
return formattedDate.join('T'); // String
|
|
|
1468 |
}
|
|
|
1469 |
|
|
|
1470 |
}
|
|
|
1471 |
|
|
|
1472 |
if(!dojo._hasResource["dojo.parser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
1473 |
dojo._hasResource["dojo.parser"] = true;
|
|
|
1474 |
dojo.provide("dojo.parser");
|
|
|
1475 |
|
|
|
1476 |
|
|
|
1477 |
dojo.parser = new function(){
|
|
|
1478 |
|
|
|
1479 |
var d = dojo;
|
|
|
1480 |
|
|
|
1481 |
function val2type(/*Object*/ value){
|
|
|
1482 |
// summary:
|
|
|
1483 |
// Returns name of type of given value.
|
|
|
1484 |
|
|
|
1485 |
if(d.isString(value)){ return "string"; }
|
|
|
1486 |
if(typeof value == "number"){ return "number"; }
|
|
|
1487 |
if(typeof value == "boolean"){ return "boolean"; }
|
|
|
1488 |
if(d.isFunction(value)){ return "function"; }
|
|
|
1489 |
if(d.isArray(value)){ return "array"; } // typeof [] == "object"
|
|
|
1490 |
if(value instanceof Date) { return "date"; } // assume timestamp
|
|
|
1491 |
if(value instanceof d._Url){ return "url"; }
|
|
|
1492 |
return "object";
|
|
|
1493 |
}
|
|
|
1494 |
|
|
|
1495 |
function str2obj(/*String*/ value, /*String*/ type){
|
|
|
1496 |
// summary:
|
|
|
1497 |
// Convert given string value to given type
|
|
|
1498 |
switch(type){
|
|
|
1499 |
case "string":
|
|
|
1500 |
return value;
|
|
|
1501 |
case "number":
|
|
|
1502 |
return value.length ? Number(value) : NaN;
|
|
|
1503 |
case "boolean":
|
|
|
1504 |
// for checked/disabled value might be "" or "checked". interpret as true.
|
|
|
1505 |
return typeof value == "boolean" ? value : !(value.toLowerCase()=="false");
|
|
|
1506 |
case "function":
|
|
|
1507 |
if(d.isFunction(value)){
|
|
|
1508 |
// IE gives us a function, even when we say something like onClick="foo"
|
|
|
1509 |
// (in which case it gives us an invalid function "function(){ foo }").
|
|
|
1510 |
// Therefore, convert to string
|
|
|
1511 |
value=value.toString();
|
|
|
1512 |
value=d.trim(value.substring(value.indexOf('{')+1, value.length-1));
|
|
|
1513 |
}
|
|
|
1514 |
try{
|
|
|
1515 |
if(value.search(/[^\w\.]+/i) != -1){
|
|
|
1516 |
// TODO: "this" here won't work
|
|
|
1517 |
value = d.parser._nameAnonFunc(new Function(value), this);
|
|
|
1518 |
}
|
|
|
1519 |
return d.getObject(value, false);
|
|
|
1520 |
}catch(e){ return new Function(); }
|
|
|
1521 |
case "array":
|
|
|
1522 |
return value.split(/\s*,\s*/);
|
|
|
1523 |
case "date":
|
|
|
1524 |
switch(value){
|
|
|
1525 |
case "": return new Date(""); // the NaN of dates
|
|
|
1526 |
case "now": return new Date(); // current date
|
|
|
1527 |
default: return d.date.stamp.fromISOString(value);
|
|
|
1528 |
}
|
|
|
1529 |
case "url":
|
|
|
1530 |
return d.baseUrl + value;
|
|
|
1531 |
default:
|
|
|
1532 |
return d.fromJson(value);
|
|
|
1533 |
}
|
|
|
1534 |
}
|
|
|
1535 |
|
|
|
1536 |
var instanceClasses = {
|
|
|
1537 |
// map from fully qualified name (like "dijit.Button") to structure like
|
|
|
1538 |
// { cls: dijit.Button, params: {label: "string", disabled: "boolean"} }
|
|
|
1539 |
};
|
|
|
1540 |
|
|
|
1541 |
function getClassInfo(/*String*/ className){
|
|
|
1542 |
// className:
|
|
|
1543 |
// fully qualified name (like "dijit.Button")
|
|
|
1544 |
// returns:
|
|
|
1545 |
// structure like
|
|
|
1546 |
// {
|
|
|
1547 |
// cls: dijit.Button,
|
|
|
1548 |
// params: { label: "string", disabled: "boolean"}
|
|
|
1549 |
// }
|
|
|
1550 |
|
|
|
1551 |
if(!instanceClasses[className]){
|
|
|
1552 |
// get pointer to widget class
|
|
|
1553 |
var cls = d.getObject(className);
|
|
|
1554 |
if(!d.isFunction(cls)){
|
|
|
1555 |
throw new Error("Could not load class '" + className +
|
|
|
1556 |
"'. Did you spell the name correctly and use a full path, like 'dijit.form.Button'?");
|
|
|
1557 |
}
|
|
|
1558 |
var proto = cls.prototype;
|
|
|
1559 |
|
|
|
1560 |
// get table of parameter names & types
|
|
|
1561 |
var params={};
|
|
|
1562 |
for(var name in proto){
|
|
|
1563 |
if(name.charAt(0)=="_"){ continue; } // skip internal properties
|
|
|
1564 |
var defVal = proto[name];
|
|
|
1565 |
params[name]=val2type(defVal);
|
|
|
1566 |
}
|
|
|
1567 |
|
|
|
1568 |
instanceClasses[className] = { cls: cls, params: params };
|
|
|
1569 |
}
|
|
|
1570 |
return instanceClasses[className];
|
|
|
1571 |
}
|
|
|
1572 |
|
|
|
1573 |
this._functionFromScript = function(script){
|
|
|
1574 |
var preamble = "";
|
|
|
1575 |
var suffix = "";
|
|
|
1576 |
var argsStr = script.getAttribute("args");
|
|
|
1577 |
if(argsStr){
|
|
|
1578 |
d.forEach(argsStr.split(/\s*,\s*/), function(part, idx){
|
|
|
1579 |
preamble += "var "+part+" = arguments["+idx+"]; ";
|
|
|
1580 |
});
|
|
|
1581 |
}
|
|
|
1582 |
var withStr = script.getAttribute("with");
|
|
|
1583 |
if(withStr && withStr.length){
|
|
|
1584 |
d.forEach(withStr.split(/\s*,\s*/), function(part){
|
|
|
1585 |
preamble += "with("+part+"){";
|
|
|
1586 |
suffix += "}";
|
|
|
1587 |
});
|
|
|
1588 |
}
|
|
|
1589 |
return new Function(preamble+script.innerHTML+suffix);
|
|
|
1590 |
}
|
|
|
1591 |
|
|
|
1592 |
this.instantiate = function(/* Array */nodes){
|
|
|
1593 |
// summary:
|
|
|
1594 |
// Takes array of nodes, and turns them into class instances and
|
|
|
1595 |
// potentially calls a layout method to allow them to connect with
|
|
|
1596 |
// any children
|
|
|
1597 |
var thelist = [];
|
|
|
1598 |
d.forEach(nodes, function(node){
|
|
|
1599 |
if(!node){ return; }
|
|
|
1600 |
var type = node.getAttribute("dojoType");
|
|
|
1601 |
if((!type)||(!type.length)){ return; }
|
|
|
1602 |
var clsInfo = getClassInfo(type);
|
|
|
1603 |
var clazz = clsInfo.cls;
|
|
|
1604 |
var ps = clazz._noScript||clazz.prototype._noScript;
|
|
|
1605 |
|
|
|
1606 |
// read parameters (ie, attributes).
|
|
|
1607 |
// clsInfo.params lists expected params like {"checked": "boolean", "n": "number"}
|
|
|
1608 |
var params = {};
|
|
|
1609 |
var attributes = node.attributes;
|
|
|
1610 |
for(var name in clsInfo.params){
|
|
|
1611 |
var item = attributes.getNamedItem(name);
|
|
|
1612 |
if(!item || (!item.specified && (!dojo.isIE || name.toLowerCase()!="value"))){ continue; }
|
|
|
1613 |
var value = item.value;
|
|
|
1614 |
// Deal with IE quirks for 'class' and 'style'
|
|
|
1615 |
switch(name){
|
|
|
1616 |
case "class":
|
|
|
1617 |
value = node.className;
|
|
|
1618 |
break;
|
|
|
1619 |
case "style":
|
|
|
1620 |
value = node.style && node.style.cssText; // FIXME: Opera?
|
|
|
1621 |
}
|
|
|
1622 |
var _type = clsInfo.params[name];
|
|
|
1623 |
params[name] = str2obj(value, _type);
|
|
|
1624 |
}
|
|
|
1625 |
|
|
|
1626 |
// Process <script type="dojo/*"> script tags
|
|
|
1627 |
// <script type="dojo/method" event="foo"> tags are added to params, and passed to
|
|
|
1628 |
// the widget on instantiation.
|
|
|
1629 |
// <script type="dojo/method"> tags (with no event) are executed after instantiation
|
|
|
1630 |
// <script type="dojo/connect" event="foo"> tags are dojo.connected after instantiation
|
|
|
1631 |
if(!ps){
|
|
|
1632 |
var connects = [], // functions to connect after instantiation
|
|
|
1633 |
calls = []; // functions to call after instantiation
|
|
|
1634 |
|
|
|
1635 |
d.query("> script[type^='dojo/']", node).orphan().forEach(function(script){
|
|
|
1636 |
var event = script.getAttribute("event"),
|
|
|
1637 |
type = script.getAttribute("type"),
|
|
|
1638 |
nf = d.parser._functionFromScript(script);
|
|
|
1639 |
if(event){
|
|
|
1640 |
if(type == "dojo/connect"){
|
|
|
1641 |
connects.push({event: event, func: nf});
|
|
|
1642 |
}else{
|
|
|
1643 |
params[event] = nf;
|
|
|
1644 |
}
|
|
|
1645 |
}else{
|
|
|
1646 |
calls.push(nf);
|
|
|
1647 |
}
|
|
|
1648 |
});
|
|
|
1649 |
}
|
|
|
1650 |
|
|
|
1651 |
var markupFactory = clazz["markupFactory"];
|
|
|
1652 |
if(!markupFactory && clazz["prototype"]){
|
|
|
1653 |
markupFactory = clazz.prototype["markupFactory"];
|
|
|
1654 |
}
|
|
|
1655 |
// create the instance
|
|
|
1656 |
var instance = markupFactory ? markupFactory(params, node, clazz) : new clazz(params, node);
|
|
|
1657 |
thelist.push(instance);
|
|
|
1658 |
|
|
|
1659 |
// map it to the JS namespace if that makes sense
|
|
|
1660 |
var jsname = node.getAttribute("jsId");
|
|
|
1661 |
if(jsname){
|
|
|
1662 |
d.setObject(jsname, instance);
|
|
|
1663 |
}
|
|
|
1664 |
|
|
|
1665 |
// process connections and startup functions
|
|
|
1666 |
if(!ps){
|
|
|
1667 |
dojo.forEach(connects, function(connect){
|
|
|
1668 |
dojo.connect(instance, connect.event, null, connect.func);
|
|
|
1669 |
});
|
|
|
1670 |
dojo.forEach(calls, function(func){
|
|
|
1671 |
func.call(instance);
|
|
|
1672 |
});
|
|
|
1673 |
}
|
|
|
1674 |
});
|
|
|
1675 |
|
|
|
1676 |
// Call startup on each top level instance if it makes sense (as for
|
|
|
1677 |
// widgets). Parent widgets will recursively call startup on their
|
|
|
1678 |
// (non-top level) children
|
|
|
1679 |
d.forEach(thelist, function(instance){
|
|
|
1680 |
if( instance &&
|
|
|
1681 |
(instance.startup) &&
|
|
|
1682 |
((!instance.getParent) || (!instance.getParent()))
|
|
|
1683 |
){
|
|
|
1684 |
instance.startup();
|
|
|
1685 |
}
|
|
|
1686 |
});
|
|
|
1687 |
return thelist;
|
|
|
1688 |
};
|
|
|
1689 |
|
|
|
1690 |
this.parse = function(/*DomNode?*/ rootNode){
|
|
|
1691 |
// summary:
|
|
|
1692 |
// Search specified node (or root node) recursively for class instances,
|
|
|
1693 |
// and instantiate them Searches for
|
|
|
1694 |
// dojoType="qualified.class.name"
|
|
|
1695 |
var list = d.query('[dojoType]', rootNode);
|
|
|
1696 |
// go build the object instances
|
|
|
1697 |
var instances = this.instantiate(list);
|
|
|
1698 |
return instances;
|
|
|
1699 |
};
|
|
|
1700 |
}();
|
|
|
1701 |
|
|
|
1702 |
//Register the parser callback. It should be the first callback
|
|
|
1703 |
//after the a11y test.
|
|
|
1704 |
|
|
|
1705 |
(function(){
|
|
|
1706 |
var parseRunner = function(){
|
|
|
1707 |
if(djConfig["parseOnLoad"] == true){
|
|
|
1708 |
dojo.parser.parse();
|
|
|
1709 |
}
|
|
|
1710 |
};
|
|
|
1711 |
|
|
|
1712 |
// FIXME: need to clobber cross-dependency!!
|
|
|
1713 |
if(dojo.exists("dijit.wai.onload") && (dijit.wai.onload === dojo._loaders[0])){
|
|
|
1714 |
dojo._loaders.splice(1, 0, parseRunner);
|
|
|
1715 |
}else{
|
|
|
1716 |
dojo._loaders.unshift(parseRunner);
|
|
|
1717 |
}
|
|
|
1718 |
})();
|
|
|
1719 |
|
|
|
1720 |
//TODO: ported from 0.4.x Dojo. Can we reduce this?
|
|
|
1721 |
dojo.parser._anonCtr = 0;
|
|
|
1722 |
dojo.parser._anon = {}; // why is this property required?
|
|
|
1723 |
dojo.parser._nameAnonFunc = function(/*Function*/anonFuncPtr, /*Object*/thisObj){
|
|
|
1724 |
// summary:
|
|
|
1725 |
// Creates a reference to anonFuncPtr in thisObj with a completely
|
|
|
1726 |
// unique name. The new name is returned as a String.
|
|
|
1727 |
var jpn = "$joinpoint";
|
|
|
1728 |
var nso = (thisObj|| dojo.parser._anon);
|
|
|
1729 |
if(dojo.isIE){
|
|
|
1730 |
var cn = anonFuncPtr["__dojoNameCache"];
|
|
|
1731 |
if(cn && nso[cn] === anonFuncPtr){
|
|
|
1732 |
return anonFuncPtr["__dojoNameCache"];
|
|
|
1733 |
}
|
|
|
1734 |
}
|
|
|
1735 |
var ret = "__"+dojo.parser._anonCtr++;
|
|
|
1736 |
while(typeof nso[ret] != "undefined"){
|
|
|
1737 |
ret = "__"+dojo.parser._anonCtr++;
|
|
|
1738 |
}
|
|
|
1739 |
nso[ret] = anonFuncPtr;
|
|
|
1740 |
return ret; // String
|
|
|
1741 |
}
|
|
|
1742 |
|
|
|
1743 |
}
|
|
|
1744 |
|
|
|
1745 |
if(!dojo._hasResource["dijit._Widget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
1746 |
dojo._hasResource["dijit._Widget"] = true;
|
|
|
1747 |
dojo.provide("dijit._Widget");
|
|
|
1748 |
|
|
|
1749 |
|
|
|
1750 |
|
|
|
1751 |
dojo.declare("dijit._Widget", null, {
|
|
|
1752 |
// summary:
|
|
|
1753 |
// The foundation of dijit widgets.
|
|
|
1754 |
//
|
|
|
1755 |
// id: String
|
|
|
1756 |
// a unique, opaque ID string that can be assigned by users or by the
|
|
|
1757 |
// system. If the developer passes an ID which is known not to be
|
|
|
1758 |
// unique, the specified ID is ignored and the system-generated ID is
|
|
|
1759 |
// used instead.
|
|
|
1760 |
id: "",
|
|
|
1761 |
|
|
|
1762 |
// lang: String
|
|
|
1763 |
// Language to display this widget in (like en-us).
|
|
|
1764 |
// Defaults to brower's specified preferred language (typically the language of the OS)
|
|
|
1765 |
lang: "",
|
|
|
1766 |
|
|
|
1767 |
// dir: String
|
|
|
1768 |
// Bi-directional support, as defined by the HTML DIR attribute. Either left-to-right "ltr" or right-to-left "rtl".
|
|
|
1769 |
dir: "",
|
|
|
1770 |
|
|
|
1771 |
// class: String
|
|
|
1772 |
// HTML class attribute
|
|
|
1773 |
"class": "",
|
|
|
1774 |
|
|
|
1775 |
// style: String
|
|
|
1776 |
// HTML style attribute
|
|
|
1777 |
style: "",
|
|
|
1778 |
|
|
|
1779 |
// title: String
|
|
|
1780 |
// HTML title attribute
|
|
|
1781 |
title: "",
|
|
|
1782 |
|
|
|
1783 |
// srcNodeRef: DomNode
|
|
|
1784 |
// pointer to original dom node
|
|
|
1785 |
srcNodeRef: null,
|
|
|
1786 |
|
|
|
1787 |
// domNode: DomNode
|
|
|
1788 |
// this is our visible representation of the widget! Other DOM
|
|
|
1789 |
// Nodes may by assigned to other properties, usually through the
|
|
|
1790 |
// template system's dojoAttachPonit syntax, but the domNode
|
|
|
1791 |
// property is the canonical "top level" node in widget UI.
|
|
|
1792 |
domNode: null,
|
|
|
1793 |
|
|
|
1794 |
// attributeMap: Object
|
|
|
1795 |
// A map of attributes and attachpoints -- typically standard HTML attributes -- to set
|
|
|
1796 |
// on the widget's dom, at the "domNode" attach point, by default.
|
|
|
1797 |
// Other node references can be specified as properties of 'this'
|
|
|
1798 |
attributeMap: {id:"", dir:"", lang:"", "class":"", style:"", title:""}, // TODO: add on* handlers?
|
|
|
1799 |
|
|
|
1800 |
//////////// INITIALIZATION METHODS ///////////////////////////////////////
|
|
|
1801 |
|
|
|
1802 |
postscript: function(params, srcNodeRef){
|
|
|
1803 |
this.create(params, srcNodeRef);
|
|
|
1804 |
},
|
|
|
1805 |
|
|
|
1806 |
create: function(params, srcNodeRef){
|
|
|
1807 |
// summary:
|
|
|
1808 |
// To understand the process by which widgets are instantiated, it
|
|
|
1809 |
// is critical to understand what other methods create calls and
|
|
|
1810 |
// which of them you'll want to override. Of course, adventurous
|
|
|
1811 |
// developers could override create entirely, but this should
|
|
|
1812 |
// only be done as a last resort.
|
|
|
1813 |
//
|
|
|
1814 |
// Below is a list of the methods that are called, in the order
|
|
|
1815 |
// they are fired, along with notes about what they do and if/when
|
|
|
1816 |
// you should over-ride them in your widget:
|
|
|
1817 |
//
|
|
|
1818 |
// postMixInProperties:
|
|
|
1819 |
// a stub function that you can over-ride to modify
|
|
|
1820 |
// variables that may have been naively assigned by
|
|
|
1821 |
// mixInProperties
|
|
|
1822 |
// # widget is added to manager object here
|
|
|
1823 |
// buildRendering
|
|
|
1824 |
// Subclasses use this method to handle all UI initialization
|
|
|
1825 |
// Sets this.domNode. Templated widgets do this automatically
|
|
|
1826 |
// and otherwise it just uses the source dom node.
|
|
|
1827 |
// postCreate
|
|
|
1828 |
// a stub function that you can over-ride to modify take
|
|
|
1829 |
// actions once the widget has been placed in the UI
|
|
|
1830 |
|
|
|
1831 |
// store pointer to original dom tree
|
|
|
1832 |
this.srcNodeRef = dojo.byId(srcNodeRef);
|
|
|
1833 |
|
|
|
1834 |
// For garbage collection. An array of handles returned by Widget.connect()
|
|
|
1835 |
// Each handle returned from Widget.connect() is an array of handles from dojo.connect()
|
|
|
1836 |
this._connects=[];
|
|
|
1837 |
|
|
|
1838 |
// _attaches: String[]
|
|
|
1839 |
// names of all our dojoAttachPoint variables
|
|
|
1840 |
this._attaches=[];
|
|
|
1841 |
|
|
|
1842 |
//mixin our passed parameters
|
|
|
1843 |
if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; }
|
|
|
1844 |
if(params){
|
|
|
1845 |
dojo.mixin(this,params);
|
|
|
1846 |
}
|
|
|
1847 |
this.postMixInProperties();
|
|
|
1848 |
|
|
|
1849 |
// generate an id for the widget if one wasn't specified
|
|
|
1850 |
// (be sure to do this before buildRendering() because that function might
|
|
|
1851 |
// expect the id to be there.
|
|
|
1852 |
if(!this.id){
|
|
|
1853 |
this.id=dijit.getUniqueId(this.declaredClass.replace(/\./g,"_"));
|
|
|
1854 |
}
|
|
|
1855 |
dijit.registry.add(this);
|
|
|
1856 |
|
|
|
1857 |
this.buildRendering();
|
|
|
1858 |
|
|
|
1859 |
// Copy attributes listed in attributeMap into the [newly created] DOM for the widget.
|
|
|
1860 |
// The placement of these attributes is according to the property mapping in attributeMap.
|
|
|
1861 |
// Note special handling for 'style' and 'class' attributes which are lists and can
|
|
|
1862 |
// have elements from both old and new structures, and some attributes like "type"
|
|
|
1863 |
// cannot be processed this way as they are not mutable.
|
|
|
1864 |
if(this.domNode){
|
|
|
1865 |
for(var attr in this.attributeMap){
|
|
|
1866 |
var mapNode = this[this.attributeMap[attr] || "domNode"];
|
|
|
1867 |
var value = this[attr];
|
|
|
1868 |
if(typeof value != "object" && (value !== "" || (params && params[attr]))){
|
|
|
1869 |
switch(attr){
|
|
|
1870 |
case "class":
|
|
|
1871 |
dojo.addClass(mapNode, value);
|
|
|
1872 |
break;
|
|
|
1873 |
case "style":
|
|
|
1874 |
if(mapNode.style.cssText){
|
|
|
1875 |
mapNode.style.cssText += "; " + value;// FIXME: Opera
|
|
|
1876 |
}else{
|
|
|
1877 |
mapNode.style.cssText = value;
|
|
|
1878 |
}
|
|
|
1879 |
break;
|
|
|
1880 |
default:
|
|
|
1881 |
mapNode.setAttribute(attr, value);
|
|
|
1882 |
}
|
|
|
1883 |
}
|
|
|
1884 |
}
|
|
|
1885 |
}
|
|
|
1886 |
|
|
|
1887 |
if(this.domNode){
|
|
|
1888 |
this.domNode.setAttribute("widgetId", this.id);
|
|
|
1889 |
}
|
|
|
1890 |
this.postCreate();
|
|
|
1891 |
|
|
|
1892 |
// If srcNodeRef has been processed and removed from the DOM (e.g. TemplatedWidget) then delete it to allow GC.
|
|
|
1893 |
if(this.srcNodeRef && !this.srcNodeRef.parentNode){
|
|
|
1894 |
delete this.srcNodeRef;
|
|
|
1895 |
}
|
|
|
1896 |
},
|
|
|
1897 |
|
|
|
1898 |
postMixInProperties: function(){
|
|
|
1899 |
// summary
|
|
|
1900 |
// Called after the parameters to the widget have been read-in,
|
|
|
1901 |
// but before the widget template is instantiated.
|
|
|
1902 |
// Especially useful to set properties that are referenced in the widget template.
|
|
|
1903 |
},
|
|
|
1904 |
|
|
|
1905 |
buildRendering: function(){
|
|
|
1906 |
// summary:
|
|
|
1907 |
// Construct the UI for this widget, setting this.domNode.
|
|
|
1908 |
// Most widgets will mixin TemplatedWidget, which overrides this method.
|
|
|
1909 |
this.domNode = this.srcNodeRef || dojo.doc.createElement('div');
|
|
|
1910 |
},
|
|
|
1911 |
|
|
|
1912 |
postCreate: function(){
|
|
|
1913 |
// summary:
|
|
|
1914 |
// Called after a widget's dom has been setup
|
|
|
1915 |
},
|
|
|
1916 |
|
|
|
1917 |
startup: function(){
|
|
|
1918 |
// summary:
|
|
|
1919 |
// Called after a widget's children, and other widgets on the page, have been created.
|
|
|
1920 |
// Provides an opportunity to manipulate any children before they are displayed
|
|
|
1921 |
// This is useful for composite widgets that need to control or layout sub-widgets
|
|
|
1922 |
// Many layout widgets can use this as a wiring phase
|
|
|
1923 |
},
|
|
|
1924 |
|
|
|
1925 |
//////////// DESTROY FUNCTIONS ////////////////////////////////
|
|
|
1926 |
|
|
|
1927 |
destroyRecursive: function(/*Boolean*/ finalize){
|
|
|
1928 |
// summary:
|
|
|
1929 |
// Destroy this widget and it's descendants. This is the generic
|
|
|
1930 |
// "destructor" function that all widget users should call to
|
|
|
1931 |
// cleanly discard with a widget. Once a widget is destroyed, it's
|
|
|
1932 |
// removed from the manager object.
|
|
|
1933 |
// finalize: Boolean
|
|
|
1934 |
// is this function being called part of global environment
|
|
|
1935 |
// tear-down?
|
|
|
1936 |
|
|
|
1937 |
this.destroyDescendants();
|
|
|
1938 |
this.destroy();
|
|
|
1939 |
},
|
|
|
1940 |
|
|
|
1941 |
destroy: function(/*Boolean*/ finalize){
|
|
|
1942 |
// summary:
|
|
|
1943 |
// Destroy this widget, but not its descendants
|
|
|
1944 |
// finalize: Boolean
|
|
|
1945 |
// is this function being called part of global environment
|
|
|
1946 |
// tear-down?
|
|
|
1947 |
this.uninitialize();
|
|
|
1948 |
dojo.forEach(this._connects, function(array){
|
|
|
1949 |
dojo.forEach(array, dojo.disconnect);
|
|
|
1950 |
});
|
|
|
1951 |
this.destroyRendering(finalize);
|
|
|
1952 |
dijit.registry.remove(this.id);
|
|
|
1953 |
},
|
|
|
1954 |
|
|
|
1955 |
destroyRendering: function(/*Boolean*/ finalize){
|
|
|
1956 |
// summary:
|
|
|
1957 |
// Destroys the DOM nodes associated with this widget
|
|
|
1958 |
// finalize: Boolean
|
|
|
1959 |
// is this function being called part of global environment
|
|
|
1960 |
// tear-down?
|
|
|
1961 |
|
|
|
1962 |
if(this.bgIframe){
|
|
|
1963 |
this.bgIframe.destroy();
|
|
|
1964 |
delete this.bgIframe;
|
|
|
1965 |
}
|
|
|
1966 |
|
|
|
1967 |
if(this.domNode){
|
|
|
1968 |
dojo._destroyElement(this.domNode);
|
|
|
1969 |
delete this.domNode;
|
|
|
1970 |
}
|
|
|
1971 |
|
|
|
1972 |
if(this.srcNodeRef){
|
|
|
1973 |
dojo._destroyElement(this.srcNodeRef);
|
|
|
1974 |
delete this.srcNodeRef;
|
|
|
1975 |
}
|
|
|
1976 |
},
|
|
|
1977 |
|
|
|
1978 |
destroyDescendants: function(){
|
|
|
1979 |
// summary:
|
|
|
1980 |
// Recursively destroy the children of this widget and their
|
|
|
1981 |
// descendants.
|
|
|
1982 |
|
|
|
1983 |
// TODO: should I destroy in the reverse order, to go bottom up?
|
|
|
1984 |
dojo.forEach(this.getDescendants(), function(widget){ widget.destroy(); });
|
|
|
1985 |
},
|
|
|
1986 |
|
|
|
1987 |
uninitialize: function(){
|
|
|
1988 |
// summary:
|
|
|
1989 |
// stub function. Over-ride to implement custom widget tear-down
|
|
|
1990 |
// behavior.
|
|
|
1991 |
return false;
|
|
|
1992 |
},
|
|
|
1993 |
|
|
|
1994 |
////////////////// MISCELLANEOUS METHODS ///////////////////
|
|
|
1995 |
|
|
|
1996 |
toString: function(){
|
|
|
1997 |
// summary:
|
|
|
1998 |
// returns a string that represents the widget. When a widget is
|
|
|
1999 |
// cast to a string, this method will be used to generate the
|
|
|
2000 |
// output. Currently, it does not implement any sort of reversable
|
|
|
2001 |
// serialization.
|
|
|
2002 |
return '[Widget ' + this.declaredClass + ', ' + (this.id || 'NO ID') + ']'; // String
|
|
|
2003 |
},
|
|
|
2004 |
|
|
|
2005 |
getDescendants: function(){
|
|
|
2006 |
// summary:
|
|
|
2007 |
// return all the descendant widgets
|
|
|
2008 |
var list = dojo.query('[widgetId]', this.domNode);
|
|
|
2009 |
return list.map(dijit.byNode); // Array
|
|
|
2010 |
},
|
|
|
2011 |
|
|
|
2012 |
nodesWithKeyClick : ["input", "button"],
|
|
|
2013 |
|
|
|
2014 |
connect: function(
|
|
|
2015 |
/*Object|null*/ obj,
|
|
|
2016 |
/*String*/ event,
|
|
|
2017 |
/*String|Function*/ method){
|
|
|
2018 |
|
|
|
2019 |
// summary:
|
|
|
2020 |
// Connects specified obj/event to specified method of this object
|
|
|
2021 |
// and registers for disconnect() on widget destroy.
|
|
|
2022 |
// Special event: "ondijitclick" triggers on a click or enter-down or space-up
|
|
|
2023 |
// Similar to dojo.connect() but takes three arguments rather than four.
|
|
|
2024 |
var handles =[];
|
|
|
2025 |
if(event == "ondijitclick"){
|
|
|
2026 |
var w = this;
|
|
|
2027 |
// add key based click activation for unsupported nodes.
|
|
|
2028 |
if(!this.nodesWithKeyClick[obj.nodeName]){
|
|
|
2029 |
handles.push(dojo.connect(obj, "onkeydown", this,
|
|
|
2030 |
function(e){
|
|
|
2031 |
if(e.keyCode == dojo.keys.ENTER){
|
|
|
2032 |
return (dojo.isString(method))?
|
|
|
2033 |
w[method](e) : method.call(w, e);
|
|
|
2034 |
}else if(e.keyCode == dojo.keys.SPACE){
|
|
|
2035 |
// stop space down as it causes IE to scroll
|
|
|
2036 |
// the browser window
|
|
|
2037 |
dojo.stopEvent(e);
|
|
|
2038 |
}
|
|
|
2039 |
}));
|
|
|
2040 |
handles.push(dojo.connect(obj, "onkeyup", this,
|
|
|
2041 |
function(e){
|
|
|
2042 |
if(e.keyCode == dojo.keys.SPACE){
|
|
|
2043 |
return dojo.isString(method) ?
|
|
|
2044 |
w[method](e) : method.call(w, e);
|
|
|
2045 |
}
|
|
|
2046 |
}));
|
|
|
2047 |
}
|
|
|
2048 |
event = "onclick";
|
|
|
2049 |
}
|
|
|
2050 |
handles.push(dojo.connect(obj, event, this, method));
|
|
|
2051 |
|
|
|
2052 |
// return handles for FormElement and ComboBox
|
|
|
2053 |
this._connects.push(handles);
|
|
|
2054 |
return handles;
|
|
|
2055 |
},
|
|
|
2056 |
|
|
|
2057 |
disconnect: function(/*Object*/ handles){
|
|
|
2058 |
// summary:
|
|
|
2059 |
// Disconnects handle created by this.connect.
|
|
|
2060 |
// Also removes handle from this widget's list of connects
|
|
|
2061 |
for(var i=0; i<this._connects.length; i++){
|
|
|
2062 |
if(this._connects[i]==handles){
|
|
|
2063 |
dojo.forEach(handles, dojo.disconnect);
|
|
|
2064 |
this._connects.splice(i, 1);
|
|
|
2065 |
return;
|
|
|
2066 |
}
|
|
|
2067 |
}
|
|
|
2068 |
},
|
|
|
2069 |
|
|
|
2070 |
isLeftToRight: function(){
|
|
|
2071 |
// summary:
|
|
|
2072 |
// Checks the DOM to for the text direction for bi-directional support
|
|
|
2073 |
// description:
|
|
|
2074 |
// This method cannot be used during widget construction because the widget
|
|
|
2075 |
// must first be connected to the DOM tree. Parent nodes are searched for the
|
|
|
2076 |
// 'dir' attribute until one is found, otherwise left to right mode is assumed.
|
|
|
2077 |
// See HTML spec, DIR attribute for more information.
|
|
|
2078 |
|
|
|
2079 |
if(typeof this._ltr == "undefined"){
|
|
|
2080 |
this._ltr = dojo.getComputedStyle(this.domNode).direction != "rtl";
|
|
|
2081 |
}
|
|
|
2082 |
return this._ltr; //Boolean
|
|
|
2083 |
},
|
|
|
2084 |
|
|
|
2085 |
isFocusable: function(){
|
|
|
2086 |
// summary:
|
|
|
2087 |
// Return true if this widget can currently be focused
|
|
|
2088 |
// and false if not
|
|
|
2089 |
return this.focus && (dojo.style(this.domNode, "display") != "none");
|
|
|
2090 |
}
|
|
|
2091 |
});
|
|
|
2092 |
|
|
|
2093 |
}
|
|
|
2094 |
|
|
|
2095 |
if(!dojo._hasResource["dojo.string"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
2096 |
dojo._hasResource["dojo.string"] = true;
|
|
|
2097 |
dojo.provide("dojo.string");
|
|
|
2098 |
|
|
|
2099 |
dojo.string.pad = function(/*String*/text, /*int*/size, /*String?*/ch, /*boolean?*/end){
|
|
|
2100 |
// summary:
|
|
|
2101 |
// Pad a string to guarantee that it is at least 'size' length by
|
|
|
2102 |
// filling with the character 'c' at either the start or end of the
|
|
|
2103 |
// string. Pads at the start, by default.
|
|
|
2104 |
// text: the string to pad
|
|
|
2105 |
// size: length to provide padding
|
|
|
2106 |
// ch: character to pad, defaults to '0'
|
|
|
2107 |
// end: adds padding at the end if true, otherwise pads at start
|
|
|
2108 |
|
|
|
2109 |
var out = String(text);
|
|
|
2110 |
if(!ch){
|
|
|
2111 |
ch = '0';
|
|
|
2112 |
}
|
|
|
2113 |
while(out.length < size){
|
|
|
2114 |
if(end){
|
|
|
2115 |
out += ch;
|
|
|
2116 |
}else{
|
|
|
2117 |
out = ch + out;
|
|
|
2118 |
}
|
|
|
2119 |
}
|
|
|
2120 |
return out; // String
|
|
|
2121 |
};
|
|
|
2122 |
|
|
|
2123 |
dojo.string.substitute = function( /*String*/template,
|
|
|
2124 |
/*Object or Array*/map,
|
|
|
2125 |
/*Function?*/transform,
|
|
|
2126 |
/*Object?*/thisObject){
|
|
|
2127 |
// summary:
|
|
|
2128 |
// Performs parameterized substitutions on a string. Throws an
|
|
|
2129 |
// exception if any parameter is unmatched.
|
|
|
2130 |
// description:
|
|
|
2131 |
// For example,
|
|
|
2132 |
// | dojo.string.substitute("File '${0}' is not found in directory '${1}'.",["foo.html","/temp"]);
|
|
|
2133 |
// | dojo.string.substitute("File '${name}' is not found in directory '${info.dir}'.",{name: "foo.html", info: {dir: "/temp"}});
|
|
|
2134 |
// both return
|
|
|
2135 |
// "File 'foo.html' is not found in directory '/temp'."
|
|
|
2136 |
// template:
|
|
|
2137 |
// a string with expressions in the form ${key} to be replaced or
|
|
|
2138 |
// ${key:format} which specifies a format function. NOTE syntax has
|
|
|
2139 |
// changed from %{key}
|
|
|
2140 |
// map: where to look for substitutions
|
|
|
2141 |
// transform:
|
|
|
2142 |
// a function to process all parameters before substitution takes
|
|
|
2143 |
// place, e.g. dojo.string.encodeXML
|
|
|
2144 |
// thisObject:
|
|
|
2145 |
// where to look for optional format function; default to the global
|
|
|
2146 |
// namespace
|
|
|
2147 |
|
|
|
2148 |
return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g, function(match, key, format){
|
|
|
2149 |
var value = dojo.getObject(key,false,map);
|
|
|
2150 |
if(format){ value = dojo.getObject(format,false,thisObject)(value);}
|
|
|
2151 |
if(transform){ value = transform(value, key); }
|
|
|
2152 |
return value.toString();
|
|
|
2153 |
}); // string
|
|
|
2154 |
};
|
|
|
2155 |
|
|
|
2156 |
dojo.string.trim = function(/*String*/ str){
|
|
|
2157 |
// summary: trims whitespaces from both sides of the string
|
|
|
2158 |
// description:
|
|
|
2159 |
// This version of trim() was taken from Steven Levithan's blog:
|
|
|
2160 |
// http://blog.stevenlevithan.com/archives/faster-trim-javascript.
|
|
|
2161 |
// The short yet good-performing version of this function is
|
|
|
2162 |
// dojo.trim(), which is part of the base.
|
|
|
2163 |
str = str.replace(/^\s+/, '');
|
|
|
2164 |
for(var i = str.length - 1; i > 0; i--){
|
|
|
2165 |
if(/\S/.test(str.charAt(i))){
|
|
|
2166 |
str = str.substring(0, i + 1);
|
|
|
2167 |
break;
|
|
|
2168 |
}
|
|
|
2169 |
}
|
|
|
2170 |
return str; // String
|
|
|
2171 |
};
|
|
|
2172 |
|
|
|
2173 |
}
|
|
|
2174 |
|
|
|
2175 |
if(!dojo._hasResource["dijit._Templated"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
2176 |
dojo._hasResource["dijit._Templated"] = true;
|
|
|
2177 |
dojo.provide("dijit._Templated");
|
|
|
2178 |
|
|
|
2179 |
|
|
|
2180 |
|
|
|
2181 |
|
|
|
2182 |
|
|
|
2183 |
|
|
|
2184 |
dojo.declare("dijit._Templated",
|
|
|
2185 |
null,
|
|
|
2186 |
{
|
|
|
2187 |
// summary:
|
|
|
2188 |
// mixin for widgets that are instantiated from a template
|
|
|
2189 |
|
|
|
2190 |
// templateNode: DomNode
|
|
|
2191 |
// a node that represents the widget template. Pre-empts both templateString and templatePath.
|
|
|
2192 |
templateNode: null,
|
|
|
2193 |
|
|
|
2194 |
// templateString String:
|
|
|
2195 |
// a string that represents the widget template. Pre-empts the
|
|
|
2196 |
// templatePath. In builds that have their strings "interned", the
|
|
|
2197 |
// templatePath is converted to an inline templateString, thereby
|
|
|
2198 |
// preventing a synchronous network call.
|
|
|
2199 |
templateString: null,
|
|
|
2200 |
|
|
|
2201 |
// templatePath: String
|
|
|
2202 |
// Path to template (HTML file) for this widget
|
|
|
2203 |
templatePath: null,
|
|
|
2204 |
|
|
|
2205 |
// widgetsInTemplate Boolean:
|
|
|
2206 |
// should we parse the template to find widgets that might be
|
|
|
2207 |
// declared in markup inside it? false by default.
|
|
|
2208 |
widgetsInTemplate: false,
|
|
|
2209 |
|
|
|
2210 |
// containerNode DomNode:
|
|
|
2211 |
// holds child elements. "containerNode" is generally set via a
|
|
|
2212 |
// dojoAttachPoint assignment and it designates where children of
|
|
|
2213 |
// the src dom node will be placed
|
|
|
2214 |
containerNode: null,
|
|
|
2215 |
|
|
|
2216 |
// skipNodeCache Boolean:
|
|
|
2217 |
// if using a cached widget template node poses issues for a
|
|
|
2218 |
// particular widget class, it can set this property to ensure
|
|
|
2219 |
// that its template is always re-built from a string
|
|
|
2220 |
_skipNodeCache: false,
|
|
|
2221 |
|
|
|
2222 |
// method over-ride
|
|
|
2223 |
buildRendering: function(){
|
|
|
2224 |
// summary:
|
|
|
2225 |
// Construct the UI for this widget from a template, setting this.domNode.
|
|
|
2226 |
|
|
|
2227 |
// Lookup cached version of template, and download to cache if it
|
|
|
2228 |
// isn't there already. Returns either a DomNode or a string, depending on
|
|
|
2229 |
// whether or not the template contains ${foo} replacement parameters.
|
|
|
2230 |
var cached = dijit._Templated.getCachedTemplate(this.templatePath, this.templateString, this._skipNodeCache);
|
|
|
2231 |
|
|
|
2232 |
var node;
|
|
|
2233 |
if(dojo.isString(cached)){
|
|
|
2234 |
var className = this.declaredClass, _this = this;
|
|
|
2235 |
// Cache contains a string because we need to do property replacement
|
|
|
2236 |
// do the property replacement
|
|
|
2237 |
var tstr = dojo.string.substitute(cached, this, function(value, key){
|
|
|
2238 |
if(key.charAt(0) == '!'){ value = _this[key.substr(1)]; }
|
|
|
2239 |
if(typeof value == "undefined"){ throw new Error(className+" template:"+key); } // a debugging aide
|
|
|
2240 |
if(!value){ return ""; }
|
|
|
2241 |
|
|
|
2242 |
// Substitution keys beginning with ! will skip the transform step,
|
|
|
2243 |
// in case a user wishes to insert unescaped markup, e.g. ${!foo}
|
|
|
2244 |
return key.charAt(0) == "!" ? value :
|
|
|
2245 |
// Safer substitution, see heading "Attribute values" in
|
|
|
2246 |
// http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
|
|
|
2247 |
value.toString().replace(/"/g,"""); //TODO: add &? use encodeXML method?
|
|
|
2248 |
}, this);
|
|
|
2249 |
|
|
|
2250 |
node = dijit._Templated._createNodesFromText(tstr)[0];
|
|
|
2251 |
}else{
|
|
|
2252 |
// if it's a node, all we have to do is clone it
|
|
|
2253 |
node = cached.cloneNode(true);
|
|
|
2254 |
}
|
|
|
2255 |
|
|
|
2256 |
// recurse through the node, looking for, and attaching to, our
|
|
|
2257 |
// attachment points which should be defined on the template node.
|
|
|
2258 |
this._attachTemplateNodes(node);
|
|
|
2259 |
|
|
|
2260 |
var source = this.srcNodeRef;
|
|
|
2261 |
if(source && source.parentNode){
|
|
|
2262 |
source.parentNode.replaceChild(node, source);
|
|
|
2263 |
}
|
|
|
2264 |
|
|
|
2265 |
this.domNode = node;
|
|
|
2266 |
if(this.widgetsInTemplate){
|
|
|
2267 |
var childWidgets = dojo.parser.parse(node);
|
|
|
2268 |
this._attachTemplateNodes(childWidgets, function(n,p){
|
|
|
2269 |
return n[p];
|
|
|
2270 |
});
|
|
|
2271 |
}
|
|
|
2272 |
|
|
|
2273 |
this._fillContent(source);
|
|
|
2274 |
},
|
|
|
2275 |
|
|
|
2276 |
_fillContent: function(/*DomNode*/ source){
|
|
|
2277 |
// summary:
|
|
|
2278 |
// relocate source contents to templated container node
|
|
|
2279 |
// this.containerNode must be able to receive children, or exceptions will be thrown
|
|
|
2280 |
var dest = this.containerNode;
|
|
|
2281 |
if(source && dest){
|
|
|
2282 |
while(source.hasChildNodes()){
|
|
|
2283 |
dest.appendChild(source.firstChild);
|
|
|
2284 |
}
|
|
|
2285 |
}
|
|
|
2286 |
},
|
|
|
2287 |
|
|
|
2288 |
_attachTemplateNodes: function(rootNode, getAttrFunc){
|
|
|
2289 |
// summary:
|
|
|
2290 |
// map widget properties and functions to the handlers specified in
|
|
|
2291 |
// the dom node and it's descendants. This function iterates over all
|
|
|
2292 |
// nodes and looks for these properties:
|
|
|
2293 |
// * dojoAttachPoint
|
|
|
2294 |
// * dojoAttachEvent
|
|
|
2295 |
// * waiRole
|
|
|
2296 |
// * waiState
|
|
|
2297 |
// rootNode: DomNode|Array[Widgets]
|
|
|
2298 |
// the node to search for properties. All children will be searched.
|
|
|
2299 |
// getAttrFunc: function?
|
|
|
2300 |
// a function which will be used to obtain property for a given
|
|
|
2301 |
// DomNode/Widget
|
|
|
2302 |
|
|
|
2303 |
getAttrFunc = getAttrFunc || function(n,p){ return n.getAttribute(p); };
|
|
|
2304 |
|
|
|
2305 |
var nodes = dojo.isArray(rootNode) ? rootNode : (rootNode.all || rootNode.getElementsByTagName("*"));
|
|
|
2306 |
var x=dojo.isArray(rootNode)?0:-1;
|
|
|
2307 |
for(; x<nodes.length; x++){
|
|
|
2308 |
var baseNode = (x == -1) ? rootNode : nodes[x];
|
|
|
2309 |
if(this.widgetsInTemplate && getAttrFunc(baseNode,'dojoType')){
|
|
|
2310 |
continue;
|
|
|
2311 |
}
|
|
|
2312 |
// Process dojoAttachPoint
|
|
|
2313 |
var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint");
|
|
|
2314 |
if(attachPoint){
|
|
|
2315 |
var point, points = attachPoint.split(/\s*,\s*/);
|
|
|
2316 |
while(point=points.shift()){
|
|
|
2317 |
if(dojo.isArray(this[point])){
|
|
|
2318 |
this[point].push(baseNode);
|
|
|
2319 |
}else{
|
|
|
2320 |
this[point]=baseNode;
|
|
|
2321 |
}
|
|
|
2322 |
}
|
|
|
2323 |
}
|
|
|
2324 |
|
|
|
2325 |
// Process dojoAttachEvent
|
|
|
2326 |
var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent");
|
|
|
2327 |
if(attachEvent){
|
|
|
2328 |
// NOTE: we want to support attributes that have the form
|
|
|
2329 |
// "domEvent: nativeEvent; ..."
|
|
|
2330 |
var event, events = attachEvent.split(/\s*,\s*/);
|
|
|
2331 |
var trim = dojo.trim;
|
|
|
2332 |
while(event=events.shift()){
|
|
|
2333 |
if(event){
|
|
|
2334 |
var thisFunc = null;
|
|
|
2335 |
if(event.indexOf(":") != -1){
|
|
|
2336 |
// oh, if only JS had tuple assignment
|
|
|
2337 |
var funcNameArr = event.split(":");
|
|
|
2338 |
event = trim(funcNameArr[0]);
|
|
|
2339 |
thisFunc = trim(funcNameArr[1]);
|
|
|
2340 |
}else{
|
|
|
2341 |
event = trim(event);
|
|
|
2342 |
}
|
|
|
2343 |
if(!thisFunc){
|
|
|
2344 |
thisFunc = event;
|
|
|
2345 |
}
|
|
|
2346 |
this.connect(baseNode, event, thisFunc);
|
|
|
2347 |
}
|
|
|
2348 |
}
|
|
|
2349 |
}
|
|
|
2350 |
|
|
|
2351 |
// waiRole, waiState
|
|
|
2352 |
var role = getAttrFunc(baseNode, "waiRole");
|
|
|
2353 |
if(role){
|
|
|
2354 |
dijit.setWaiRole(baseNode, role);
|
|
|
2355 |
}
|
|
|
2356 |
var values = getAttrFunc(baseNode, "waiState");
|
|
|
2357 |
if(values){
|
|
|
2358 |
dojo.forEach(values.split(/\s*,\s*/), function(stateValue){
|
|
|
2359 |
if(stateValue.indexOf('-') != -1){
|
|
|
2360 |
var pair = stateValue.split('-');
|
|
|
2361 |
dijit.setWaiState(baseNode, pair[0], pair[1]);
|
|
|
2362 |
}
|
|
|
2363 |
});
|
|
|
2364 |
}
|
|
|
2365 |
|
|
|
2366 |
}
|
|
|
2367 |
}
|
|
|
2368 |
}
|
|
|
2369 |
);
|
|
|
2370 |
|
|
|
2371 |
// key is either templatePath or templateString; object is either string or DOM tree
|
|
|
2372 |
dijit._Templated._templateCache = {};
|
|
|
2373 |
|
|
|
2374 |
dijit._Templated.getCachedTemplate = function(templatePath, templateString, alwaysUseString){
|
|
|
2375 |
// summary:
|
|
|
2376 |
// static method to get a template based on the templatePath or
|
|
|
2377 |
// templateString key
|
|
|
2378 |
// templatePath: String
|
|
|
2379 |
// the URL to get the template from. dojo.uri.Uri is often passed as well.
|
|
|
2380 |
// templateString: String?
|
|
|
2381 |
// a string to use in lieu of fetching the template from a URL
|
|
|
2382 |
// Returns:
|
|
|
2383 |
// Either string (if there are ${} variables that need to be replaced) or just
|
|
|
2384 |
// a DOM tree (if the node can be cloned directly)
|
|
|
2385 |
|
|
|
2386 |
// is it already cached?
|
|
|
2387 |
var tmplts = dijit._Templated._templateCache;
|
|
|
2388 |
var key = templateString || templatePath;
|
|
|
2389 |
var cached = tmplts[key];
|
|
|
2390 |
if(cached){
|
|
|
2391 |
return cached;
|
|
|
2392 |
}
|
|
|
2393 |
|
|
|
2394 |
// If necessary, load template string from template path
|
|
|
2395 |
if(!templateString){
|
|
|
2396 |
templateString = dijit._Templated._sanitizeTemplateString(dojo._getText(templatePath));
|
|
|
2397 |
}
|
|
|
2398 |
|
|
|
2399 |
templateString = dojo.string.trim(templateString);
|
|
|
2400 |
|
|
|
2401 |
if(templateString.match(/\$\{([^\}]+)\}/g) || alwaysUseString){
|
|
|
2402 |
// there are variables in the template so all we can do is cache the string
|
|
|
2403 |
return (tmplts[key] = templateString); //String
|
|
|
2404 |
}else{
|
|
|
2405 |
// there are no variables in the template so we can cache the DOM tree
|
|
|
2406 |
return (tmplts[key] = dijit._Templated._createNodesFromText(templateString)[0]); //Node
|
|
|
2407 |
}
|
|
|
2408 |
};
|
|
|
2409 |
|
|
|
2410 |
dijit._Templated._sanitizeTemplateString = function(/*String*/tString){
|
|
|
2411 |
// summary:
|
|
|
2412 |
// Strips <?xml ...?> declarations so that external SVG and XML
|
|
|
2413 |
// documents can be added to a document without worry. Also, if the string
|
|
|
2414 |
// is an HTML document, only the part inside the body tag is returned.
|
|
|
2415 |
if(tString){
|
|
|
2416 |
tString = tString.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
|
|
|
2417 |
var matches = tString.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
|
|
|
2418 |
if(matches){
|
|
|
2419 |
tString = matches[1];
|
|
|
2420 |
}
|
|
|
2421 |
}else{
|
|
|
2422 |
tString = "";
|
|
|
2423 |
}
|
|
|
2424 |
return tString; //String
|
|
|
2425 |
};
|
|
|
2426 |
|
|
|
2427 |
|
|
|
2428 |
if(dojo.isIE){
|
|
|
2429 |
dojo.addOnUnload(function(){
|
|
|
2430 |
var cache = dijit._Templated._templateCache;
|
|
|
2431 |
for(var key in cache){
|
|
|
2432 |
var value = cache[key];
|
|
|
2433 |
if(!isNaN(value.nodeType)){ // isNode equivalent
|
|
|
2434 |
dojo._destroyElement(value);
|
|
|
2435 |
}
|
|
|
2436 |
delete cache[key];
|
|
|
2437 |
}
|
|
|
2438 |
});
|
|
|
2439 |
}
|
|
|
2440 |
|
|
|
2441 |
(function(){
|
|
|
2442 |
var tagMap = {
|
|
|
2443 |
cell: {re: /^<t[dh][\s\r\n>]/i, pre: "<table><tbody><tr>", post: "</tr></tbody></table>"},
|
|
|
2444 |
row: {re: /^<tr[\s\r\n>]/i, pre: "<table><tbody>", post: "</tbody></table>"},
|
|
|
2445 |
section: {re: /^<(thead|tbody|tfoot)[\s\r\n>]/i, pre: "<table>", post: "</table>"}
|
|
|
2446 |
};
|
|
|
2447 |
|
|
|
2448 |
// dummy container node used temporarily to hold nodes being created
|
|
|
2449 |
var tn;
|
|
|
2450 |
|
|
|
2451 |
dijit._Templated._createNodesFromText = function(/*String*/text){
|
|
|
2452 |
// summary:
|
|
|
2453 |
// Attempts to create a set of nodes based on the structure of the passed text.
|
|
|
2454 |
|
|
|
2455 |
if(!tn){
|
|
|
2456 |
tn = dojo.doc.createElement("div");
|
|
|
2457 |
tn.style.display="none";
|
|
|
2458 |
dojo.body().appendChild(tn);
|
|
|
2459 |
}
|
|
|
2460 |
var tableType = "none";
|
|
|
2461 |
var rtext = text.replace(/^\s+/, "");
|
|
|
2462 |
for(var type in tagMap){
|
|
|
2463 |
var map = tagMap[type];
|
|
|
2464 |
if(map.re.test(rtext)){
|
|
|
2465 |
tableType = type;
|
|
|
2466 |
text = map.pre + text + map.post;
|
|
|
2467 |
break;
|
|
|
2468 |
}
|
|
|
2469 |
}
|
|
|
2470 |
|
|
|
2471 |
tn.innerHTML = text;
|
|
|
2472 |
if(tn.normalize){
|
|
|
2473 |
tn.normalize();
|
|
|
2474 |
}
|
|
|
2475 |
|
|
|
2476 |
var tag = { cell: "tr", row: "tbody", section: "table" }[tableType];
|
|
|
2477 |
var _parent = (typeof tag != "undefined") ?
|
|
|
2478 |
tn.getElementsByTagName(tag)[0] :
|
|
|
2479 |
tn;
|
|
|
2480 |
|
|
|
2481 |
var nodes = [];
|
|
|
2482 |
while(_parent.firstChild){
|
|
|
2483 |
nodes.push(_parent.removeChild(_parent.firstChild));
|
|
|
2484 |
}
|
|
|
2485 |
tn.innerHTML="";
|
|
|
2486 |
return nodes; // Array
|
|
|
2487 |
}
|
|
|
2488 |
})();
|
|
|
2489 |
|
|
|
2490 |
// These arguments can be specified for widgets which are used in templates.
|
|
|
2491 |
// Since any widget can be specified as sub widgets in template, mix it
|
|
|
2492 |
// into the base widget class. (This is a hack, but it's effective.)
|
|
|
2493 |
dojo.extend(dijit._Widget,{
|
|
|
2494 |
dojoAttachEvent: "",
|
|
|
2495 |
dojoAttachPoint: "",
|
|
|
2496 |
waiRole: "",
|
|
|
2497 |
waiState:""
|
|
|
2498 |
})
|
|
|
2499 |
|
|
|
2500 |
}
|
|
|
2501 |
|
|
|
2502 |
if(!dojo._hasResource["dijit._Container"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
2503 |
dojo._hasResource["dijit._Container"] = true;
|
|
|
2504 |
dojo.provide("dijit._Container");
|
|
|
2505 |
|
|
|
2506 |
dojo.declare("dijit._Contained",
|
|
|
2507 |
null,
|
|
|
2508 |
{
|
|
|
2509 |
// summary
|
|
|
2510 |
// Mixin for widgets that are children of a container widget
|
|
|
2511 |
|
|
|
2512 |
getParent: function(){
|
|
|
2513 |
// summary:
|
|
|
2514 |
// returns the parent widget of this widget, assuming the parent
|
|
|
2515 |
// implements dijit._Container
|
|
|
2516 |
for(var p=this.domNode.parentNode; p; p=p.parentNode){
|
|
|
2517 |
var id = p.getAttribute && p.getAttribute("widgetId");
|
|
|
2518 |
if(id){
|
|
|
2519 |
var parent = dijit.byId(id);
|
|
|
2520 |
return parent.isContainer ? parent : null;
|
|
|
2521 |
}
|
|
|
2522 |
}
|
|
|
2523 |
return null;
|
|
|
2524 |
},
|
|
|
2525 |
|
|
|
2526 |
_getSibling: function(which){
|
|
|
2527 |
var node = this.domNode;
|
|
|
2528 |
do{
|
|
|
2529 |
node = node[which+"Sibling"];
|
|
|
2530 |
}while(node && node.nodeType != 1);
|
|
|
2531 |
if(!node){ return null; } // null
|
|
|
2532 |
var id = node.getAttribute("widgetId");
|
|
|
2533 |
return dijit.byId(id);
|
|
|
2534 |
},
|
|
|
2535 |
|
|
|
2536 |
getPreviousSibling: function(){
|
|
|
2537 |
// summary:
|
|
|
2538 |
// returns null if this is the first child of the parent,
|
|
|
2539 |
// otherwise returns the next element sibling to the "left".
|
|
|
2540 |
|
|
|
2541 |
return this._getSibling("previous");
|
|
|
2542 |
},
|
|
|
2543 |
|
|
|
2544 |
getNextSibling: function(){
|
|
|
2545 |
// summary:
|
|
|
2546 |
// returns null if this is the last child of the parent,
|
|
|
2547 |
// otherwise returns the next element sibling to the "right".
|
|
|
2548 |
|
|
|
2549 |
return this._getSibling("next");
|
|
|
2550 |
}
|
|
|
2551 |
}
|
|
|
2552 |
);
|
|
|
2553 |
|
|
|
2554 |
dojo.declare("dijit._Container",
|
|
|
2555 |
null,
|
|
|
2556 |
{
|
|
|
2557 |
// summary
|
|
|
2558 |
// Mixin for widgets that contain a list of children like SplitContainer
|
|
|
2559 |
|
|
|
2560 |
isContainer: true,
|
|
|
2561 |
|
|
|
2562 |
addChild: function(/*Widget*/ widget, /*int?*/ insertIndex){
|
|
|
2563 |
// summary:
|
|
|
2564 |
// Process the given child widget, inserting it's dom node as
|
|
|
2565 |
// a child of our dom node
|
|
|
2566 |
|
|
|
2567 |
if(insertIndex === undefined){
|
|
|
2568 |
insertIndex = "last";
|
|
|
2569 |
}
|
|
|
2570 |
var refNode = this.containerNode || this.domNode;
|
|
|
2571 |
if(insertIndex && typeof insertIndex == "number"){
|
|
|
2572 |
var children = dojo.query("> [widgetid]", refNode);
|
|
|
2573 |
if(children && children.length >= insertIndex){
|
|
|
2574 |
refNode = children[insertIndex-1]; insertIndex = "after";
|
|
|
2575 |
}
|
|
|
2576 |
}
|
|
|
2577 |
dojo.place(widget.domNode, refNode, insertIndex);
|
|
|
2578 |
|
|
|
2579 |
// If I've been started but the child widget hasn't been started,
|
|
|
2580 |
// start it now. Make sure to do this after widget has been
|
|
|
2581 |
// inserted into the DOM tree, so it can see that it's being controlled by me,
|
|
|
2582 |
// so it doesn't try to size itself.
|
|
|
2583 |
if(this._started && !widget._started){
|
|
|
2584 |
widget.startup();
|
|
|
2585 |
}
|
|
|
2586 |
},
|
|
|
2587 |
|
|
|
2588 |
removeChild: function(/*Widget*/ widget){
|
|
|
2589 |
// summary:
|
|
|
2590 |
// removes the passed widget instance from this widget but does
|
|
|
2591 |
// not destroy it
|
|
|
2592 |
var node = widget.domNode;
|
|
|
2593 |
node.parentNode.removeChild(node); // detach but don't destroy
|
|
|
2594 |
},
|
|
|
2595 |
|
|
|
2596 |
_nextElement: function(node){
|
|
|
2597 |
do{
|
|
|
2598 |
node = node.nextSibling;
|
|
|
2599 |
}while(node && node.nodeType != 1);
|
|
|
2600 |
return node;
|
|
|
2601 |
},
|
|
|
2602 |
|
|
|
2603 |
_firstElement: function(node){
|
|
|
2604 |
node = node.firstChild;
|
|
|
2605 |
if(node && node.nodeType != 1){
|
|
|
2606 |
node = this._nextElement(node);
|
|
|
2607 |
}
|
|
|
2608 |
return node;
|
|
|
2609 |
},
|
|
|
2610 |
|
|
|
2611 |
getChildren: function(){
|
|
|
2612 |
// summary:
|
|
|
2613 |
// Returns array of children widgets
|
|
|
2614 |
return dojo.query("> [widgetId]", this.containerNode || this.domNode).map(dijit.byNode); // Array
|
|
|
2615 |
},
|
|
|
2616 |
|
|
|
2617 |
hasChildren: function(){
|
|
|
2618 |
// summary:
|
|
|
2619 |
// Returns true if widget has children
|
|
|
2620 |
var cn = this.containerNode || this.domNode;
|
|
|
2621 |
return !!this._firstElement(cn); // Boolean
|
|
|
2622 |
},
|
|
|
2623 |
|
|
|
2624 |
_getSiblingOfChild: function(/*Widget*/ child, /*int*/ dir){
|
|
|
2625 |
// summary:
|
|
|
2626 |
// get the next or previous widget sibling of child
|
|
|
2627 |
// dir:
|
|
|
2628 |
// if 1, get the next sibling
|
|
|
2629 |
// if -1, get the previous sibling
|
|
|
2630 |
var node = child.domNode;
|
|
|
2631 |
var which = (dir>0 ? "nextSibling" : "previousSibling");
|
|
|
2632 |
do{
|
|
|
2633 |
node = node[which];
|
|
|
2634 |
}while(node && (node.nodeType != 1 || !dijit.byNode(node)));
|
|
|
2635 |
return node ? dijit.byNode(node) : null;
|
|
|
2636 |
}
|
|
|
2637 |
}
|
|
|
2638 |
);
|
|
|
2639 |
|
|
|
2640 |
dojo.declare("dijit._KeyNavContainer",
|
|
|
2641 |
[dijit._Container],
|
|
|
2642 |
{
|
|
|
2643 |
|
|
|
2644 |
// summary:
|
|
|
2645 |
// A _Container with keyboard navigation of its children.
|
|
|
2646 |
// To use this mixin, call connectKeyNavHandlers() in
|
|
|
2647 |
// postCreate() and call startupKeyNavChildren() in startup().
|
|
|
2648 |
|
|
|
2649 |
/*=====
|
|
|
2650 |
// focusedChild: Widget
|
|
|
2651 |
// The currently focused child widget, or null if there isn't one
|
|
|
2652 |
focusedChild: null,
|
|
|
2653 |
=====*/
|
|
|
2654 |
|
|
|
2655 |
_keyNavCodes: {},
|
|
|
2656 |
|
|
|
2657 |
connectKeyNavHandlers: function(/*Array*/ prevKeyCodes, /*Array*/ nextKeyCodes){
|
|
|
2658 |
// summary:
|
|
|
2659 |
// Call in postCreate() to attach the keyboard handlers
|
|
|
2660 |
// to the container.
|
|
|
2661 |
// preKeyCodes: Array
|
|
|
2662 |
// Key codes for navigating to the previous child.
|
|
|
2663 |
// nextKeyCodes: Array
|
|
|
2664 |
// Key codes for navigating to the next child.
|
|
|
2665 |
|
|
|
2666 |
var keyCodes = this._keyNavCodes = {};
|
|
|
2667 |
var prev = dojo.hitch(this, this.focusPrev);
|
|
|
2668 |
var next = dojo.hitch(this, this.focusNext);
|
|
|
2669 |
dojo.forEach(prevKeyCodes, function(code){ keyCodes[code] = prev });
|
|
|
2670 |
dojo.forEach(nextKeyCodes, function(code){ keyCodes[code] = next });
|
|
|
2671 |
this.connect(this.domNode, "onkeypress", "_onContainerKeypress");
|
|
|
2672 |
if(dojo.isIE){
|
|
|
2673 |
this.connect(this.domNode, "onactivate", "_onContainerFocus");
|
|
|
2674 |
this.connect(this.domNode, "ondeactivate", "_onContainerBlur");
|
|
|
2675 |
}else{
|
|
|
2676 |
this.connect(this.domNode, "onfocus", "_onContainerFocus");
|
|
|
2677 |
this.connect(this.domNode, "onblur", "_onContainerBlur");
|
|
|
2678 |
}
|
|
|
2679 |
},
|
|
|
2680 |
|
|
|
2681 |
startupKeyNavChildren: function(){
|
|
|
2682 |
// summary:
|
|
|
2683 |
// Call in startup() to set child tabindexes to -1
|
|
|
2684 |
dojo.forEach(this.getChildren(), dojo.hitch(this, "_setTabIndexMinusOne"));
|
|
|
2685 |
},
|
|
|
2686 |
|
|
|
2687 |
addChild: function(/*Widget*/ widget, /*int?*/ insertIndex){
|
|
|
2688 |
// summary: Add a child to our _Container
|
|
|
2689 |
dijit._KeyNavContainer.superclass.addChild.apply(this, arguments);
|
|
|
2690 |
this._setTabIndexMinusOne(widget);
|
|
|
2691 |
},
|
|
|
2692 |
|
|
|
2693 |
focus: function(){
|
|
|
2694 |
// summary: Default focus() implementation: focus the first child.
|
|
|
2695 |
this.focusFirstChild();
|
|
|
2696 |
},
|
|
|
2697 |
|
|
|
2698 |
focusFirstChild: function(){
|
|
|
2699 |
// summary: Focus the first focusable child in the container.
|
|
|
2700 |
this.focusChild(this._getFirstFocusableChild());
|
|
|
2701 |
},
|
|
|
2702 |
|
|
|
2703 |
focusNext: function(){
|
|
|
2704 |
// summary: Focus the next widget or focal node (for widgets
|
|
|
2705 |
// with multiple focal nodes) within this container.
|
|
|
2706 |
if(this.focusedChild && this.focusedChild.hasNextFocalNode
|
|
|
2707 |
&& this.focusedChild.hasNextFocalNode()){
|
|
|
2708 |
this.focusedChild.focusNext();
|
|
|
2709 |
return;
|
|
|
2710 |
}
|
|
|
2711 |
var child = this._getNextFocusableChild(this.focusedChild, 1);
|
|
|
2712 |
if(child.getFocalNodes){
|
|
|
2713 |
this.focusChild(child, child.getFocalNodes()[0]);
|
|
|
2714 |
}else{
|
|
|
2715 |
this.focusChild(child);
|
|
|
2716 |
}
|
|
|
2717 |
},
|
|
|
2718 |
|
|
|
2719 |
focusPrev: function(){
|
|
|
2720 |
// summary: Focus the previous widget or focal node (for widgets
|
|
|
2721 |
// with multiple focal nodes) within this container.
|
|
|
2722 |
if(this.focusedChild && this.focusedChild.hasPrevFocalNode
|
|
|
2723 |
&& this.focusedChild.hasPrevFocalNode()){
|
|
|
2724 |
this.focusedChild.focusPrev();
|
|
|
2725 |
return;
|
|
|
2726 |
}
|
|
|
2727 |
var child = this._getNextFocusableChild(this.focusedChild, -1);
|
|
|
2728 |
if(child.getFocalNodes){
|
|
|
2729 |
var nodes = child.getFocalNodes();
|
|
|
2730 |
this.focusChild(child, nodes[nodes.length-1]);
|
|
|
2731 |
}else{
|
|
|
2732 |
this.focusChild(child);
|
|
|
2733 |
}
|
|
|
2734 |
},
|
|
|
2735 |
|
|
|
2736 |
focusChild: function(/*Widget*/ widget, /*Node?*/ node){
|
|
|
2737 |
// summary: Focus widget. Optionally focus 'node' within widget.
|
|
|
2738 |
if(widget){
|
|
|
2739 |
if(this.focusedChild && widget !== this.focusedChild){
|
|
|
2740 |
this._onChildBlur(this.focusedChild);
|
|
|
2741 |
}
|
|
|
2742 |
this.focusedChild = widget;
|
|
|
2743 |
if(node && widget.focusFocalNode){
|
|
|
2744 |
widget.focusFocalNode(node);
|
|
|
2745 |
}else{
|
|
|
2746 |
widget.focus();
|
|
|
2747 |
}
|
|
|
2748 |
}
|
|
|
2749 |
},
|
|
|
2750 |
|
|
|
2751 |
_setTabIndexMinusOne: function(/*Widget*/ widget){
|
|
|
2752 |
if(widget.getFocalNodes){
|
|
|
2753 |
dojo.forEach(widget.getFocalNodes(), function(node){
|
|
|
2754 |
node.setAttribute("tabIndex", -1);
|
|
|
2755 |
});
|
|
|
2756 |
}else{
|
|
|
2757 |
(widget.focusNode || widget.domNode).setAttribute("tabIndex", -1);
|
|
|
2758 |
}
|
|
|
2759 |
},
|
|
|
2760 |
|
|
|
2761 |
_onContainerFocus: function(evt){
|
|
|
2762 |
this.domNode.setAttribute("tabIndex", -1);
|
|
|
2763 |
if(evt.target === this.domNode){
|
|
|
2764 |
this.focusFirstChild();
|
|
|
2765 |
}else{
|
|
|
2766 |
var widget = dijit.getEnclosingWidget(evt.target);
|
|
|
2767 |
if(widget && widget.isFocusable()){
|
|
|
2768 |
this.focusedChild = widget;
|
|
|
2769 |
}
|
|
|
2770 |
}
|
|
|
2771 |
},
|
|
|
2772 |
|
|
|
2773 |
_onContainerBlur: function(evt){
|
|
|
2774 |
if(this.tabIndex){
|
|
|
2775 |
this.domNode.setAttribute("tabIndex", this.tabIndex);
|
|
|
2776 |
}
|
|
|
2777 |
},
|
|
|
2778 |
|
|
|
2779 |
_onContainerKeypress: function(evt){
|
|
|
2780 |
if(evt.ctrlKey || evt.altKey){ return; }
|
|
|
2781 |
var func = this._keyNavCodes[evt.keyCode];
|
|
|
2782 |
if(func){
|
|
|
2783 |
func();
|
|
|
2784 |
dojo.stopEvent(evt);
|
|
|
2785 |
}
|
|
|
2786 |
},
|
|
|
2787 |
|
|
|
2788 |
_onChildBlur: function(/*Widget*/ widget){
|
|
|
2789 |
// summary:
|
|
|
2790 |
// Called when focus leaves a child widget to go
|
|
|
2791 |
// to a sibling widget.
|
|
|
2792 |
},
|
|
|
2793 |
|
|
|
2794 |
_getFirstFocusableChild: function(){
|
|
|
2795 |
return this._getNextFocusableChild(null, 1);
|
|
|
2796 |
},
|
|
|
2797 |
|
|
|
2798 |
_getNextFocusableChild: function(child, dir){
|
|
|
2799 |
if(child){
|
|
|
2800 |
child = this._getSiblingOfChild(child, dir);
|
|
|
2801 |
}
|
|
|
2802 |
var children = this.getChildren();
|
|
|
2803 |
for(var i=0; i < children.length; i++){
|
|
|
2804 |
if(!child){
|
|
|
2805 |
child = children[(dir>0) ? 0 : (children.length-1)];
|
|
|
2806 |
}
|
|
|
2807 |
if(child.isFocusable()){
|
|
|
2808 |
return child;
|
|
|
2809 |
}
|
|
|
2810 |
child = this._getSiblingOfChild(child, dir);
|
|
|
2811 |
}
|
|
|
2812 |
}
|
|
|
2813 |
}
|
|
|
2814 |
);
|
|
|
2815 |
|
|
|
2816 |
}
|
|
|
2817 |
|
|
|
2818 |
if(!dojo._hasResource["dijit.layout._LayoutWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
2819 |
dojo._hasResource["dijit.layout._LayoutWidget"] = true;
|
|
|
2820 |
dojo.provide("dijit.layout._LayoutWidget");
|
|
|
2821 |
|
|
|
2822 |
|
|
|
2823 |
|
|
|
2824 |
|
|
|
2825 |
dojo.declare("dijit.layout._LayoutWidget",
|
|
|
2826 |
[dijit._Widget, dijit._Container, dijit._Contained],
|
|
|
2827 |
{
|
|
|
2828 |
// summary
|
|
|
2829 |
// Mixin for widgets that contain a list of children like SplitContainer.
|
|
|
2830 |
// Widgets which mixin this code must define layout() to lay out the children
|
|
|
2831 |
|
|
|
2832 |
isLayoutContainer: true,
|
|
|
2833 |
|
|
|
2834 |
postCreate: function(){
|
|
|
2835 |
dojo.addClass(this.domNode, "dijitContainer");
|
|
|
2836 |
},
|
|
|
2837 |
|
|
|
2838 |
startup: function(){
|
|
|
2839 |
// summary:
|
|
|
2840 |
// Called after all the widgets have been instantiated and their
|
|
|
2841 |
// dom nodes have been inserted somewhere under document.body.
|
|
|
2842 |
//
|
|
|
2843 |
// Widgets should override this method to do any initialization
|
|
|
2844 |
// dependent on other widgets existing, and then call
|
|
|
2845 |
// this superclass method to finish things off.
|
|
|
2846 |
//
|
|
|
2847 |
// startup() in subclasses shouldn't do anything
|
|
|
2848 |
// size related because the size of the widget hasn't been set yet.
|
|
|
2849 |
|
|
|
2850 |
if(this._started){ return; }
|
|
|
2851 |
this._started=true;
|
|
|
2852 |
|
|
|
2853 |
if(this.getChildren){
|
|
|
2854 |
dojo.forEach(this.getChildren(), function(child){ child.startup(); });
|
|
|
2855 |
}
|
|
|
2856 |
|
|
|
2857 |
// If I am a top level widget
|
|
|
2858 |
if(!this.getParent || !this.getParent()){
|
|
|
2859 |
// Do recursive sizing and layout of all my descendants
|
|
|
2860 |
// (passing in no argument to resize means that it has to glean the size itself)
|
|
|
2861 |
this.resize();
|
|
|
2862 |
|
|
|
2863 |
// since my parent isn't a layout container, and my style is width=height=100% (or something similar),
|
|
|
2864 |
// then I need to watch when the window resizes, and size myself accordingly
|
|
|
2865 |
// (passing in no argument to resize means that it has to glean the size itself)
|
|
|
2866 |
this.connect(window, 'onresize', function(){this.resize();});
|
|
|
2867 |
}
|
|
|
2868 |
},
|
|
|
2869 |
|
|
|
2870 |
resize: function(args){
|
|
|
2871 |
// summary:
|
|
|
2872 |
// Explicitly set this widget's size (in pixels),
|
|
|
2873 |
// and then call layout() to resize contents (and maybe adjust child widgets)
|
|
|
2874 |
//
|
|
|
2875 |
// args: Object?
|
|
|
2876 |
// {w: int, h: int, l: int, t: int}
|
|
|
2877 |
|
|
|
2878 |
var node = this.domNode;
|
|
|
2879 |
|
|
|
2880 |
// set margin box size, unless it wasn't specified, in which case use current size
|
|
|
2881 |
if(args){
|
|
|
2882 |
dojo.marginBox(node, args);
|
|
|
2883 |
|
|
|
2884 |
// set offset of the node
|
|
|
2885 |
if(args.t){ node.style.top = args.t + "px"; }
|
|
|
2886 |
if(args.l){ node.style.left = args.l + "px"; }
|
|
|
2887 |
}
|
|
|
2888 |
// If either height or width wasn't specified by the user, then query node for it.
|
|
|
2889 |
// But note that setting the margin box and then immediately querying dimensions may return
|
|
|
2890 |
// inaccurate results, so try not to depend on it.
|
|
|
2891 |
var mb = dojo.mixin(dojo.marginBox(node), args||{});
|
|
|
2892 |
|
|
|
2893 |
// Save the size of my content box.
|
|
|
2894 |
this._contentBox = dijit.layout.marginBox2contentBox(node, mb);
|
|
|
2895 |
|
|
|
2896 |
// Callback for widget to adjust size of it's children
|
|
|
2897 |
this.layout();
|
|
|
2898 |
},
|
|
|
2899 |
|
|
|
2900 |
layout: function(){
|
|
|
2901 |
// summary
|
|
|
2902 |
// Widgets override this method to size & position their contents/children.
|
|
|
2903 |
// When this is called this._contentBox is guaranteed to be set (see resize()).
|
|
|
2904 |
//
|
|
|
2905 |
// This is called after startup(), and also when the widget's size has been
|
|
|
2906 |
// changed.
|
|
|
2907 |
}
|
|
|
2908 |
}
|
|
|
2909 |
);
|
|
|
2910 |
|
|
|
2911 |
dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
|
|
|
2912 |
// summary:
|
|
|
2913 |
// Given the margin-box size of a node, return it's content box size.
|
|
|
2914 |
// Functions like dojo.contentBox() but is more reliable since it doesn't have
|
|
|
2915 |
// to wait for the browser to compute sizes.
|
|
|
2916 |
var cs = dojo.getComputedStyle(node);
|
|
|
2917 |
var me=dojo._getMarginExtents(node, cs);
|
|
|
2918 |
var pb=dojo._getPadBorderExtents(node, cs);
|
|
|
2919 |
return {
|
|
|
2920 |
l: dojo._toPixelValue(node, cs.paddingLeft),
|
|
|
2921 |
t: dojo._toPixelValue(node, cs.paddingTop),
|
|
|
2922 |
w: mb.w - (me.w + pb.w),
|
|
|
2923 |
h: mb.h - (me.h + pb.h)
|
|
|
2924 |
};
|
|
|
2925 |
};
|
|
|
2926 |
|
|
|
2927 |
(function(){
|
|
|
2928 |
var capitalize = function(word){
|
|
|
2929 |
return word.substring(0,1).toUpperCase() + word.substring(1);
|
|
|
2930 |
};
|
|
|
2931 |
|
|
|
2932 |
var size = function(widget, dim){
|
|
|
2933 |
// size the child
|
|
|
2934 |
widget.resize ? widget.resize(dim) : dojo.marginBox(widget.domNode, dim);
|
|
|
2935 |
|
|
|
2936 |
// record child's size, but favor our own numbers when we have them.
|
|
|
2937 |
// the browser lies sometimes
|
|
|
2938 |
dojo.mixin(widget, dojo.marginBox(widget.domNode));
|
|
|
2939 |
dojo.mixin(widget, dim);
|
|
|
2940 |
};
|
|
|
2941 |
|
|
|
2942 |
dijit.layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Object[]*/ children){
|
|
|
2943 |
/**
|
|
|
2944 |
* summary
|
|
|
2945 |
* Layout a bunch of child dom nodes within a parent dom node
|
|
|
2946 |
* container:
|
|
|
2947 |
* parent node
|
|
|
2948 |
* dim:
|
|
|
2949 |
* {l, t, w, h} object specifying dimensions of container into which to place children
|
|
|
2950 |
* children:
|
|
|
2951 |
* an array like [ {domNode: foo, layoutAlign: "bottom" }, {domNode: bar, layoutAlign: "client"} ]
|
|
|
2952 |
*/
|
|
|
2953 |
|
|
|
2954 |
// copy dim because we are going to modify it
|
|
|
2955 |
dim = dojo.mixin({}, dim);
|
|
|
2956 |
|
|
|
2957 |
dojo.addClass(container, "dijitLayoutContainer");
|
|
|
2958 |
|
|
|
2959 |
// Move "client" elements to the end of the array for layout. a11y dictates that the author
|
|
|
2960 |
// needs to be able to put them in the document in tab-order, but this algorithm requires that
|
|
|
2961 |
// client be last.
|
|
|
2962 |
children = dojo.filter(children, function(item){ return item.layoutAlign != "client"; })
|
|
|
2963 |
.concat(dojo.filter(children, function(item){ return item.layoutAlign == "client"; }));
|
|
|
2964 |
|
|
|
2965 |
// set positions/sizes
|
|
|
2966 |
dojo.forEach(children, function(child){
|
|
|
2967 |
var elm = child.domNode,
|
|
|
2968 |
pos = child.layoutAlign;
|
|
|
2969 |
|
|
|
2970 |
// set elem to upper left corner of unused space; may move it later
|
|
|
2971 |
var elmStyle = elm.style;
|
|
|
2972 |
elmStyle.left = dim.l+"px";
|
|
|
2973 |
elmStyle.top = dim.t+"px";
|
|
|
2974 |
elmStyle.bottom = elmStyle.right = "auto";
|
|
|
2975 |
|
|
|
2976 |
dojo.addClass(elm, "dijitAlign" + capitalize(pos));
|
|
|
2977 |
|
|
|
2978 |
// set size && adjust record of remaining space.
|
|
|
2979 |
// note that setting the width of a <div> may affect it's height.
|
|
|
2980 |
if(pos=="top" || pos=="bottom"){
|
|
|
2981 |
size(child, { w: dim.w });
|
|
|
2982 |
dim.h -= child.h;
|
|
|
2983 |
if(pos=="top"){
|
|
|
2984 |
dim.t += child.h;
|
|
|
2985 |
}else{
|
|
|
2986 |
elmStyle.top = dim.t + dim.h + "px";
|
|
|
2987 |
}
|
|
|
2988 |
}else if(pos=="left" || pos=="right"){
|
|
|
2989 |
size(child, { h: dim.h });
|
|
|
2990 |
dim.w -= child.w;
|
|
|
2991 |
if(pos=="left"){
|
|
|
2992 |
dim.l += child.w;
|
|
|
2993 |
}else{
|
|
|
2994 |
elmStyle.left = dim.l + dim.w + "px";
|
|
|
2995 |
}
|
|
|
2996 |
}else if(pos=="client"){
|
|
|
2997 |
size(child, dim);
|
|
|
2998 |
}
|
|
|
2999 |
});
|
|
|
3000 |
};
|
|
|
3001 |
|
|
|
3002 |
})();
|
|
|
3003 |
|
|
|
3004 |
}
|
|
|
3005 |
|
|
|
3006 |
if(!dojo._hasResource["dijit.form._FormWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
3007 |
dojo._hasResource["dijit.form._FormWidget"] = true;
|
|
|
3008 |
dojo.provide("dijit.form._FormWidget");
|
|
|
3009 |
|
|
|
3010 |
|
|
|
3011 |
|
|
|
3012 |
|
|
|
3013 |
dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated],
|
|
|
3014 |
{
|
|
|
3015 |
/*
|
|
|
3016 |
Summary:
|
|
|
3017 |
FormElement widgets correspond to native HTML elements such as <input> or <button> or <select>.
|
|
|
3018 |
Each FormElement represents a single input value, and has a (possibly hidden) <input> element,
|
|
|
3019 |
to which it serializes its input value, so that form submission (either normal submission or via FormBind?)
|
|
|
3020 |
works as expected.
|
|
|
3021 |
|
|
|
3022 |
All these widgets should have these attributes just like native HTML input elements.
|
|
|
3023 |
You can set them during widget construction, but after that they are read only.
|
|
|
3024 |
|
|
|
3025 |
They also share some common methods.
|
|
|
3026 |
*/
|
|
|
3027 |
|
|
|
3028 |
// baseClass: String
|
|
|
3029 |
// Root CSS class of the widget (ex: dijitTextBox), used to add CSS classes of widget
|
|
|
3030 |
// (ex: "dijitTextBox dijitTextBoxInvalid dijitTextBoxFocused dijitTextBoxInvalidFocused")
|
|
|
3031 |
// See _setStateClass().
|
|
|
3032 |
baseClass: "",
|
|
|
3033 |
|
|
|
3034 |
// value: String
|
|
|
3035 |
// Corresponds to the native HTML <input> element's attribute.
|
|
|
3036 |
value: "",
|
|
|
3037 |
|
|
|
3038 |
// name: String
|
|
|
3039 |
// Name used when submitting form; same as "name" attribute or plain HTML elements
|
|
|
3040 |
name: "",
|
|
|
3041 |
|
|
|
3042 |
// id: String
|
|
|
3043 |
// Corresponds to the native HTML <input> element's attribute.
|
|
|
3044 |
// Also becomes the id for the widget.
|
|
|
3045 |
id: "",
|
|
|
3046 |
|
|
|
3047 |
// alt: String
|
|
|
3048 |
// Corresponds to the native HTML <input> element's attribute.
|
|
|
3049 |
alt: "",
|
|
|
3050 |
|
|
|
3051 |
// type: String
|
|
|
3052 |
// Corresponds to the native HTML <input> element's attribute.
|
|
|
3053 |
type: "text",
|
|
|
3054 |
|
|
|
3055 |
// tabIndex: Integer
|
|
|
3056 |
// Order fields are traversed when user hits the tab key
|
|
|
3057 |
tabIndex: "0",
|
|
|
3058 |
|
|
|
3059 |
// disabled: Boolean
|
|
|
3060 |
// Should this widget respond to user input?
|
|
|
3061 |
// In markup, this is specified as "disabled='disabled'", or just "disabled".
|
|
|
3062 |
disabled: false,
|
|
|
3063 |
|
|
|
3064 |
// intermediateChanges: Boolean
|
|
|
3065 |
// Fires onChange for each value change or only on demand
|
|
|
3066 |
intermediateChanges: false,
|
|
|
3067 |
|
|
|
3068 |
// These mixins assume that the focus node is an INPUT, as many but not all _FormWidgets are.
|
|
|
3069 |
// Don't attempt to mixin the 'type', 'name' attributes here programatically -- they must be declared
|
|
|
3070 |
// directly in the template as read by the parser in order to function. IE is known to specifically
|
|
|
3071 |
// require the 'name' attribute at element creation time.
|
|
|
3072 |
attributeMap: dojo.mixin(dojo.clone(dijit._Widget.prototype.attributeMap),
|
|
|
3073 |
{id:"focusNode", tabIndex:"focusNode", alt:"focusNode"}),
|
|
|
3074 |
|
|
|
3075 |
setDisabled: function(/*Boolean*/ disabled){
|
|
|
3076 |
// summary:
|
|
|
3077 |
// Set disabled state of widget.
|
|
|
3078 |
|
|
|
3079 |
this.domNode.disabled = this.disabled = disabled;
|
|
|
3080 |
if(this.focusNode){
|
|
|
3081 |
this.focusNode.disabled = disabled;
|
|
|
3082 |
}
|
|
|
3083 |
if(disabled){
|
|
|
3084 |
//reset those, because after the domNode is disabled, we can no longer receive
|
|
|
3085 |
//mouse related events, see #4200
|
|
|
3086 |
this._hovering = false;
|
|
|
3087 |
this._active = false;
|
|
|
3088 |
}
|
|
|
3089 |
dijit.setWaiState(this.focusNode || this.domNode, "disabled", disabled);
|
|
|
3090 |
this._setStateClass();
|
|
|
3091 |
},
|
|
|
3092 |
|
|
|
3093 |
|
|
|
3094 |
_onMouse : function(/*Event*/ event){
|
|
|
3095 |
// summary:
|
|
|
3096 |
// Sets _hovering, _active, and stateModifier properties depending on mouse state,
|
|
|
3097 |
// then calls setStateClass() to set appropriate CSS classes for this.domNode.
|
|
|
3098 |
//
|
|
|
3099 |
// To get a different CSS class for hover, send onmouseover and onmouseout events to this method.
|
|
|
3100 |
// To get a different CSS class while mouse button is depressed, send onmousedown to this method.
|
|
|
3101 |
|
|
|
3102 |
var mouseNode = event.target;
|
|
|
3103 |
if(mouseNode && mouseNode.getAttribute){
|
|
|
3104 |
this.stateModifier = mouseNode.getAttribute("stateModifier") || "";
|
|
|
3105 |
}
|
|
|
3106 |
|
|
|
3107 |
if(!this.disabled){
|
|
|
3108 |
switch(event.type){
|
|
|
3109 |
case "mouseenter" :
|
|
|
3110 |
case "mouseover" :
|
|
|
3111 |
this._hovering = true;
|
|
|
3112 |
break;
|
|
|
3113 |
|
|
|
3114 |
case "mouseout" :
|
|
|
3115 |
case "mouseleave" :
|
|
|
3116 |
this._hovering = false;
|
|
|
3117 |
break;
|
|
|
3118 |
|
|
|
3119 |
case "mousedown" :
|
|
|
3120 |
this._active = true;
|
|
|
3121 |
// set a global event to handle mouseup, so it fires properly
|
|
|
3122 |
// even if the cursor leaves the button
|
|
|
3123 |
var self = this;
|
|
|
3124 |
// #2685: use this.connect and disconnect so destroy works properly
|
|
|
3125 |
var mouseUpConnector = this.connect(dojo.body(), "onmouseup", function(){
|
|
|
3126 |
self._active = false;
|
|
|
3127 |
self._setStateClass();
|
|
|
3128 |
self.disconnect(mouseUpConnector);
|
|
|
3129 |
});
|
|
|
3130 |
break;
|
|
|
3131 |
}
|
|
|
3132 |
this._setStateClass();
|
|
|
3133 |
}
|
|
|
3134 |
},
|
|
|
3135 |
|
|
|
3136 |
isFocusable: function(){
|
|
|
3137 |
return !this.disabled && (dojo.style(this.domNode, "display") != "none");
|
|
|
3138 |
},
|
|
|
3139 |
|
|
|
3140 |
focus: function(){
|
|
|
3141 |
dijit.focus(this.focusNode);
|
|
|
3142 |
},
|
|
|
3143 |
|
|
|
3144 |
_setStateClass: function(){
|
|
|
3145 |
// summary
|
|
|
3146 |
// Update the visual state of the widget by setting the css classes on this.domNode
|
|
|
3147 |
// (or this.stateNode if defined) by combining this.baseClass with
|
|
|
3148 |
// various suffixes that represent the current widget state(s).
|
|
|
3149 |
//
|
|
|
3150 |
// In the case where a widget has multiple
|
|
|
3151 |
// states, it sets the class based on all possible
|
|
|
3152 |
// combinations. For example, an invalid form widget that is being hovered
|
|
|
3153 |
// will be "dijitInput dijitInputInvalid dijitInputHover dijitInputInvalidHover".
|
|
|
3154 |
//
|
|
|
3155 |
// For complex widgets with multiple regions, there can be various hover/active states,
|
|
|
3156 |
// such as "Hover" or "CloseButtonHover" (for tab buttons).
|
|
|
3157 |
// This is controlled by a stateModifier="CloseButton" attribute on the close button node.
|
|
|
3158 |
//
|
|
|
3159 |
// The widget may have one or more of the following states, determined
|
|
|
3160 |
// by this.state, this.checked, this.valid, and this.selected:
|
|
|
3161 |
// Error - ValidationTextBox sets this.state to "Error" if the current input value is invalid
|
|
|
3162 |
// Checked - ex: a checkmark or a ToggleButton in a checked state, will have this.checked==true
|
|
|
3163 |
// Selected - ex: currently selected tab will have this.selected==true
|
|
|
3164 |
//
|
|
|
3165 |
// In addition, it may have at most one of the following states,
|
|
|
3166 |
// based on this.disabled and flags set in _onMouse (this._active, this._hovering, this._focused):
|
|
|
3167 |
// Disabled - if the widget is disabled
|
|
|
3168 |
// Active - if the mouse (or space/enter key?) is being pressed down
|
|
|
3169 |
// Focused - if the widget has focus
|
|
|
3170 |
// Hover - if the mouse is over the widget
|
|
|
3171 |
//
|
|
|
3172 |
// (even if multiple af the above conditions are true we only pick the first matching one)
|
|
|
3173 |
|
|
|
3174 |
|
|
|
3175 |
// Get original (non state related, non baseClass related) class specified in template
|
|
|
3176 |
if(!("staticClass" in this)){
|
|
|
3177 |
this.staticClass = (this.stateNode||this.domNode).className;
|
|
|
3178 |
}
|
|
|
3179 |
|
|
|
3180 |
// Compute new set of classes
|
|
|
3181 |
var classes = [ this.baseClass ];
|
|
|
3182 |
|
|
|
3183 |
function multiply(modifier){
|
|
|
3184 |
classes=classes.concat(dojo.map(classes, function(c){ return c+modifier; }));
|
|
|
3185 |
}
|
|
|
3186 |
|
|
|
3187 |
if(this.checked){
|
|
|
3188 |
multiply("Checked");
|
|
|
3189 |
}
|
|
|
3190 |
if(this.state){
|
|
|
3191 |
multiply(this.state);
|
|
|
3192 |
}
|
|
|
3193 |
if(this.selected){
|
|
|
3194 |
multiply("Selected");
|
|
|
3195 |
}
|
|
|
3196 |
|
|
|
3197 |
// Only one of these four can be applied.
|
|
|
3198 |
// Active trumps Focused, Focused trumps Hover, and Disabled trumps all.
|
|
|
3199 |
if(this.disabled){
|
|
|
3200 |
multiply("Disabled");
|
|
|
3201 |
}else if(this._active){
|
|
|
3202 |
multiply(this.stateModifier+"Active");
|
|
|
3203 |
}else{
|
|
|
3204 |
if(this._focused){
|
|
|
3205 |
multiply("Focused");
|
|
|
3206 |
}
|
|
|
3207 |
if((this.stateModifier || !this._focused) && this._hovering){
|
|
|
3208 |
multiply(this.stateModifier+"Hover");
|
|
|
3209 |
}
|
|
|
3210 |
}
|
|
|
3211 |
(this.stateNode || this.domNode).className = this.staticClass + " " + classes.join(" ");
|
|
|
3212 |
},
|
|
|
3213 |
|
|
|
3214 |
onChange: function(newValue){
|
|
|
3215 |
// summary: callback when value is changed
|
|
|
3216 |
},
|
|
|
3217 |
|
|
|
3218 |
postCreate: function(){
|
|
|
3219 |
this.setValue(this.value, null); // null reserved for initial value
|
|
|
3220 |
this.setDisabled(this.disabled);
|
|
|
3221 |
this._setStateClass();
|
|
|
3222 |
},
|
|
|
3223 |
|
|
|
3224 |
setValue: function(/*anything*/ newValue, /*Boolean, optional*/ priorityChange){
|
|
|
3225 |
// summary: set the value of the widget.
|
|
|
3226 |
this._lastValue = newValue;
|
|
|
3227 |
dijit.setWaiState(this.focusNode || this.domNode, "valuenow", this.forWaiValuenow());
|
|
|
3228 |
if(priorityChange === undefined){ priorityChange = true; } // setValue with value only should fire onChange
|
|
|
3229 |
if(this._lastValueReported == undefined && priorityChange === null){ // don't report the initial value
|
|
|
3230 |
this._lastValueReported = newValue;
|
|
|
3231 |
}
|
|
|
3232 |
if((this.intermediateChanges || priorityChange) &&
|
|
|
3233 |
((newValue && newValue.toString)?newValue.toString():newValue) !== ((this._lastValueReported && this._lastValueReported.toString)?this._lastValueReported.toString():this._lastValueReported)){
|
|
|
3234 |
this._lastValueReported = newValue;
|
|
|
3235 |
this.onChange(newValue);
|
|
|
3236 |
}
|
|
|
3237 |
},
|
|
|
3238 |
|
|
|
3239 |
getValue: function(){
|
|
|
3240 |
// summary: get the value of the widget.
|
|
|
3241 |
return this._lastValue;
|
|
|
3242 |
},
|
|
|
3243 |
|
|
|
3244 |
undo: function(){
|
|
|
3245 |
// summary: restore the value to the last value passed to onChange
|
|
|
3246 |
this.setValue(this._lastValueReported, false);
|
|
|
3247 |
},
|
|
|
3248 |
|
|
|
3249 |
_onKeyPress: function(e){
|
|
|
3250 |
if(e.keyCode == dojo.keys.ESCAPE && !e.shiftKey && !e.ctrlKey && !e.altKey){
|
|
|
3251 |
var v = this.getValue();
|
|
|
3252 |
var lv = this._lastValueReported;
|
|
|
3253 |
// Equality comparison of objects such as dates are done by reference so
|
|
|
3254 |
// two distinct objects are != even if they have the same data. So use
|
|
|
3255 |
// toStrings in case the values are objects.
|
|
|
3256 |
if((typeof lv != "undefined") && ((v!==null && v.toString)?v.toString():null) !== lv.toString()){
|
|
|
3257 |
this.undo();
|
|
|
3258 |
dojo.stopEvent(e);
|
|
|
3259 |
return false;
|
|
|
3260 |
}
|
|
|
3261 |
}
|
|
|
3262 |
return true;
|
|
|
3263 |
},
|
|
|
3264 |
|
|
|
3265 |
forWaiValuenow: function(){
|
|
|
3266 |
// summary: returns a value, reflecting the current state of the widget,
|
|
|
3267 |
// to be used for the ARIA valuenow.
|
|
|
3268 |
// This method may be overridden by subclasses that want
|
|
|
3269 |
// to use something other than this.getValue() for valuenow
|
|
|
3270 |
return this.getValue();
|
|
|
3271 |
}
|
|
|
3272 |
});
|
|
|
3273 |
|
|
|
3274 |
}
|
|
|
3275 |
|
|
|
3276 |
if(!dojo._hasResource["dijit.dijit"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
3277 |
dojo._hasResource["dijit.dijit"] = true;
|
|
|
3278 |
dojo.provide("dijit.dijit");
|
|
|
3279 |
|
|
|
3280 |
// All the stuff in _base (these are the function that are guaranteed available without an explicit dojo.require)
|
|
|
3281 |
|
|
|
3282 |
|
|
|
3283 |
// And some other stuff that we tend to pull in all the time anyway
|
|
|
3284 |
|
|
|
3285 |
|
|
|
3286 |
|
|
|
3287 |
|
|
|
3288 |
|
|
|
3289 |
|
|
|
3290 |
|
|
|
3291 |
}
|
|
|
3292 |
|