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(typeof dojo == "undefined"){
|
|
|
21 |
|
|
|
22 |
// TODOC: HOW TO DOC THE BELOW?
|
|
|
23 |
// @global: djConfig
|
|
|
24 |
// summary:
|
|
|
25 |
// Application code can set the global 'djConfig' prior to loading
|
|
|
26 |
// the library to override certain global settings for how dojo works.
|
|
|
27 |
// description: The variables that can be set are as follows:
|
|
|
28 |
// - isDebug: false
|
|
|
29 |
// - libraryScriptUri: ""
|
|
|
30 |
// - locale: undefined
|
|
|
31 |
// - extraLocale: undefined
|
|
|
32 |
// - preventBackButtonFix: true
|
|
|
33 |
// note:
|
|
|
34 |
// 'djConfig' does not exist under 'dojo.*' so that it can be set before the
|
|
|
35 |
// 'dojo' variable exists.
|
|
|
36 |
// note:
|
|
|
37 |
// Setting any of these variables *after* the library has loaded does
|
|
|
38 |
// nothing at all.
|
|
|
39 |
|
|
|
40 |
(function(){
|
|
|
41 |
// make sure djConfig is defined
|
|
|
42 |
if(typeof this["djConfig"] == "undefined"){
|
|
|
43 |
this.djConfig = {};
|
|
|
44 |
}
|
|
|
45 |
|
|
|
46 |
// firebug stubs
|
|
|
47 |
if((!this["console"])||(!console["firebug"])){
|
|
|
48 |
this.console = {};
|
|
|
49 |
}
|
|
|
50 |
|
|
|
51 |
var cn = [
|
|
|
52 |
"assert", "count", "debug", "dir", "dirxml", "error", "group",
|
|
|
53 |
"groupEnd", "info", "log", "profile", "profileEnd", "time",
|
|
|
54 |
"timeEnd", "trace", "warn"
|
|
|
55 |
];
|
|
|
56 |
var i=0, tn;
|
|
|
57 |
while((tn=cn[i++])){
|
|
|
58 |
if(!console[tn]){
|
|
|
59 |
console[tn] = function(){};
|
|
|
60 |
}
|
|
|
61 |
}
|
|
|
62 |
|
|
|
63 |
//TODOC: HOW TO DOC THIS?
|
|
|
64 |
// dojo is the root variable of (almost all) our public symbols -- make sure it is defined.
|
|
|
65 |
if(typeof this["dojo"] == "undefined"){
|
|
|
66 |
this.dojo = {};
|
|
|
67 |
}
|
|
|
68 |
|
|
|
69 |
var d = dojo;
|
|
|
70 |
|
|
|
71 |
// summary:
|
|
|
72 |
// return the current global context object
|
|
|
73 |
// (e.g., the window object in a browser).
|
|
|
74 |
// description:
|
|
|
75 |
// Refer to 'dojo.global' rather than referring to window to ensure your
|
|
|
76 |
// code runs correctly in contexts other than web browsers (eg: Rhino on a server).
|
|
|
77 |
dojo.global = this;
|
|
|
78 |
|
|
|
79 |
var _config =/*===== djConfig = =====*/{
|
|
|
80 |
isDebug: false,
|
|
|
81 |
libraryScriptUri: "",
|
|
|
82 |
preventBackButtonFix: true,
|
|
|
83 |
delayMozLoadingFix: false
|
|
|
84 |
};
|
|
|
85 |
|
|
|
86 |
for(var option in _config){
|
|
|
87 |
if(typeof djConfig[option] == "undefined"){
|
|
|
88 |
djConfig[option] = _config[option];
|
|
|
89 |
}
|
|
|
90 |
}
|
|
|
91 |
|
|
|
92 |
var _platforms = ["Browser", "Rhino", "Spidermonkey", "Mobile"];
|
|
|
93 |
var t;
|
|
|
94 |
while(t=_platforms.shift()){
|
|
|
95 |
d["is"+t] = false;
|
|
|
96 |
}
|
|
|
97 |
|
|
|
98 |
// Override locale setting, if specified
|
|
|
99 |
dojo.locale = djConfig.locale;
|
|
|
100 |
|
|
|
101 |
//TODOC: HOW TO DOC THIS?
|
|
|
102 |
dojo.version = {
|
|
|
103 |
// summary: version number of this instance of dojo.
|
|
|
104 |
major: 1, minor: 0, patch: 2, flag: "",
|
|
|
105 |
revision: Number("$Rev: 11832 $".match(/[0-9]+/)[0]),
|
|
|
106 |
toString: function(){
|
|
|
107 |
with(d.version){
|
|
|
108 |
return major + "." + minor + "." + patch + flag + " (" + revision + ")"; // String
|
|
|
109 |
}
|
|
|
110 |
}
|
|
|
111 |
}
|
|
|
112 |
|
|
|
113 |
// Register with the OpenAjax hub
|
|
|
114 |
if(typeof OpenAjax != "undefined"){
|
|
|
115 |
OpenAjax.hub.registerLibrary("dojo", "http://dojotoolkit.org", d.version.toString());
|
|
|
116 |
}
|
|
|
117 |
|
|
|
118 |
dojo._mixin = function(/*Object*/ obj, /*Object*/ props){
|
|
|
119 |
// summary:
|
|
|
120 |
// Adds all properties and methods of props to obj. This addition is
|
|
|
121 |
// "prototype extension safe", so that instances of objects will not
|
|
|
122 |
// pass along prototype defaults.
|
|
|
123 |
var tobj = {};
|
|
|
124 |
for(var x in props){
|
|
|
125 |
// the "tobj" condition avoid copying properties in "props"
|
|
|
126 |
// inherited from Object.prototype. For example, if obj has a custom
|
|
|
127 |
// toString() method, don't overwrite it with the toString() method
|
|
|
128 |
// that props inherited from Object.prototype
|
|
|
129 |
if(tobj[x] === undefined || tobj[x] != props[x]){
|
|
|
130 |
obj[x] = props[x];
|
|
|
131 |
}
|
|
|
132 |
}
|
|
|
133 |
// IE doesn't recognize custom toStrings in for..in
|
|
|
134 |
if(d["isIE"] && props){
|
|
|
135 |
var p = props.toString;
|
|
|
136 |
if(typeof p == "function" && p != obj.toString && p != tobj.toString &&
|
|
|
137 |
p != "\nfunction toString() {\n [native code]\n}\n"){
|
|
|
138 |
obj.toString = props.toString;
|
|
|
139 |
}
|
|
|
140 |
}
|
|
|
141 |
return obj; // Object
|
|
|
142 |
}
|
|
|
143 |
|
|
|
144 |
dojo.mixin = function(/*Object*/obj, /*Object...*/props){
|
|
|
145 |
// summary: Adds all properties and methods of props to obj.
|
|
|
146 |
for(var i=1, l=arguments.length; i<l; i++){
|
|
|
147 |
d._mixin(obj, arguments[i]);
|
|
|
148 |
}
|
|
|
149 |
return obj; // Object
|
|
|
150 |
}
|
|
|
151 |
|
|
|
152 |
dojo._getProp = function(/*Array*/parts, /*Boolean*/create, /*Object*/context){
|
|
|
153 |
var obj=context||d.global;
|
|
|
154 |
for(var i=0, p; obj&&(p=parts[i]); i++){
|
|
|
155 |
obj = (p in obj ? obj[p] : (create ? obj[p]={} : undefined));
|
|
|
156 |
}
|
|
|
157 |
return obj; // mixed
|
|
|
158 |
}
|
|
|
159 |
|
|
|
160 |
dojo.setObject = function(/*String*/name, /*mixed*/value, /*Object*/context){
|
|
|
161 |
// summary:
|
|
|
162 |
// Set a property from a dot-separated string, such as "A.B.C"
|
|
|
163 |
// description:
|
|
|
164 |
// Useful for longer api chains where you have to test each object in
|
|
|
165 |
// the chain, or when you have an object reference in string format.
|
|
|
166 |
// Objects are created as needed along 'path'.
|
|
|
167 |
// name:
|
|
|
168 |
// Path to a property, in the form "A.B.C".
|
|
|
169 |
// context:
|
|
|
170 |
// Optional. Object to use as root of path. Defaults to
|
|
|
171 |
// 'dojo.global'. Null may be passed.
|
|
|
172 |
var parts=name.split("."), p=parts.pop(), obj=d._getProp(parts, true, context);
|
|
|
173 |
return (obj && p ? (obj[p]=value) : undefined); // mixed
|
|
|
174 |
}
|
|
|
175 |
|
|
|
176 |
dojo.getObject = function(/*String*/name, /*Boolean*/create, /*Object*/context){
|
|
|
177 |
// summary:
|
|
|
178 |
// Get a property from a dot-separated string, such as "A.B.C"
|
|
|
179 |
// description:
|
|
|
180 |
// Useful for longer api chains where you have to test each object in
|
|
|
181 |
// the chain, or when you have an object reference in string format.
|
|
|
182 |
// name:
|
|
|
183 |
// Path to an property, in the form "A.B.C".
|
|
|
184 |
// context:
|
|
|
185 |
// Optional. Object to use as root of path. Defaults to
|
|
|
186 |
// 'dojo.global'. Null may be passed.
|
|
|
187 |
// create:
|
|
|
188 |
// Optional. If true, Objects will be created at any point along the
|
|
|
189 |
// 'path' that is undefined.
|
|
|
190 |
return d._getProp(name.split("."), create, context); // mixed
|
|
|
191 |
}
|
|
|
192 |
|
|
|
193 |
dojo.exists = function(/*String*/name, /*Object?*/obj){
|
|
|
194 |
// summary:
|
|
|
195 |
// determine if an object supports a given method
|
|
|
196 |
// description:
|
|
|
197 |
// useful for longer api chains where you have to test each object in
|
|
|
198 |
// the chain
|
|
|
199 |
// name:
|
|
|
200 |
// Path to an object, in the form "A.B.C".
|
|
|
201 |
// obj:
|
|
|
202 |
// Object to use as root of path. Defaults to
|
|
|
203 |
// 'dojo.global'. Null may be passed.
|
|
|
204 |
return !!d.getObject(name, false, obj); // Boolean
|
|
|
205 |
}
|
|
|
206 |
|
|
|
207 |
|
|
|
208 |
dojo["eval"] = function(/*String*/ scriptFragment){
|
|
|
209 |
// summary:
|
|
|
210 |
// Perform an evaluation in the global scope. Use this rather than
|
|
|
211 |
// calling 'eval()' directly.
|
|
|
212 |
// description:
|
|
|
213 |
// Placed in a separate function to minimize size of trapped
|
|
|
214 |
// evaluation context.
|
|
|
215 |
// note:
|
|
|
216 |
// - JSC eval() takes an optional second argument which can be 'unsafe'.
|
|
|
217 |
// - Mozilla/SpiderMonkey eval() takes an optional second argument which is the
|
|
|
218 |
// scope object for new symbols.
|
|
|
219 |
|
|
|
220 |
// FIXME: investigate Joseph Smarr's technique for IE:
|
|
|
221 |
// http://josephsmarr.com/2007/01/31/fixing-eval-to-use-global-scope-in-ie/
|
|
|
222 |
// see also:
|
|
|
223 |
// http://trac.dojotoolkit.org/ticket/744
|
|
|
224 |
return d.global.eval ? d.global.eval(scriptFragment) : eval(scriptFragment); // mixed
|
|
|
225 |
}
|
|
|
226 |
|
|
|
227 |
/*=====
|
|
|
228 |
dojo.deprecated = function(behaviour, extra, removal){
|
|
|
229 |
// summary:
|
|
|
230 |
// Log a debug message to indicate that a behavior has been
|
|
|
231 |
// deprecated.
|
|
|
232 |
// behaviour: String
|
|
|
233 |
// The API or behavior being deprecated. Usually in the form
|
|
|
234 |
// of "myApp.someFunction()".
|
|
|
235 |
// extra: String?
|
|
|
236 |
// Text to append to the message. Often provides advice on a
|
|
|
237 |
// new function or facility to achieve the same goal during
|
|
|
238 |
// the deprecation period.
|
|
|
239 |
// removal: String?
|
|
|
240 |
// Text to indicate when in the future the behavior will be
|
|
|
241 |
// removed. Usually a version number.
|
|
|
242 |
// example:
|
|
|
243 |
// | dojo.deprecated("myApp.getTemp()", "use myApp.getLocaleTemp() instead", "1.0");
|
|
|
244 |
}
|
|
|
245 |
|
|
|
246 |
dojo.experimental = function(moduleName, extra){
|
|
|
247 |
// summary: Marks code as experimental.
|
|
|
248 |
// description:
|
|
|
249 |
// This can be used to mark a function, file, or module as
|
|
|
250 |
// experimental. Experimental code is not ready to be used, and the
|
|
|
251 |
// APIs are subject to change without notice. Experimental code may be
|
|
|
252 |
// completed deleted without going through the normal deprecation
|
|
|
253 |
// process.
|
|
|
254 |
// moduleName: String
|
|
|
255 |
// The name of a module, or the name of a module file or a specific
|
|
|
256 |
// function
|
|
|
257 |
// extra: String?
|
|
|
258 |
// some additional message for the user
|
|
|
259 |
// example:
|
|
|
260 |
// | dojo.experimental("dojo.data.Result");
|
|
|
261 |
// example:
|
|
|
262 |
// | dojo.experimental("dojo.weather.toKelvin()", "PENDING approval from NOAA");
|
|
|
263 |
}
|
|
|
264 |
=====*/
|
|
|
265 |
|
|
|
266 |
//Real functions declared in dojo._firebug.firebug.
|
|
|
267 |
d.deprecated = d.experimental = function(){};
|
|
|
268 |
|
|
|
269 |
})();
|
|
|
270 |
// vim:ai:ts=4:noet
|
|
|
271 |
|
|
|
272 |
/*
|
|
|
273 |
* loader.js - A bootstrap module. Runs before the hostenv_*.js file. Contains
|
|
|
274 |
* all of the package loading methods.
|
|
|
275 |
*/
|
|
|
276 |
|
|
|
277 |
(function(){
|
|
|
278 |
var d = dojo;
|
|
|
279 |
|
|
|
280 |
dojo.mixin(dojo, {
|
|
|
281 |
_loadedModules: {},
|
|
|
282 |
_inFlightCount: 0,
|
|
|
283 |
_hasResource: {},
|
|
|
284 |
|
|
|
285 |
// FIXME: it should be possible to pull module prefixes in from djConfig
|
|
|
286 |
_modulePrefixes: {
|
|
|
287 |
dojo: {name: "dojo", value: "."},
|
|
|
288 |
doh: {name: "doh", value: "../util/doh"},
|
|
|
289 |
tests: {name: "tests", value: "tests"}
|
|
|
290 |
},
|
|
|
291 |
|
|
|
292 |
_moduleHasPrefix: function(/*String*/module){
|
|
|
293 |
// summary: checks to see if module has been established
|
|
|
294 |
var mp = this._modulePrefixes;
|
|
|
295 |
return !!(mp[module] && mp[module].value); // Boolean
|
|
|
296 |
},
|
|
|
297 |
|
|
|
298 |
_getModulePrefix: function(/*String*/module){
|
|
|
299 |
// summary: gets the prefix associated with module
|
|
|
300 |
var mp = this._modulePrefixes;
|
|
|
301 |
if(this._moduleHasPrefix(module)){
|
|
|
302 |
return mp[module].value; // String
|
|
|
303 |
}
|
|
|
304 |
return module; // String
|
|
|
305 |
},
|
|
|
306 |
|
|
|
307 |
_loadedUrls: [],
|
|
|
308 |
|
|
|
309 |
//WARNING:
|
|
|
310 |
// This variable is referenced by packages outside of bootstrap:
|
|
|
311 |
// FloatingPane.js and undo/browser.js
|
|
|
312 |
_postLoad: false,
|
|
|
313 |
|
|
|
314 |
//Egad! Lots of test files push on this directly instead of using dojo.addOnLoad.
|
|
|
315 |
_loaders: [],
|
|
|
316 |
_unloaders: [],
|
|
|
317 |
_loadNotifying: false
|
|
|
318 |
});
|
|
|
319 |
|
|
|
320 |
|
|
|
321 |
dojo._loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){
|
|
|
322 |
// summary:
|
|
|
323 |
// Load a Javascript module given a relative path
|
|
|
324 |
//
|
|
|
325 |
// description:
|
|
|
326 |
// Loads and interprets the script located at relpath, which is
|
|
|
327 |
// relative to the script root directory. If the script is found but
|
|
|
328 |
// its interpretation causes a runtime exception, that exception is
|
|
|
329 |
// not caught by us, so the caller will see it. We return a true
|
|
|
330 |
// value if and only if the script is found.
|
|
|
331 |
//
|
|
|
332 |
// relpath:
|
|
|
333 |
// A relative path to a script (no leading '/', and typically ending
|
|
|
334 |
// in '.js').
|
|
|
335 |
// module:
|
|
|
336 |
// A module whose existance to check for after loading a path. Can be
|
|
|
337 |
// used to determine success or failure of the load.
|
|
|
338 |
// cb:
|
|
|
339 |
// a callback function to pass the result of evaluating the script
|
|
|
340 |
|
|
|
341 |
var uri = (((relpath.charAt(0) == '/' || relpath.match(/^\w+:/))) ? "" : this.baseUrl) + relpath;
|
|
|
342 |
if(djConfig.cacheBust && d.isBrowser){
|
|
|
343 |
uri += "?" + String(djConfig.cacheBust).replace(/\W+/g,"");
|
|
|
344 |
}
|
|
|
345 |
try{
|
|
|
346 |
return !module ? this._loadUri(uri, cb) : this._loadUriAndCheck(uri, module, cb); // Boolean
|
|
|
347 |
}catch(e){
|
|
|
348 |
console.debug(e);
|
|
|
349 |
return false; // Boolean
|
|
|
350 |
}
|
|
|
351 |
}
|
|
|
352 |
|
|
|
353 |
dojo._loadUri = function(/*String (URL)*/uri, /*Function?*/cb){
|
|
|
354 |
// summary:
|
|
|
355 |
// Loads JavaScript from a URI
|
|
|
356 |
// description:
|
|
|
357 |
// Reads the contents of the URI, and evaluates the contents. This is
|
|
|
358 |
// used to load modules as well as resource bundles. Returns true if
|
|
|
359 |
// it succeeded. Returns false if the URI reading failed. Throws if
|
|
|
360 |
// the evaluation throws.
|
|
|
361 |
// uri: a uri which points at the script to be loaded
|
|
|
362 |
// cb:
|
|
|
363 |
// a callback function to process the result of evaluating the script
|
|
|
364 |
// as an expression, typically used by the resource bundle loader to
|
|
|
365 |
// load JSON-style resources
|
|
|
366 |
|
|
|
367 |
if(this._loadedUrls[uri]){
|
|
|
368 |
return true; // Boolean
|
|
|
369 |
}
|
|
|
370 |
var contents = this._getText(uri, true);
|
|
|
371 |
if(!contents){ return false; } // Boolean
|
|
|
372 |
this._loadedUrls[uri] = true;
|
|
|
373 |
this._loadedUrls.push(uri);
|
|
|
374 |
if(cb){ contents = '('+contents+')'; }
|
|
|
375 |
var value = d["eval"](contents+"\r\n//@ sourceURL="+uri);
|
|
|
376 |
if(cb){ cb(value); }
|
|
|
377 |
return true; // Boolean
|
|
|
378 |
}
|
|
|
379 |
|
|
|
380 |
// FIXME: probably need to add logging to this method
|
|
|
381 |
dojo._loadUriAndCheck = function(/*String (URL)*/uri, /*String*/moduleName, /*Function?*/cb){
|
|
|
382 |
// summary: calls loadUri then findModule and returns true if both succeed
|
|
|
383 |
var ok = false;
|
|
|
384 |
try{
|
|
|
385 |
ok = this._loadUri(uri, cb);
|
|
|
386 |
}catch(e){
|
|
|
387 |
console.debug("failed loading " + uri + " with error: " + e);
|
|
|
388 |
}
|
|
|
389 |
return Boolean(ok && this._loadedModules[moduleName]); // Boolean
|
|
|
390 |
}
|
|
|
391 |
|
|
|
392 |
dojo.loaded = function(){
|
|
|
393 |
// summary:
|
|
|
394 |
// signal fired when initial environment and package loading is
|
|
|
395 |
// complete. You may use dojo.addOnLoad() or dojo.connect() to
|
|
|
396 |
// this method in order to handle initialization tasks that
|
|
|
397 |
// require the environment to be initialized. In a browser host,
|
|
|
398 |
// declarative widgets will be constructed when this function
|
|
|
399 |
// finishes runing.
|
|
|
400 |
this._loadNotifying = true;
|
|
|
401 |
this._postLoad = true;
|
|
|
402 |
var mll = this._loaders;
|
|
|
403 |
|
|
|
404 |
//Clear listeners so new ones can be added
|
|
|
405 |
//For other xdomain package loads after the initial load.
|
|
|
406 |
this._loaders = [];
|
|
|
407 |
|
|
|
408 |
for(var x=0; x<mll.length; x++){
|
|
|
409 |
mll[x]();
|
|
|
410 |
}
|
|
|
411 |
|
|
|
412 |
this._loadNotifying = false;
|
|
|
413 |
|
|
|
414 |
//Make sure nothing else got added to the onload queue
|
|
|
415 |
//after this first run. If something did, and we are not waiting for any
|
|
|
416 |
//more inflight resources, run again.
|
|
|
417 |
if(d._postLoad && d._inFlightCount == 0 && this._loaders.length > 0){
|
|
|
418 |
d._callLoaded();
|
|
|
419 |
}
|
|
|
420 |
}
|
|
|
421 |
|
|
|
422 |
dojo.unloaded = function(){
|
|
|
423 |
// summary:
|
|
|
424 |
// signal fired by impending environment destruction. You may use
|
|
|
425 |
// dojo.addOnUnload() or dojo.connect() to this method to perform
|
|
|
426 |
// page/application cleanup methods.
|
|
|
427 |
var mll = this._unloaders;
|
|
|
428 |
while(mll.length){
|
|
|
429 |
(mll.pop())();
|
|
|
430 |
}
|
|
|
431 |
}
|
|
|
432 |
|
|
|
433 |
dojo.addOnLoad = function(/*Object?*/obj, /*String|Function*/functionName){
|
|
|
434 |
// summary:
|
|
|
435 |
// Registers a function to be triggered after the DOM has finished
|
|
|
436 |
// loading and widgets declared in markup have been instantiated.
|
|
|
437 |
// Images and CSS files may or may not have finished downloading when
|
|
|
438 |
// the specified function is called. (Note that widgets' CSS and HTML
|
|
|
439 |
// code is guaranteed to be downloaded before said widgets are
|
|
|
440 |
// instantiated.)
|
|
|
441 |
// example:
|
|
|
442 |
// | dojo.addOnLoad(functionPointer);
|
|
|
443 |
// | dojo.addOnLoad(object, "functionName");
|
|
|
444 |
if(arguments.length == 1){
|
|
|
445 |
d._loaders.push(obj);
|
|
|
446 |
}else if(arguments.length > 1){
|
|
|
447 |
d._loaders.push(function(){
|
|
|
448 |
obj[functionName]();
|
|
|
449 |
});
|
|
|
450 |
}
|
|
|
451 |
|
|
|
452 |
//Added for xdomain loading. dojo.addOnLoad is used to
|
|
|
453 |
//indicate callbacks after doing some dojo.require() statements.
|
|
|
454 |
//In the xdomain case, if all the requires are loaded (after initial
|
|
|
455 |
//page load), then immediately call any listeners.
|
|
|
456 |
if(d._postLoad && d._inFlightCount == 0 && !d._loadNotifying){
|
|
|
457 |
d._callLoaded();
|
|
|
458 |
}
|
|
|
459 |
}
|
|
|
460 |
|
|
|
461 |
dojo.addOnUnload = function(/*Object?*/obj, /*String|Function?*/functionName){
|
|
|
462 |
// summary: registers a function to be triggered when the page unloads
|
|
|
463 |
// example:
|
|
|
464 |
// | dojo.addOnUnload(functionPointer)
|
|
|
465 |
// | dojo.addOnUnload(object, "functionName")
|
|
|
466 |
if(arguments.length == 1){
|
|
|
467 |
d._unloaders.push(obj);
|
|
|
468 |
}else if(arguments.length > 1){
|
|
|
469 |
d._unloaders.push(function(){
|
|
|
470 |
obj[functionName]();
|
|
|
471 |
});
|
|
|
472 |
}
|
|
|
473 |
}
|
|
|
474 |
|
|
|
475 |
dojo._modulesLoaded = function(){
|
|
|
476 |
if(d._postLoad){ return; }
|
|
|
477 |
if(d._inFlightCount > 0){
|
|
|
478 |
console.debug("files still in flight!");
|
|
|
479 |
return;
|
|
|
480 |
}
|
|
|
481 |
d._callLoaded();
|
|
|
482 |
}
|
|
|
483 |
|
|
|
484 |
dojo._callLoaded = function(){
|
|
|
485 |
//The "object" check is for IE, and the other opera check fixes an issue
|
|
|
486 |
//in Opera where it could not find the body element in some widget test cases.
|
|
|
487 |
//For 0.9, maybe route all browsers through the setTimeout (need protection
|
|
|
488 |
//still for non-browser environments though). This might also help the issue with
|
|
|
489 |
//FF 2.0 and freezing issues where we try to do sync xhr while background css images
|
|
|
490 |
//are being loaded (trac #2572)? Consider for 0.9.
|
|
|
491 |
if(typeof setTimeout == "object" || (djConfig["useXDomain"] && d.isOpera)){
|
|
|
492 |
setTimeout("dojo.loaded();", 0);
|
|
|
493 |
}else{
|
|
|
494 |
d.loaded();
|
|
|
495 |
}
|
|
|
496 |
}
|
|
|
497 |
|
|
|
498 |
dojo._getModuleSymbols = function(/*String*/modulename){
|
|
|
499 |
// summary:
|
|
|
500 |
// Converts a module name in dotted JS notation to an array
|
|
|
501 |
// representing the path in the source tree
|
|
|
502 |
var syms = modulename.split(".");
|
|
|
503 |
for(var i = syms.length; i>0; i--){
|
|
|
504 |
var parentModule = syms.slice(0, i).join(".");
|
|
|
505 |
if((i==1) && !this._moduleHasPrefix(parentModule)){
|
|
|
506 |
// Support default module directory (sibling of dojo) for top-level modules
|
|
|
507 |
syms[0] = "../" + syms[0];
|
|
|
508 |
}else{
|
|
|
509 |
var parentModulePath = this._getModulePrefix(parentModule);
|
|
|
510 |
if(parentModulePath != parentModule){
|
|
|
511 |
syms.splice(0, i, parentModulePath);
|
|
|
512 |
break;
|
|
|
513 |
}
|
|
|
514 |
}
|
|
|
515 |
}
|
|
|
516 |
// console.debug(syms);
|
|
|
517 |
return syms; // Array
|
|
|
518 |
}
|
|
|
519 |
|
|
|
520 |
dojo._global_omit_module_check = false;
|
|
|
521 |
|
|
|
522 |
dojo._loadModule = dojo.require = function(/*String*/moduleName, /*Boolean?*/omitModuleCheck){
|
|
|
523 |
// summary:
|
|
|
524 |
// loads a Javascript module from the appropriate URI
|
|
|
525 |
// moduleName: String
|
|
|
526 |
// omitModuleCheck: Boolean?
|
|
|
527 |
// description:
|
|
|
528 |
// _loadModule("A.B") first checks to see if symbol A.B is defined. If
|
|
|
529 |
// it is, it is simply returned (nothing to do).
|
|
|
530 |
//
|
|
|
531 |
// If it is not defined, it will look for "A/B.js" in the script root
|
|
|
532 |
// directory.
|
|
|
533 |
//
|
|
|
534 |
// It throws if it cannot find a file to load, or if the symbol A.B is
|
|
|
535 |
// not defined after loading.
|
|
|
536 |
//
|
|
|
537 |
// It returns the object A.B.
|
|
|
538 |
//
|
|
|
539 |
// This does nothing about importing symbols into the current package.
|
|
|
540 |
// It is presumed that the caller will take care of that. For example,
|
|
|
541 |
// to import all symbols:
|
|
|
542 |
//
|
|
|
543 |
// | with (dojo._loadModule("A.B")) {
|
|
|
544 |
// | ...
|
|
|
545 |
// | }
|
|
|
546 |
//
|
|
|
547 |
// And to import just the leaf symbol:
|
|
|
548 |
//
|
|
|
549 |
// | var B = dojo._loadModule("A.B");
|
|
|
550 |
// | ...
|
|
|
551 |
// returns: the required namespace object
|
|
|
552 |
omitModuleCheck = this._global_omit_module_check || omitModuleCheck;
|
|
|
553 |
var module = this._loadedModules[moduleName];
|
|
|
554 |
if(module){
|
|
|
555 |
return module;
|
|
|
556 |
}
|
|
|
557 |
|
|
|
558 |
// convert periods to slashes
|
|
|
559 |
var relpath = this._getModuleSymbols(moduleName).join("/") + '.js';
|
|
|
560 |
|
|
|
561 |
var modArg = (!omitModuleCheck) ? moduleName : null;
|
|
|
562 |
var ok = this._loadPath(relpath, modArg);
|
|
|
563 |
|
|
|
564 |
if((!ok)&&(!omitModuleCheck)){
|
|
|
565 |
throw new Error("Could not load '" + moduleName + "'; last tried '" + relpath + "'");
|
|
|
566 |
}
|
|
|
567 |
|
|
|
568 |
// check that the symbol was defined
|
|
|
569 |
// Don't bother if we're doing xdomain (asynchronous) loading.
|
|
|
570 |
if((!omitModuleCheck)&&(!this["_isXDomain"])){
|
|
|
571 |
// pass in false so we can give better error
|
|
|
572 |
module = this._loadedModules[moduleName];
|
|
|
573 |
if(!module){
|
|
|
574 |
throw new Error("symbol '" + moduleName + "' is not defined after loading '" + relpath + "'");
|
|
|
575 |
}
|
|
|
576 |
}
|
|
|
577 |
|
|
|
578 |
return module;
|
|
|
579 |
}
|
|
|
580 |
|
|
|
581 |
dojo.provide = function(/*String*/ resourceName){
|
|
|
582 |
// summary:
|
|
|
583 |
// Each javascript source file must have (exactly) one dojo.provide()
|
|
|
584 |
// call at the top of the file, corresponding to the file name.
|
|
|
585 |
// For example, js/dojo/foo.js must have dojo.provide("dojo.foo"); at the
|
|
|
586 |
// top of the file.
|
|
|
587 |
// description:
|
|
|
588 |
// Each javascript source file is called a resource. When a resource
|
|
|
589 |
// is loaded by the browser, dojo.provide() registers that it has been
|
|
|
590 |
// loaded.
|
|
|
591 |
//
|
|
|
592 |
// For backwards compatibility reasons, in addition to registering the
|
|
|
593 |
// resource, dojo.provide() also ensures that the javascript object
|
|
|
594 |
// for the module exists. For example,
|
|
|
595 |
// dojo.provide("dojo.io.cometd"), in addition to registering that
|
|
|
596 |
// cometd.js is a resource for the dojo.iomodule, will ensure that
|
|
|
597 |
// the dojo.io javascript object exists, so that calls like
|
|
|
598 |
// dojo.io.foo = function(){ ... } don't fail.
|
|
|
599 |
//
|
|
|
600 |
// In the case of a build (or in the future, a rollup), where multiple
|
|
|
601 |
// javascript source files are combined into one bigger file (similar
|
|
|
602 |
// to a .lib or .jar file), that file will contain multiple
|
|
|
603 |
// dojo.provide() calls, to note that it includes multiple resources.
|
|
|
604 |
|
|
|
605 |
//Make sure we have a string.
|
|
|
606 |
resourceName = resourceName + "";
|
|
|
607 |
return (d._loadedModules[resourceName] = d.getObject(resourceName, true)); // Object
|
|
|
608 |
}
|
|
|
609 |
|
|
|
610 |
//Start of old bootstrap2:
|
|
|
611 |
|
|
|
612 |
dojo.platformRequire = function(/*Object containing Arrays*/modMap){
|
|
|
613 |
// description:
|
|
|
614 |
// This method taks a "map" of arrays which one can use to optionally
|
|
|
615 |
// load dojo modules. The map is indexed by the possible
|
|
|
616 |
// dojo.name_ values, with two additional values: "default"
|
|
|
617 |
// and "common". The items in the "default" array will be loaded if
|
|
|
618 |
// none of the other items have been choosen based on the
|
|
|
619 |
// hostenv.name_ item. The items in the "common" array will _always_
|
|
|
620 |
// be loaded, regardless of which list is chosen. Here's how it's
|
|
|
621 |
// normally called:
|
|
|
622 |
//
|
|
|
623 |
// | dojo.platformRequire({
|
|
|
624 |
// | // an example that passes multiple args to _loadModule()
|
|
|
625 |
// | browser: [
|
|
|
626 |
// | ["foo.bar.baz", true, true],
|
|
|
627 |
// | "foo.sample",
|
|
|
628 |
// | "foo.test,
|
|
|
629 |
// | ],
|
|
|
630 |
// | default: [ "foo.sample.*" ],
|
|
|
631 |
// | common: [ "really.important.module.*" ]
|
|
|
632 |
// | });
|
|
|
633 |
|
|
|
634 |
// FIXME: dojo.name_ no longer works!!
|
|
|
635 |
|
|
|
636 |
var common = modMap["common"]||[];
|
|
|
637 |
var result = common.concat(modMap[d._name]||modMap["default"]||[]);
|
|
|
638 |
|
|
|
639 |
for(var x=0; x<result.length; x++){
|
|
|
640 |
var curr = result[x];
|
|
|
641 |
if(curr.constructor == Array){
|
|
|
642 |
d._loadModule.apply(d, curr);
|
|
|
643 |
}else{
|
|
|
644 |
d._loadModule(curr);
|
|
|
645 |
}
|
|
|
646 |
}
|
|
|
647 |
}
|
|
|
648 |
|
|
|
649 |
|
|
|
650 |
dojo.requireIf = function(/*Boolean*/ condition, /*String*/ resourceName){
|
|
|
651 |
// summary:
|
|
|
652 |
// If the condition is true then call dojo.require() for the specified
|
|
|
653 |
// resource
|
|
|
654 |
if(condition === true){
|
|
|
655 |
// FIXME: why do we support chained require()'s here? does the build system?
|
|
|
656 |
var args = [];
|
|
|
657 |
for(var i = 1; i < arguments.length; i++){
|
|
|
658 |
args.push(arguments[i]);
|
|
|
659 |
}
|
|
|
660 |
d.require.apply(d, args);
|
|
|
661 |
}
|
|
|
662 |
}
|
|
|
663 |
|
|
|
664 |
dojo.requireAfterIf = d.requireIf;
|
|
|
665 |
|
|
|
666 |
dojo.registerModulePath = function(/*String*/module, /*String*/prefix){
|
|
|
667 |
// summary:
|
|
|
668 |
// maps a module name to a path
|
|
|
669 |
// description:
|
|
|
670 |
// An unregistered module is given the default path of ../<module>,
|
|
|
671 |
// relative to Dojo root. For example, module acme is mapped to
|
|
|
672 |
// ../acme. If you want to use a different module name, use
|
|
|
673 |
// dojo.registerModulePath.
|
|
|
674 |
d._modulePrefixes[module] = { name: module, value: prefix };
|
|
|
675 |
}
|
|
|
676 |
|
|
|
677 |
dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String?*/availableFlatLocales){
|
|
|
678 |
// summary:
|
|
|
679 |
// Declares translated resources and loads them if necessary, in the
|
|
|
680 |
// same style as dojo.require. Contents of the resource bundle are
|
|
|
681 |
// typically strings, but may be any name/value pair, represented in
|
|
|
682 |
// JSON format. See also dojo.i18n.getLocalization.
|
|
|
683 |
// moduleName:
|
|
|
684 |
// name of the package containing the "nls" directory in which the
|
|
|
685 |
// bundle is found
|
|
|
686 |
// bundleName:
|
|
|
687 |
// bundle name, i.e. the filename without the '.js' suffix
|
|
|
688 |
// locale:
|
|
|
689 |
// the locale to load (optional) By default, the browser's user
|
|
|
690 |
// locale as defined by dojo.locale
|
|
|
691 |
// availableFlatLocales:
|
|
|
692 |
// A comma-separated list of the available, flattened locales for this
|
|
|
693 |
// bundle. This argument should only be set by the build process.
|
|
|
694 |
// description:
|
|
|
695 |
// Load translated resource bundles provided underneath the "nls"
|
|
|
696 |
// directory within a package. Translated resources may be located in
|
|
|
697 |
// different packages throughout the source tree. For example, a
|
|
|
698 |
// particular widget may define one or more resource bundles,
|
|
|
699 |
// structured in a program as follows, where moduleName is
|
|
|
700 |
// mycode.mywidget and bundleNames available include bundleone and
|
|
|
701 |
// bundletwo:
|
|
|
702 |
//
|
|
|
703 |
// ...
|
|
|
704 |
// mycode/
|
|
|
705 |
// mywidget/
|
|
|
706 |
// nls/
|
|
|
707 |
// bundleone.js (the fallback translation, English in this example)
|
|
|
708 |
// bundletwo.js (also a fallback translation)
|
|
|
709 |
// de/
|
|
|
710 |
// bundleone.js
|
|
|
711 |
// bundletwo.js
|
|
|
712 |
// de-at/
|
|
|
713 |
// bundleone.js
|
|
|
714 |
// en/
|
|
|
715 |
// (empty; use the fallback translation)
|
|
|
716 |
// en-us/
|
|
|
717 |
// bundleone.js
|
|
|
718 |
// en-gb/
|
|
|
719 |
// bundleone.js
|
|
|
720 |
// es/
|
|
|
721 |
// bundleone.js
|
|
|
722 |
// bundletwo.js
|
|
|
723 |
// ...etc
|
|
|
724 |
// ...
|
|
|
725 |
//
|
|
|
726 |
// Each directory is named for a locale as specified by RFC 3066,
|
|
|
727 |
// (http://www.ietf.org/rfc/rfc3066.txt), normalized in lowercase.
|
|
|
728 |
// Note that the two bundles in the example do not define all the same
|
|
|
729 |
// variants. For a given locale, bundles will be loaded for that
|
|
|
730 |
// locale and all more general locales above it, including a fallback
|
|
|
731 |
// at the root directory. For example, a declaration for the "de-at"
|
|
|
732 |
// locale will first load nls/de-at/bundleone.js, then
|
|
|
733 |
// nls/de/bundleone.js and finally nls/bundleone.js. The data will be
|
|
|
734 |
// flattened into a single Object so that lookups will follow this
|
|
|
735 |
// cascading pattern. An optional build step can preload the bundles
|
|
|
736 |
// to avoid data redundancy and the multiple network hits normally
|
|
|
737 |
// required to load these resources.
|
|
|
738 |
|
|
|
739 |
d.require("dojo.i18n");
|
|
|
740 |
d.i18n._requireLocalization.apply(d.hostenv, arguments);
|
|
|
741 |
};
|
|
|
742 |
|
|
|
743 |
|
|
|
744 |
var ore = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$");
|
|
|
745 |
var ire = new RegExp("^((([^:]+:)?([^@]+))@)?([^:]*)(:([0-9]+))?$");
|
|
|
746 |
|
|
|
747 |
dojo._Url = function(/*dojo._Url||String...*/){
|
|
|
748 |
// summary:
|
|
|
749 |
// Constructor to create an object representing a URL.
|
|
|
750 |
// It is marked as private, since we might consider removing
|
|
|
751 |
// or simplifying it.
|
|
|
752 |
// description:
|
|
|
753 |
// Each argument is evaluated in order relative to the next until
|
|
|
754 |
// a canonical uri is produced. To get an absolute Uri relative to
|
|
|
755 |
// the current document use:
|
|
|
756 |
// new dojo._Url(document.baseURI, url)
|
|
|
757 |
|
|
|
758 |
var n = null;
|
|
|
759 |
|
|
|
760 |
// TODO: support for IPv6, see RFC 2732
|
|
|
761 |
var _a = arguments;
|
|
|
762 |
var uri = _a[0];
|
|
|
763 |
// resolve uri components relative to each other
|
|
|
764 |
for(var i = 1; i<_a.length; i++){
|
|
|
765 |
if(!_a[i]){ continue; }
|
|
|
766 |
|
|
|
767 |
// Safari doesn't support this.constructor so we have to be explicit
|
|
|
768 |
// FIXME: Tracked (and fixed) in Webkit bug 3537.
|
|
|
769 |
// http://bugs.webkit.org/show_bug.cgi?id=3537
|
|
|
770 |
var relobj = new d._Url(_a[i]+"");
|
|
|
771 |
var uriobj = new d._Url(uri+"");
|
|
|
772 |
|
|
|
773 |
if(
|
|
|
774 |
(relobj.path=="") &&
|
|
|
775 |
(!relobj.scheme) &&
|
|
|
776 |
(!relobj.authority) &&
|
|
|
777 |
(!relobj.query)
|
|
|
778 |
){
|
|
|
779 |
if(relobj.fragment != n){
|
|
|
780 |
uriobj.fragment = relobj.fragment;
|
|
|
781 |
}
|
|
|
782 |
relobj = uriobj;
|
|
|
783 |
}else if(!relobj.scheme){
|
|
|
784 |
relobj.scheme = uriobj.scheme;
|
|
|
785 |
|
|
|
786 |
if(!relobj.authority){
|
|
|
787 |
relobj.authority = uriobj.authority;
|
|
|
788 |
|
|
|
789 |
if(relobj.path.charAt(0) != "/"){
|
|
|
790 |
var path = uriobj.path.substring(0,
|
|
|
791 |
uriobj.path.lastIndexOf("/") + 1) + relobj.path;
|
|
|
792 |
|
|
|
793 |
var segs = path.split("/");
|
|
|
794 |
for(var j = 0; j < segs.length; j++){
|
|
|
795 |
if(segs[j] == "."){
|
|
|
796 |
if(j == segs.length - 1){
|
|
|
797 |
segs[j] = "";
|
|
|
798 |
}else{
|
|
|
799 |
segs.splice(j, 1);
|
|
|
800 |
j--;
|
|
|
801 |
}
|
|
|
802 |
}else if(j > 0 && !(j == 1 && segs[0] == "") &&
|
|
|
803 |
segs[j] == ".." && segs[j-1] != ".."){
|
|
|
804 |
|
|
|
805 |
if(j == (segs.length - 1)){
|
|
|
806 |
segs.splice(j, 1);
|
|
|
807 |
segs[j - 1] = "";
|
|
|
808 |
}else{
|
|
|
809 |
segs.splice(j - 1, 2);
|
|
|
810 |
j -= 2;
|
|
|
811 |
}
|
|
|
812 |
}
|
|
|
813 |
}
|
|
|
814 |
relobj.path = segs.join("/");
|
|
|
815 |
}
|
|
|
816 |
}
|
|
|
817 |
}
|
|
|
818 |
|
|
|
819 |
uri = "";
|
|
|
820 |
if(relobj.scheme){
|
|
|
821 |
uri += relobj.scheme + ":";
|
|
|
822 |
}
|
|
|
823 |
if(relobj.authority){
|
|
|
824 |
uri += "//" + relobj.authority;
|
|
|
825 |
}
|
|
|
826 |
uri += relobj.path;
|
|
|
827 |
if(relobj.query){
|
|
|
828 |
uri += "?" + relobj.query;
|
|
|
829 |
}
|
|
|
830 |
if(relobj.fragment){
|
|
|
831 |
uri += "#" + relobj.fragment;
|
|
|
832 |
}
|
|
|
833 |
}
|
|
|
834 |
|
|
|
835 |
this.uri = uri.toString();
|
|
|
836 |
|
|
|
837 |
// break the uri into its main components
|
|
|
838 |
var r = this.uri.match(ore);
|
|
|
839 |
|
|
|
840 |
this.scheme = r[2] || (r[1] ? "" : n);
|
|
|
841 |
this.authority = r[4] || (r[3] ? "" : n);
|
|
|
842 |
this.path = r[5]; // can never be undefined
|
|
|
843 |
this.query = r[7] || (r[6] ? "" : n);
|
|
|
844 |
this.fragment = r[9] || (r[8] ? "" : n);
|
|
|
845 |
|
|
|
846 |
if(this.authority != n){
|
|
|
847 |
// server based naming authority
|
|
|
848 |
r = this.authority.match(ire);
|
|
|
849 |
|
|
|
850 |
this.user = r[3] || n;
|
|
|
851 |
this.password = r[4] || n;
|
|
|
852 |
this.host = r[5];
|
|
|
853 |
this.port = r[7] || n;
|
|
|
854 |
}
|
|
|
855 |
}
|
|
|
856 |
|
|
|
857 |
dojo._Url.prototype.toString = function(){ return this.uri; };
|
|
|
858 |
|
|
|
859 |
dojo.moduleUrl = function(/*String*/module, /*dojo._Url||String*/url){
|
|
|
860 |
// summary:
|
|
|
861 |
// Returns a Url object relative to a module
|
|
|
862 |
//
|
|
|
863 |
// example:
|
|
|
864 |
// | dojo.moduleUrl("dojo.widget","templates/template.html");
|
|
|
865 |
// example:
|
|
|
866 |
// | dojo.moduleUrl("acme","images/small.png")
|
|
|
867 |
|
|
|
868 |
var loc = dojo._getModuleSymbols(module).join('/');
|
|
|
869 |
if(!loc){ return null; }
|
|
|
870 |
if(loc.lastIndexOf("/") != loc.length-1){
|
|
|
871 |
loc += "/";
|
|
|
872 |
}
|
|
|
873 |
|
|
|
874 |
//If the path is an absolute path (starts with a / or is on another
|
|
|
875 |
//domain/xdomain) then don't add the baseUrl.
|
|
|
876 |
var colonIndex = loc.indexOf(":");
|
|
|
877 |
if(loc.charAt(0) != "/" && (colonIndex == -1 || colonIndex > loc.indexOf("/"))){
|
|
|
878 |
loc = d.baseUrl + loc;
|
|
|
879 |
}
|
|
|
880 |
|
|
|
881 |
return new d._Url(loc, url); // String
|
|
|
882 |
}
|
|
|
883 |
})();
|
|
|
884 |
|
|
|
885 |
if(typeof window != 'undefined'){
|
|
|
886 |
dojo.isBrowser = true;
|
|
|
887 |
dojo._name = "browser";
|
|
|
888 |
|
|
|
889 |
|
|
|
890 |
// attempt to figure out the path to dojo if it isn't set in the config
|
|
|
891 |
(function(){
|
|
|
892 |
var d = dojo;
|
|
|
893 |
// this is a scope protection closure. We set browser versions and grab
|
|
|
894 |
// the URL we were loaded from here.
|
|
|
895 |
|
|
|
896 |
// grab the node we were loaded from
|
|
|
897 |
if(document && document.getElementsByTagName){
|
|
|
898 |
var scripts = document.getElementsByTagName("script");
|
|
|
899 |
var rePkg = /dojo(\.xd)?\.js([\?\.]|$)/i;
|
|
|
900 |
for(var i = 0; i < scripts.length; i++){
|
|
|
901 |
var src = scripts[i].getAttribute("src");
|
|
|
902 |
if(!src){ continue; }
|
|
|
903 |
var m = src.match(rePkg);
|
|
|
904 |
if(m){
|
|
|
905 |
// find out where we came from
|
|
|
906 |
if(!djConfig["baseUrl"]){
|
|
|
907 |
djConfig["baseUrl"] = src.substring(0, m.index);
|
|
|
908 |
}
|
|
|
909 |
// and find out if we need to modify our behavior
|
|
|
910 |
var cfg = scripts[i].getAttribute("djConfig");
|
|
|
911 |
if(cfg){
|
|
|
912 |
var cfgo = eval("({ "+cfg+" })");
|
|
|
913 |
for(var x in cfgo){
|
|
|
914 |
djConfig[x] = cfgo[x];
|
|
|
915 |
}
|
|
|
916 |
}
|
|
|
917 |
break; // "first Dojo wins"
|
|
|
918 |
}
|
|
|
919 |
}
|
|
|
920 |
}
|
|
|
921 |
d.baseUrl = djConfig["baseUrl"];
|
|
|
922 |
|
|
|
923 |
// fill in the rendering support information in dojo.render.*
|
|
|
924 |
var n = navigator;
|
|
|
925 |
var dua = n.userAgent;
|
|
|
926 |
var dav = n.appVersion;
|
|
|
927 |
var tv = parseFloat(dav);
|
|
|
928 |
|
|
|
929 |
d.isOpera = (dua.indexOf("Opera") >= 0) ? tv : 0;
|
|
|
930 |
d.isKhtml = (dav.indexOf("Konqueror") >= 0)||(dav.indexOf("Safari") >= 0) ? tv : 0;
|
|
|
931 |
if(dav.indexOf("Safari") >= 0){
|
|
|
932 |
d.isSafari = parseFloat(dav.split("Version/")[1]) || 2;
|
|
|
933 |
}
|
|
|
934 |
var geckoPos = dua.indexOf("Gecko");
|
|
|
935 |
d.isMozilla = d.isMoz = ((geckoPos >= 0)&&(!d.isKhtml)) ? tv : 0;
|
|
|
936 |
d.isFF = 0;
|
|
|
937 |
d.isIE = 0;
|
|
|
938 |
try{
|
|
|
939 |
if(d.isMoz){
|
|
|
940 |
d.isFF = parseFloat(dua.split("Firefox/")[1].split(" ")[0]);
|
|
|
941 |
}
|
|
|
942 |
if((document.all)&&(!d.isOpera)){
|
|
|
943 |
d.isIE = parseFloat(dav.split("MSIE ")[1].split(";")[0]);
|
|
|
944 |
}
|
|
|
945 |
}catch(e){}
|
|
|
946 |
|
|
|
947 |
//Workaround to get local file loads of dojo to work on IE 7
|
|
|
948 |
//by forcing to not use native xhr.
|
|
|
949 |
if(dojo.isIE && (window.location.protocol === "file:")){
|
|
|
950 |
djConfig.ieForceActiveXXhr=true;
|
|
|
951 |
}
|
|
|
952 |
|
|
|
953 |
var cm = document["compatMode"];
|
|
|
954 |
d.isQuirks = (cm == "BackCompat")||(cm == "QuirksMode")||(d.isIE < 6);
|
|
|
955 |
|
|
|
956 |
// TODO: is the HTML LANG attribute relevant?
|
|
|
957 |
d.locale = djConfig.locale || (d.isIE ? n.userLanguage : n.language).toLowerCase();
|
|
|
958 |
|
|
|
959 |
d._println = console.debug;
|
|
|
960 |
|
|
|
961 |
// These are in order of decreasing likelihood; this will change in time.
|
|
|
962 |
d._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
|
|
|
963 |
|
|
|
964 |
d._xhrObj= function(){
|
|
|
965 |
// summary:
|
|
|
966 |
// does the work of portably generating a new XMLHTTPRequest
|
|
|
967 |
// object.
|
|
|
968 |
var http = null;
|
|
|
969 |
var last_e = null;
|
|
|
970 |
if(!dojo.isIE || !djConfig.ieForceActiveXXhr){
|
|
|
971 |
try{ http = new XMLHttpRequest(); }catch(e){}
|
|
|
972 |
}
|
|
|
973 |
if(!http){
|
|
|
974 |
for(var i=0; i<3; ++i){
|
|
|
975 |
var progid = dojo._XMLHTTP_PROGIDS[i];
|
|
|
976 |
try{
|
|
|
977 |
http = new ActiveXObject(progid);
|
|
|
978 |
}catch(e){
|
|
|
979 |
last_e = e;
|
|
|
980 |
}
|
|
|
981 |
|
|
|
982 |
if(http){
|
|
|
983 |
dojo._XMLHTTP_PROGIDS = [progid]; // so faster next time
|
|
|
984 |
break;
|
|
|
985 |
}
|
|
|
986 |
}
|
|
|
987 |
}
|
|
|
988 |
|
|
|
989 |
if(!http){
|
|
|
990 |
throw new Error("XMLHTTP not available: "+last_e);
|
|
|
991 |
}
|
|
|
992 |
|
|
|
993 |
return http; // XMLHTTPRequest instance
|
|
|
994 |
}
|
|
|
995 |
|
|
|
996 |
d._isDocumentOk = function(http){
|
|
|
997 |
var stat = http.status || 0;
|
|
|
998 |
return ( (stat>=200)&&(stat<300))|| // Boolean
|
|
|
999 |
(stat==304)|| // allow any 2XX response code
|
|
|
1000 |
(stat==1223)|| // get it out of the cache
|
|
|
1001 |
(!stat && (location.protocol=="file:" || location.protocol=="chrome:") ); // Internet Explorer mangled the status code
|
|
|
1002 |
}
|
|
|
1003 |
|
|
|
1004 |
//See if base tag is in use.
|
|
|
1005 |
//This is to fix http://trac.dojotoolkit.org/ticket/3973,
|
|
|
1006 |
//but really, we need to find out how to get rid of the dojo._Url reference
|
|
|
1007 |
//below and still have DOH work with the dojo.i18n test following some other
|
|
|
1008 |
//test that uses the test frame to load a document (trac #2757).
|
|
|
1009 |
//Opera still has problems, but perhaps a larger issue of base tag support
|
|
|
1010 |
//with XHR requests (hasBase is true, but the request is still made to document
|
|
|
1011 |
//path, not base path).
|
|
|
1012 |
var owloc = window.location+"";
|
|
|
1013 |
var base = document.getElementsByTagName("base");
|
|
|
1014 |
var hasBase = (base && base.length > 0);
|
|
|
1015 |
|
|
|
1016 |
d._getText = function(/*URI*/ uri, /*Boolean*/ fail_ok){
|
|
|
1017 |
// summary: Read the contents of the specified uri and return those contents.
|
|
|
1018 |
// uri:
|
|
|
1019 |
// A relative or absolute uri. If absolute, it still must be in
|
|
|
1020 |
// the same "domain" as we are.
|
|
|
1021 |
// fail_ok:
|
|
|
1022 |
// Default false. If fail_ok and loading fails, return null
|
|
|
1023 |
// instead of throwing.
|
|
|
1024 |
// returns: The response text. null is returned when there is a
|
|
|
1025 |
// failure and failure is okay (an exception otherwise)
|
|
|
1026 |
|
|
|
1027 |
// alert("_getText: " + uri);
|
|
|
1028 |
|
|
|
1029 |
// NOTE: must be declared before scope switches ie. this._xhrObj()
|
|
|
1030 |
var http = this._xhrObj();
|
|
|
1031 |
|
|
|
1032 |
if(!hasBase && dojo._Url){
|
|
|
1033 |
uri = (new dojo._Url(owloc, uri)).toString();
|
|
|
1034 |
}
|
|
|
1035 |
/*
|
|
|
1036 |
console.debug("_getText:", uri);
|
|
|
1037 |
console.debug(window.location+"");
|
|
|
1038 |
alert(uri);
|
|
|
1039 |
*/
|
|
|
1040 |
|
|
|
1041 |
http.open('GET', uri, false);
|
|
|
1042 |
try{
|
|
|
1043 |
http.send(null);
|
|
|
1044 |
// alert(http);
|
|
|
1045 |
if(!d._isDocumentOk(http)){
|
|
|
1046 |
var err = Error("Unable to load "+uri+" status:"+ http.status);
|
|
|
1047 |
err.status = http.status;
|
|
|
1048 |
err.responseText = http.responseText;
|
|
|
1049 |
throw err;
|
|
|
1050 |
}
|
|
|
1051 |
}catch(e){
|
|
|
1052 |
if(fail_ok){ return null; } // null
|
|
|
1053 |
// rethrow the exception
|
|
|
1054 |
throw e;
|
|
|
1055 |
}
|
|
|
1056 |
return http.responseText; // String
|
|
|
1057 |
}
|
|
|
1058 |
})();
|
|
|
1059 |
|
|
|
1060 |
dojo._initFired = false;
|
|
|
1061 |
// BEGIN DOMContentLoaded, from Dean Edwards (http://dean.edwards.name/weblog/2006/06/again/)
|
|
|
1062 |
dojo._loadInit = function(e){
|
|
|
1063 |
dojo._initFired = true;
|
|
|
1064 |
// allow multiple calls, only first one will take effect
|
|
|
1065 |
// A bug in khtml calls events callbacks for document for event which isnt supported
|
|
|
1066 |
// for example a created contextmenu event calls DOMContentLoaded, workaround
|
|
|
1067 |
var type = (e && e.type) ? e.type.toLowerCase() : "load";
|
|
|
1068 |
if(arguments.callee.initialized || (type!="domcontentloaded" && type!="load")){ return; }
|
|
|
1069 |
arguments.callee.initialized = true;
|
|
|
1070 |
if(typeof dojo["_khtmlTimer"] != 'undefined'){
|
|
|
1071 |
clearInterval(dojo._khtmlTimer);
|
|
|
1072 |
delete dojo._khtmlTimer;
|
|
|
1073 |
}
|
|
|
1074 |
|
|
|
1075 |
if(dojo._inFlightCount == 0){
|
|
|
1076 |
dojo._modulesLoaded();
|
|
|
1077 |
}
|
|
|
1078 |
}
|
|
|
1079 |
|
|
|
1080 |
// START DOMContentLoaded
|
|
|
1081 |
// Mozilla and Opera 9 expose the event we could use
|
|
|
1082 |
if(document.addEventListener){
|
|
|
1083 |
// NOTE:
|
|
|
1084 |
// due to a threading issue in Firefox 2.0, we can't enable
|
|
|
1085 |
// DOMContentLoaded on that platform. For more information, see:
|
|
|
1086 |
// http://trac.dojotoolkit.org/ticket/1704
|
|
|
1087 |
if(dojo.isOpera|| (dojo.isMoz && (djConfig["enableMozDomContentLoaded"] === true))){
|
|
|
1088 |
document.addEventListener("DOMContentLoaded", dojo._loadInit, null);
|
|
|
1089 |
}
|
|
|
1090 |
|
|
|
1091 |
// mainly for Opera 8.5, won't be fired if DOMContentLoaded fired already.
|
|
|
1092 |
// also used for Mozilla because of trac #1640
|
|
|
1093 |
window.addEventListener("load", dojo._loadInit, null);
|
|
|
1094 |
}
|
|
|
1095 |
|
|
|
1096 |
if(/(WebKit|khtml)/i.test(navigator.userAgent)){ // sniff
|
|
|
1097 |
dojo._khtmlTimer = setInterval(function(){
|
|
|
1098 |
if(/loaded|complete/.test(document.readyState)){
|
|
|
1099 |
dojo._loadInit(); // call the onload handler
|
|
|
1100 |
}
|
|
|
1101 |
}, 10);
|
|
|
1102 |
}
|
|
|
1103 |
// END DOMContentLoaded
|
|
|
1104 |
|
|
|
1105 |
(function(){
|
|
|
1106 |
|
|
|
1107 |
var _w = window;
|
|
|
1108 |
var _handleNodeEvent = function(/*String*/evtName, /*Function*/fp){
|
|
|
1109 |
// summary:
|
|
|
1110 |
// non-destructively adds the specified function to the node's
|
|
|
1111 |
// evtName handler.
|
|
|
1112 |
// evtName: should be in the form "onclick" for "onclick" handlers.
|
|
|
1113 |
// Make sure you pass in the "on" part.
|
|
|
1114 |
var oldHandler = _w[evtName] || function(){};
|
|
|
1115 |
_w[evtName] = function(){
|
|
|
1116 |
fp.apply(_w, arguments);
|
|
|
1117 |
oldHandler.apply(_w, arguments);
|
|
|
1118 |
}
|
|
|
1119 |
}
|
|
|
1120 |
|
|
|
1121 |
if(dojo.isIE){
|
|
|
1122 |
// for Internet Explorer. readyState will not be achieved on init
|
|
|
1123 |
// call, but dojo doesn't need it however, we'll include it
|
|
|
1124 |
// because we don't know if there are other functions added that
|
|
|
1125 |
// might. Note that this has changed because the build process
|
|
|
1126 |
// strips all comments -- including conditional ones.
|
|
|
1127 |
|
|
|
1128 |
document.write('<scr'+'ipt defer src="//:" '
|
|
|
1129 |
+ 'onreadystatechange="if(this.readyState==\'complete\'){dojo._loadInit();}">'
|
|
|
1130 |
+ '</scr'+'ipt>'
|
|
|
1131 |
);
|
|
|
1132 |
|
|
|
1133 |
// IE WebControl hosted in an application can fire "beforeunload" and "unload"
|
|
|
1134 |
// events when control visibility changes, causing Dojo to unload too soon. The
|
|
|
1135 |
// following code fixes the problem
|
|
|
1136 |
// Reference: http://support.microsoft.com/default.aspx?scid=kb;en-us;199155
|
|
|
1137 |
var _unloading = true;
|
|
|
1138 |
_handleNodeEvent("onbeforeunload", function(){
|
|
|
1139 |
_w.setTimeout(function(){ _unloading = false; }, 0);
|
|
|
1140 |
});
|
|
|
1141 |
_handleNodeEvent("onunload", function(){
|
|
|
1142 |
if(_unloading){ dojo.unloaded(); }
|
|
|
1143 |
});
|
|
|
1144 |
|
|
|
1145 |
try{
|
|
|
1146 |
document.namespaces.add("v","urn:schemas-microsoft-com:vml");
|
|
|
1147 |
document.createStyleSheet().addRule("v\\:*", "behavior:url(#default#VML)");
|
|
|
1148 |
}catch(e){}
|
|
|
1149 |
}else{
|
|
|
1150 |
// FIXME: dojo.unloaded requires dojo scope, so using anon function wrapper.
|
|
|
1151 |
_handleNodeEvent("onbeforeunload", function() { dojo.unloaded(); });
|
|
|
1152 |
}
|
|
|
1153 |
|
|
|
1154 |
})();
|
|
|
1155 |
|
|
|
1156 |
/*
|
|
|
1157 |
OpenAjax.subscribe("OpenAjax", "onload", function(){
|
|
|
1158 |
if(dojo._inFlightCount == 0){
|
|
|
1159 |
dojo._modulesLoaded();
|
|
|
1160 |
}
|
|
|
1161 |
});
|
|
|
1162 |
|
|
|
1163 |
OpenAjax.subscribe("OpenAjax", "onunload", function(){
|
|
|
1164 |
dojo.unloaded();
|
|
|
1165 |
});
|
|
|
1166 |
*/
|
|
|
1167 |
} //if (typeof window != 'undefined')
|
|
|
1168 |
|
|
|
1169 |
//Load debug code if necessary.
|
|
|
1170 |
// dojo.requireIf((djConfig["isDebug"] || djConfig["debugAtAllCosts"]), "dojo.debug");
|
|
|
1171 |
|
|
|
1172 |
//window.widget is for Dashboard detection
|
|
|
1173 |
//The full conditionals are spelled out to avoid issues during builds.
|
|
|
1174 |
//Builds may be looking for require/requireIf statements and processing them.
|
|
|
1175 |
// dojo.requireIf(djConfig["debugAtAllCosts"] && !window.widget && !djConfig["useXDomain"], "dojo.browser_debug");
|
|
|
1176 |
// dojo.requireIf(djConfig["debugAtAllCosts"] && !window.widget && djConfig["useXDomain"], "dojo.browser_debug_xd");
|
|
|
1177 |
|
|
|
1178 |
if(djConfig.isDebug){
|
|
|
1179 |
dojo.require("dojo._firebug.firebug");
|
|
|
1180 |
}
|
|
|
1181 |
|
|
|
1182 |
if(djConfig.debugAtAllCosts){
|
|
|
1183 |
djConfig.useXDomain = true;
|
|
|
1184 |
dojo.require("dojo._base._loader.loader_xd");
|
|
|
1185 |
dojo.require("dojo._base._loader.loader_debug");
|
|
|
1186 |
dojo.require("dojo.i18n");
|
|
|
1187 |
}
|
|
|
1188 |
|
|
|
1189 |
};
|
|
|
1190 |
|
|
|
1191 |
if(!dojo._hasResource["dojo._base.lang"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
1192 |
dojo._hasResource["dojo._base.lang"] = true;
|
|
|
1193 |
dojo.provide("dojo._base.lang");
|
|
|
1194 |
|
|
|
1195 |
// Crockford (ish) functions
|
|
|
1196 |
|
|
|
1197 |
dojo.isString = function(/*anything*/ it){
|
|
|
1198 |
// summary: Return true if it is a String
|
|
|
1199 |
return typeof it == "string" || it instanceof String; // Boolean
|
|
|
1200 |
}
|
|
|
1201 |
|
|
|
1202 |
dojo.isArray = function(/*anything*/ it){
|
|
|
1203 |
// summary: Return true if it is an Array
|
|
|
1204 |
return it && it instanceof Array || typeof it == "array"; // Boolean
|
|
|
1205 |
}
|
|
|
1206 |
|
|
|
1207 |
/*=====
|
|
|
1208 |
dojo.isFunction = function(it){
|
|
|
1209 |
// summary: Return true if it is a Function
|
|
|
1210 |
// it: anything
|
|
|
1211 |
}
|
|
|
1212 |
=====*/
|
|
|
1213 |
|
|
|
1214 |
dojo.isFunction = (function(){
|
|
|
1215 |
var _isFunction = function(/*anything*/ it){
|
|
|
1216 |
return typeof it == "function" || it instanceof Function; // Boolean
|
|
|
1217 |
};
|
|
|
1218 |
|
|
|
1219 |
return dojo.isSafari ?
|
|
|
1220 |
// only slow this down w/ gratuitious casting in Safari since it's what's b0rken
|
|
|
1221 |
function(/*anything*/ it){
|
|
|
1222 |
if(typeof it == "function" && it == "[object NodeList]"){ return false; }
|
|
|
1223 |
return _isFunction(it); // Boolean
|
|
|
1224 |
} : _isFunction;
|
|
|
1225 |
})();
|
|
|
1226 |
|
|
|
1227 |
dojo.isObject = function(/*anything*/ it){
|
|
|
1228 |
// summary:
|
|
|
1229 |
// Returns true if it is a JavaScript object (or an Array, a Function or null)
|
|
|
1230 |
return it !== undefined &&
|
|
|
1231 |
(it === null || typeof it == "object" || dojo.isArray(it) || dojo.isFunction(it)); // Boolean
|
|
|
1232 |
}
|
|
|
1233 |
|
|
|
1234 |
dojo.isArrayLike = function(/*anything*/ it){
|
|
|
1235 |
// summary:
|
|
|
1236 |
// similar to dojo.isArray() but more permissive
|
|
|
1237 |
// description:
|
|
|
1238 |
// Doesn't strongly test for "arrayness". Instead, settles for "isn't
|
|
|
1239 |
// a string or number and has a length property". Arguments objects
|
|
|
1240 |
// and DOM collections will return true when passed to
|
|
|
1241 |
// dojo.isArrayLike(), but will return false when passed to
|
|
|
1242 |
// dojo.isArray().
|
|
|
1243 |
// return:
|
|
|
1244 |
// If it walks like a duck and quicks like a duck, return true
|
|
|
1245 |
var d = dojo;
|
|
|
1246 |
return it && it !== undefined &&
|
|
|
1247 |
// keep out built-in constructors (Number, String, ...) which have length
|
|
|
1248 |
// properties
|
|
|
1249 |
!d.isString(it) && !d.isFunction(it) &&
|
|
|
1250 |
!(it.tagName && it.tagName.toLowerCase() == 'form') &&
|
|
|
1251 |
(d.isArray(it) || isFinite(it.length)); // Boolean
|
|
|
1252 |
}
|
|
|
1253 |
|
|
|
1254 |
dojo.isAlien = function(/*anything*/ it){
|
|
|
1255 |
// summary:
|
|
|
1256 |
// Returns true if it is a built-in function or some other kind of
|
|
|
1257 |
// oddball that *should* report as a function but doesn't
|
|
|
1258 |
return it && !dojo.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean
|
|
|
1259 |
}
|
|
|
1260 |
|
|
|
1261 |
dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){
|
|
|
1262 |
// summary:
|
|
|
1263 |
// Adds all properties and methods of props to constructor's
|
|
|
1264 |
// prototype, making them available to all instances created with
|
|
|
1265 |
// constructor.
|
|
|
1266 |
for(var i=1, l=arguments.length; i<l; i++){
|
|
|
1267 |
dojo._mixin(constructor.prototype, arguments[i]);
|
|
|
1268 |
}
|
|
|
1269 |
return constructor; // Object
|
|
|
1270 |
}
|
|
|
1271 |
|
|
|
1272 |
dojo._hitchArgs = function(scope, method /*,...*/){
|
|
|
1273 |
var pre = dojo._toArray(arguments, 2);
|
|
|
1274 |
var named = dojo.isString(method);
|
|
|
1275 |
return function(){
|
|
|
1276 |
// arrayify arguments
|
|
|
1277 |
var args = dojo._toArray(arguments);
|
|
|
1278 |
// locate our method
|
|
|
1279 |
var f = named ? (scope||dojo.global)[method] : method;
|
|
|
1280 |
// invoke with collected args
|
|
|
1281 |
return f && f.apply(scope || this, pre.concat(args)); // mixed
|
|
|
1282 |
} // Function
|
|
|
1283 |
}
|
|
|
1284 |
|
|
|
1285 |
dojo.hitch = function(/*Object*/scope, /*Function|String*/method /*,...*/){
|
|
|
1286 |
// summary:
|
|
|
1287 |
// Returns a function that will only ever execute in the a given scope.
|
|
|
1288 |
// This allows for easy use of object member functions
|
|
|
1289 |
// in callbacks and other places in which the "this" keyword may
|
|
|
1290 |
// otherwise not reference the expected scope.
|
|
|
1291 |
// Any number of default positional arguments may be passed as parameters
|
|
|
1292 |
// beyond "method".
|
|
|
1293 |
// Each of these values will be used to "placehold" (similar to curry)
|
|
|
1294 |
// for the hitched function.
|
|
|
1295 |
// scope:
|
|
|
1296 |
// The scope to use when method executes. If method is a string,
|
|
|
1297 |
// scope is also the object containing method.
|
|
|
1298 |
// method:
|
|
|
1299 |
// A function to be hitched to scope, or the name of the method in
|
|
|
1300 |
// scope to be hitched.
|
|
|
1301 |
// example:
|
|
|
1302 |
// | dojo.hitch(foo, "bar")();
|
|
|
1303 |
// runs foo.bar() in the scope of foo
|
|
|
1304 |
// example:
|
|
|
1305 |
// | dojo.hitch(foo, myFunction);
|
|
|
1306 |
// returns a function that runs myFunction in the scope of foo
|
|
|
1307 |
if(arguments.length > 2){
|
|
|
1308 |
return dojo._hitchArgs.apply(dojo, arguments); // Function
|
|
|
1309 |
}
|
|
|
1310 |
if(!method){
|
|
|
1311 |
method = scope;
|
|
|
1312 |
scope = null;
|
|
|
1313 |
}
|
|
|
1314 |
if(dojo.isString(method)){
|
|
|
1315 |
scope = scope || dojo.global;
|
|
|
1316 |
if(!scope[method]){ throw(['dojo.hitch: scope["', method, '"] is null (scope="', scope, '")'].join('')); }
|
|
|
1317 |
return function(){ return scope[method].apply(scope, arguments || []); }; // Function
|
|
|
1318 |
}
|
|
|
1319 |
return !scope ? method : function(){ return method.apply(scope, arguments || []); }; // Function
|
|
|
1320 |
}
|
|
|
1321 |
|
|
|
1322 |
/*=====
|
|
|
1323 |
dojo.delegate = function(obj, props){
|
|
|
1324 |
// summary:
|
|
|
1325 |
// returns a new object which "looks" to obj for properties which it
|
|
|
1326 |
// does not have a value for. Optionally takes a bag of properties to
|
|
|
1327 |
// seed the returned object with initially.
|
|
|
1328 |
// description:
|
|
|
1329 |
// This is a small implementaton of the Boodman/Crockford delegation
|
|
|
1330 |
// pattern in JavaScript. An intermediate object constructor mediates
|
|
|
1331 |
// the prototype chain for the returned object, using it to delegate
|
|
|
1332 |
// down to obj for property lookup when object-local lookup fails.
|
|
|
1333 |
// This can be thought of similarly to ES4's "wrap", save that it does
|
|
|
1334 |
// not act on types but rather on pure objects.
|
|
|
1335 |
// obj:
|
|
|
1336 |
// The object to delegate to for properties not found directly on the
|
|
|
1337 |
// return object or in props.
|
|
|
1338 |
// props:
|
|
|
1339 |
// an object containing properties to assign to the returned object
|
|
|
1340 |
// returns:
|
|
|
1341 |
// an Object of anonymous type
|
|
|
1342 |
// example:
|
|
|
1343 |
// | var foo = { bar: "baz" };
|
|
|
1344 |
// | var thinger = dojo.delegate(foo, { thud: "xyzzy"});
|
|
|
1345 |
// | thinger.bar == "baz"; // delegated to foo
|
|
|
1346 |
// | foo.xyzzy == undefined; // by definition
|
|
|
1347 |
// | thinger.xyzzy == "xyzzy"; // mixed in from props
|
|
|
1348 |
// | foo.bar = "thonk";
|
|
|
1349 |
// | thinger.bar == "thonk"; // still delegated to foo's bar
|
|
|
1350 |
}
|
|
|
1351 |
=====*/
|
|
|
1352 |
|
|
|
1353 |
|
|
|
1354 |
dojo.delegate = dojo._delegate = function(obj, props){
|
|
|
1355 |
|
|
|
1356 |
// boodman/crockford delegation
|
|
|
1357 |
function TMP(){};
|
|
|
1358 |
TMP.prototype = obj;
|
|
|
1359 |
var tmp = new TMP();
|
|
|
1360 |
if(props){
|
|
|
1361 |
dojo.mixin(tmp, props);
|
|
|
1362 |
}
|
|
|
1363 |
return tmp; // Object
|
|
|
1364 |
}
|
|
|
1365 |
|
|
|
1366 |
dojo.partial = function(/*Function|String*/method /*, ...*/){
|
|
|
1367 |
// summary:
|
|
|
1368 |
// similar to hitch() except that the scope object is left to be
|
|
|
1369 |
// whatever the execution context eventually becomes.
|
|
|
1370 |
// description:
|
|
|
1371 |
// Calling dojo.partial is the functional equivalent of calling:
|
|
|
1372 |
// | dojo.hitch(null, funcName, ...);
|
|
|
1373 |
var arr = [ null ];
|
|
|
1374 |
return dojo.hitch.apply(dojo, arr.concat(dojo._toArray(arguments))); // Function
|
|
|
1375 |
}
|
|
|
1376 |
|
|
|
1377 |
dojo._toArray = function(/*Object*/obj, /*Number?*/offset, /*Array?*/ startWith){
|
|
|
1378 |
// summary:
|
|
|
1379 |
// Converts an array-like object (i.e. arguments, DOMCollection)
|
|
|
1380 |
// to an array. Returns a new Array object.
|
|
|
1381 |
// obj:
|
|
|
1382 |
// the object to "arrayify". We expect the object to have, at a
|
|
|
1383 |
// minimum, a length property which corresponds to integer-indexed
|
|
|
1384 |
// properties.
|
|
|
1385 |
// offset:
|
|
|
1386 |
// the location in obj to start iterating from. Defaults to 0. Optional.
|
|
|
1387 |
// startWith:
|
|
|
1388 |
// An array to pack with the properties of obj. If provided,
|
|
|
1389 |
// properties in obj are appended at the end of startWith and
|
|
|
1390 |
// startWith is the returned array.
|
|
|
1391 |
var arr = startWith||[];
|
|
|
1392 |
for(var x = offset || 0; x < obj.length; x++){
|
|
|
1393 |
arr.push(obj[x]);
|
|
|
1394 |
}
|
|
|
1395 |
return arr; // Array
|
|
|
1396 |
}
|
|
|
1397 |
|
|
|
1398 |
dojo.clone = function(/*anything*/ o){
|
|
|
1399 |
// summary:
|
|
|
1400 |
// Clones objects (including DOM nodes) and all children.
|
|
|
1401 |
// Warning: do not clone cyclic structures.
|
|
|
1402 |
if(!o){ return o; }
|
|
|
1403 |
if(dojo.isArray(o)){
|
|
|
1404 |
var r = [];
|
|
|
1405 |
for(var i = 0; i < o.length; ++i){
|
|
|
1406 |
r.push(dojo.clone(o[i]));
|
|
|
1407 |
}
|
|
|
1408 |
return r; // Array
|
|
|
1409 |
}
|
|
|
1410 |
if(!dojo.isObject(o)){
|
|
|
1411 |
return o; /*anything*/
|
|
|
1412 |
}
|
|
|
1413 |
if(o.nodeType && o.cloneNode){ // isNode
|
|
|
1414 |
return o.cloneNode(true); // Node
|
|
|
1415 |
}
|
|
|
1416 |
if(o instanceof Date){
|
|
|
1417 |
return new Date(o.getTime()); // Date
|
|
|
1418 |
}
|
|
|
1419 |
// Generic objects
|
|
|
1420 |
var r = new o.constructor(); // specific to dojo.declare()'d classes!
|
|
|
1421 |
for(var i in o){
|
|
|
1422 |
if(!(i in r) || r[i] != o[i]){
|
|
|
1423 |
r[i] = dojo.clone(o[i]);
|
|
|
1424 |
}
|
|
|
1425 |
}
|
|
|
1426 |
return r; // Object
|
|
|
1427 |
}
|
|
|
1428 |
|
|
|
1429 |
dojo.trim = function(/*String*/ str){
|
|
|
1430 |
// summary:
|
|
|
1431 |
// trims whitespaces from both sides of the string
|
|
|
1432 |
// description:
|
|
|
1433 |
// This version of trim() was selected for inclusion into the base due
|
|
|
1434 |
// to its compact size and relatively good performance (see Steven
|
|
|
1435 |
// Levithan's blog:
|
|
|
1436 |
// http://blog.stevenlevithan.com/archives/faster-trim-javascript).
|
|
|
1437 |
// The fastest but longest version of this function is located at
|
|
|
1438 |
// dojo.string.trim()
|
|
|
1439 |
return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); // String
|
|
|
1440 |
}
|
|
|
1441 |
|
|
|
1442 |
}
|
|
|
1443 |
|
|
|
1444 |
if(!dojo._hasResource["dojo._base.declare"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
1445 |
dojo._hasResource["dojo._base.declare"] = true;
|
|
|
1446 |
dojo.provide("dojo._base.declare");
|
|
|
1447 |
|
|
|
1448 |
|
|
|
1449 |
// this file courtesy of the TurboAjax group, licensed under a Dojo CLA
|
|
|
1450 |
|
|
|
1451 |
dojo.declare = function(/*String*/ className, /*Function|Function[]*/ superclass, /*Object*/ props){
|
|
|
1452 |
// summary:
|
|
|
1453 |
// Create a feature-rich constructor from compact notation
|
|
|
1454 |
// className:
|
|
|
1455 |
// The name of the constructor (loosely, a "class")
|
|
|
1456 |
// stored in the "declaredClass" property in the created prototype
|
|
|
1457 |
// superclass:
|
|
|
1458 |
// May be null, a Function, or an Array of Functions. If an array,
|
|
|
1459 |
// the first element is used as the prototypical ancestor and
|
|
|
1460 |
// any following Functions become mixin ancestors.
|
|
|
1461 |
// props:
|
|
|
1462 |
// An object whose properties are copied to the
|
|
|
1463 |
// created prototype.
|
|
|
1464 |
// Add an instance-initialization function by making it a property
|
|
|
1465 |
// named "constructor".
|
|
|
1466 |
// description:
|
|
|
1467 |
// Create a constructor using a compact notation for inheritance and
|
|
|
1468 |
// prototype extension.
|
|
|
1469 |
//
|
|
|
1470 |
// All superclasses (including mixins) must be Functions (not simple Objects).
|
|
|
1471 |
//
|
|
|
1472 |
// Mixin ancestors provide a type of multiple inheritance. Prototypes of mixin
|
|
|
1473 |
// ancestors are copied to the new class: changes to mixin prototypes will
|
|
|
1474 |
// not affect classes to which they have been mixed in.
|
|
|
1475 |
//
|
|
|
1476 |
// "className" is cached in "declaredClass" property of the new class.
|
|
|
1477 |
//
|
|
|
1478 |
// example:
|
|
|
1479 |
// | dojo.declare("my.classes.bar", my.classes.foo, {
|
|
|
1480 |
// | // properties to be added to the class prototype
|
|
|
1481 |
// | someValue: 2,
|
|
|
1482 |
// | // initialization function
|
|
|
1483 |
// | constructor: function(){
|
|
|
1484 |
// | this.myComplicatedObject = new ReallyComplicatedObject();
|
|
|
1485 |
// | },
|
|
|
1486 |
// | // other functions
|
|
|
1487 |
// | someMethod: function(){
|
|
|
1488 |
// | doStuff();
|
|
|
1489 |
// | }
|
|
|
1490 |
// | );
|
|
|
1491 |
|
|
|
1492 |
// argument juggling (deprecated)
|
|
|
1493 |
if(dojo.isFunction(props)||(arguments.length>3)){
|
|
|
1494 |
dojo.deprecated("dojo.declare: for class '" + className + "' pass initializer function as 'constructor' property instead of as a separate argument.", "", "1.0");
|
|
|
1495 |
var c = props;
|
|
|
1496 |
props = arguments[3] || {};
|
|
|
1497 |
props.constructor = c;
|
|
|
1498 |
}
|
|
|
1499 |
// process superclass argument
|
|
|
1500 |
// var dd=dojo.declare, mixins=null;
|
|
|
1501 |
var dd=arguments.callee, mixins=null;
|
|
|
1502 |
if(dojo.isArray(superclass)){
|
|
|
1503 |
mixins = superclass;
|
|
|
1504 |
superclass = mixins.shift();
|
|
|
1505 |
}
|
|
|
1506 |
// construct intermediate classes for mixins
|
|
|
1507 |
if(mixins){
|
|
|
1508 |
for(var i=0, m; i<mixins.length; i++){
|
|
|
1509 |
m = mixins[i];
|
|
|
1510 |
if(!m){throw("Mixin #" + i + " to declaration of " + className + " is null. It's likely a required module is not loaded.")};
|
|
|
1511 |
superclass = dd._delegate(superclass, m);
|
|
|
1512 |
}
|
|
|
1513 |
}
|
|
|
1514 |
// prepare values
|
|
|
1515 |
var init=(props||0).constructor, ctor=dd._delegate(superclass), fn;
|
|
|
1516 |
// name methods (experimental)
|
|
|
1517 |
for(var i in props){if(dojo.isFunction(fn=props[i])&&(!0[i])){fn.nom=i;}}
|
|
|
1518 |
// decorate prototype
|
|
|
1519 |
dojo.extend(ctor, {declaredClass: className, _constructor: init, preamble: null}, props||0);
|
|
|
1520 |
// special help for IE
|
|
|
1521 |
ctor.prototype.constructor = ctor;
|
|
|
1522 |
// create named reference
|
|
|
1523 |
return dojo.setObject(className, ctor); // Function
|
|
|
1524 |
}
|
|
|
1525 |
|
|
|
1526 |
dojo.mixin(dojo.declare, {
|
|
|
1527 |
_delegate: function(base, mixin){
|
|
|
1528 |
var bp = (base||0).prototype, mp = (mixin||0).prototype;
|
|
|
1529 |
// fresh constructor, fresh prototype
|
|
|
1530 |
var ctor = dojo.declare._makeCtor();
|
|
|
1531 |
// cache ancestry
|
|
|
1532 |
dojo.mixin(ctor, {superclass: bp, mixin: mp, extend: dojo.declare._extend});
|
|
|
1533 |
// chain prototypes
|
|
|
1534 |
if(base){ctor.prototype = dojo._delegate(bp);}
|
|
|
1535 |
// add mixin and core
|
|
|
1536 |
dojo.extend(ctor, dojo.declare._core, mp||0, {_constructor: null, preamble: null});
|
|
|
1537 |
// special help for IE
|
|
|
1538 |
ctor.prototype.constructor = ctor;
|
|
|
1539 |
// name this class for debugging
|
|
|
1540 |
ctor.prototype.declaredClass = (bp||0).declaredClass + '_' + (mp||0).declaredClass;
|
|
|
1541 |
return ctor;
|
|
|
1542 |
},
|
|
|
1543 |
_extend: function(props){
|
|
|
1544 |
for(var i in props){if(dojo.isFunction(fn=props[i])&&(!0[i])){fn.nom=i;}}
|
|
|
1545 |
dojo.extend(this, props);
|
|
|
1546 |
},
|
|
|
1547 |
_makeCtor: function(){
|
|
|
1548 |
// we have to make a function, but don't want to close over anything
|
|
|
1549 |
return function(){ this._construct(arguments); }
|
|
|
1550 |
},
|
|
|
1551 |
_core: {
|
|
|
1552 |
_construct: function(args){
|
|
|
1553 |
var c=args.callee, s=c.superclass, ct=s&&s.constructor, m=c.mixin, mct=m&&m.constructor, a=args, ii, fn;
|
|
|
1554 |
// side-effect of = used on purpose here, lint may complain, don't try this at home
|
|
|
1555 |
if(a[0]){
|
|
|
1556 |
// FIXME: preambles for each mixin should be allowed
|
|
|
1557 |
// FIXME:
|
|
|
1558 |
// should we allow the preamble here NOT to modify the
|
|
|
1559 |
// default args, but instead to act on each mixin
|
|
|
1560 |
// independently of the class instance being constructed
|
|
|
1561 |
// (for impdedence matching)?
|
|
|
1562 |
|
|
|
1563 |
// allow any first argument w/ a "preamble" property to act as a
|
|
|
1564 |
// class preamble (not exclusive of the prototype preamble)
|
|
|
1565 |
if(/*dojo.isFunction*/(fn = a[0]["preamble"])){
|
|
|
1566 |
a = fn.apply(this, a) || a;
|
|
|
1567 |
}
|
|
|
1568 |
}
|
|
|
1569 |
// prototype preamble
|
|
|
1570 |
if(fn=c.prototype.preamble){a = fn.apply(this, a) || a;}
|
|
|
1571 |
// FIXME:
|
|
|
1572 |
// need to provide an optional prototype-settable
|
|
|
1573 |
// "_explicitSuper" property which disables this
|
|
|
1574 |
// initialize superclass
|
|
|
1575 |
if(ct&&ct.apply){ct.apply(this, a);}
|
|
|
1576 |
// initialize mixin
|
|
|
1577 |
if(mct&&mct.apply){mct.apply(this, a);}
|
|
|
1578 |
// initialize self
|
|
|
1579 |
if(ii=c.prototype._constructor){ii.apply(this, args);}
|
|
|
1580 |
// post construction
|
|
|
1581 |
if(this.constructor.prototype==c.prototype && (ct=this.postscript)){ct.apply(this, args)};
|
|
|
1582 |
},
|
|
|
1583 |
_findMixin: function(mixin){
|
|
|
1584 |
var c = this.constructor, p, m;
|
|
|
1585 |
while(c){
|
|
|
1586 |
p = c.superclass;
|
|
|
1587 |
m = c.mixin;
|
|
|
1588 |
if(m==mixin || (m instanceof mixin.constructor)){return p;}
|
|
|
1589 |
if(m && (m=m._findMixin(mixin))){return m;}
|
|
|
1590 |
c = p && p.constructor;
|
|
|
1591 |
}
|
|
|
1592 |
},
|
|
|
1593 |
_findMethod: function(name, method, ptype, has){
|
|
|
1594 |
// consciously trading readability for bytes and speed in this low-level method
|
|
|
1595 |
var p=ptype, c, m, f;
|
|
|
1596 |
do{
|
|
|
1597 |
c = p.constructor;
|
|
|
1598 |
m = c.mixin;
|
|
|
1599 |
// find method by name in our mixin ancestor
|
|
|
1600 |
if(m && (m=this._findMethod(name, method, m, has))){return m};
|
|
|
1601 |
// if we found a named method that either exactly-is or exactly-is-not 'method'
|
|
|
1602 |
if((f=p[name])&&(has==(f==method))){return p};
|
|
|
1603 |
// ascend chain
|
|
|
1604 |
p = c.superclass;
|
|
|
1605 |
}while(p);
|
|
|
1606 |
// if we couldn't find an ancestor in our primary chain, try a mixin chain
|
|
|
1607 |
return !has && (p=this._findMixin(ptype)) && this._findMethod(name, method, p, has);
|
|
|
1608 |
},
|
|
|
1609 |
inherited: function(name, args, newArgs){
|
|
|
1610 |
// optionalize name argument (experimental)
|
|
|
1611 |
var a = arguments;
|
|
|
1612 |
if(!dojo.isString(a[0])){newArgs=args; args=name; name=args.callee.nom;}
|
|
|
1613 |
var c=args.callee, p=this.constructor.prototype, a=newArgs||args, fn, mp;
|
|
|
1614 |
// if not an instance override
|
|
|
1615 |
if(this[name]!=c || p[name]==c){
|
|
|
1616 |
mp = this._findMethod(name, c, p, true);
|
|
|
1617 |
if(!mp){throw(this.declaredClass + ': name argument ("' + name + '") to inherited must match callee (declare.js)');}
|
|
|
1618 |
p = this._findMethod(name, c, mp, false);
|
|
|
1619 |
}
|
|
|
1620 |
fn = p && p[name];
|
|
|
1621 |
// FIXME: perhaps we should throw here?
|
|
|
1622 |
if(!fn){console.debug(mp.declaredClass + ': no inherited "' + name + '" was found (declare.js)'); return;}
|
|
|
1623 |
// if the function exists, invoke it in our scope
|
|
|
1624 |
return fn.apply(this, a);
|
|
|
1625 |
}
|
|
|
1626 |
}
|
|
|
1627 |
});
|
|
|
1628 |
|
|
|
1629 |
}
|
|
|
1630 |
|
|
|
1631 |
if(!dojo._hasResource["dojo._base.connect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
1632 |
dojo._hasResource["dojo._base.connect"] = true;
|
|
|
1633 |
dojo.provide("dojo._base.connect");
|
|
|
1634 |
|
|
|
1635 |
|
|
|
1636 |
// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
|
|
|
1637 |
|
|
|
1638 |
// low-level delegation machinery
|
|
|
1639 |
dojo._listener = {
|
|
|
1640 |
// create a dispatcher function
|
|
|
1641 |
getDispatcher: function(){
|
|
|
1642 |
// following comments pulled out-of-line to prevent cloning them
|
|
|
1643 |
// in the returned function.
|
|
|
1644 |
// - indices (i) that are really in the array of listeners (ls) will
|
|
|
1645 |
// not be in Array.prototype. This is the 'sparse array' trick
|
|
|
1646 |
// that keeps us safe from libs that take liberties with built-in
|
|
|
1647 |
// objects
|
|
|
1648 |
// - listener is invoked with current scope (this)
|
|
|
1649 |
return function(){
|
|
|
1650 |
var ap=Array.prototype, c=arguments.callee, ls=c._listeners, t=c.target;
|
|
|
1651 |
// return value comes from original target function
|
|
|
1652 |
var r=t && t.apply(this, arguments);
|
|
|
1653 |
// invoke listeners after target function
|
|
|
1654 |
for(var i in ls){
|
|
|
1655 |
if(!(i in ap)){
|
|
|
1656 |
ls[i].apply(this, arguments);
|
|
|
1657 |
}
|
|
|
1658 |
}
|
|
|
1659 |
// return value comes from original target function
|
|
|
1660 |
return r;
|
|
|
1661 |
}
|
|
|
1662 |
},
|
|
|
1663 |
// add a listener to an object
|
|
|
1664 |
add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
|
|
|
1665 |
// Whenever 'method' is invoked, 'listener' will have the same scope.
|
|
|
1666 |
// Trying to supporting a context object for the listener led to
|
|
|
1667 |
// complexity.
|
|
|
1668 |
// Non trivial to provide 'once' functionality here
|
|
|
1669 |
// because listener could be the result of a dojo.hitch call,
|
|
|
1670 |
// in which case two references to the same hitch target would not
|
|
|
1671 |
// be equivalent.
|
|
|
1672 |
source = source || dojo.global;
|
|
|
1673 |
// The source method is either null, a dispatcher, or some other function
|
|
|
1674 |
var f = source[method];
|
|
|
1675 |
// Ensure a dispatcher
|
|
|
1676 |
if(!f||!f._listeners){
|
|
|
1677 |
var d = dojo._listener.getDispatcher();
|
|
|
1678 |
// original target function is special
|
|
|
1679 |
d.target = f;
|
|
|
1680 |
// dispatcher holds a list of listeners
|
|
|
1681 |
d._listeners = [];
|
|
|
1682 |
// redirect source to dispatcher
|
|
|
1683 |
f = source[method] = d;
|
|
|
1684 |
}
|
|
|
1685 |
// The contract is that a handle is returned that can
|
|
|
1686 |
// identify this listener for disconnect.
|
|
|
1687 |
//
|
|
|
1688 |
// The type of the handle is private. Here is it implemented as Integer.
|
|
|
1689 |
// DOM event code has this same contract but handle is Function
|
|
|
1690 |
// in non-IE browsers.
|
|
|
1691 |
//
|
|
|
1692 |
// We could have separate lists of before and after listeners.
|
|
|
1693 |
return f._listeners.push(listener) ; /*Handle*/
|
|
|
1694 |
},
|
|
|
1695 |
// remove a listener from an object
|
|
|
1696 |
remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
|
|
|
1697 |
var f = (source||dojo.global)[method];
|
|
|
1698 |
// remember that handle is the index+1 (0 is not a valid handle)
|
|
|
1699 |
if(f && f._listeners && handle--){
|
|
|
1700 |
delete f._listeners[handle];
|
|
|
1701 |
}
|
|
|
1702 |
}
|
|
|
1703 |
};
|
|
|
1704 |
|
|
|
1705 |
// Multiple delegation for arbitrary methods.
|
|
|
1706 |
|
|
|
1707 |
// This unit knows nothing about DOM,
|
|
|
1708 |
// but we include DOM aware
|
|
|
1709 |
// documentation and dontFix
|
|
|
1710 |
// argument here to help the autodocs.
|
|
|
1711 |
// Actual DOM aware code is in event.js.
|
|
|
1712 |
|
|
|
1713 |
dojo.connect = function(/*Object|null*/ obj,
|
|
|
1714 |
/*String*/ event,
|
|
|
1715 |
/*Object|null*/ context,
|
|
|
1716 |
/*String|Function*/ method,
|
|
|
1717 |
/*Boolean*/ dontFix){
|
|
|
1718 |
// summary:
|
|
|
1719 |
// Create a link that calls one function when another executes.
|
|
|
1720 |
//
|
|
|
1721 |
// description:
|
|
|
1722 |
// Connects method to event, so that after event fires, method
|
|
|
1723 |
// does too. All connected functions are passed the same arguments as
|
|
|
1724 |
// the event function was initially called with. You may connect as
|
|
|
1725 |
// many methods to event as needed.
|
|
|
1726 |
//
|
|
|
1727 |
// event must be a string. If obj is null, dojo.global is used.
|
|
|
1728 |
//
|
|
|
1729 |
// null arguments may simply be omitted.
|
|
|
1730 |
//
|
|
|
1731 |
// obj[event] can resolve to a function or undefined (null).
|
|
|
1732 |
// If obj[event] is null, it is assigned a function.
|
|
|
1733 |
//
|
|
|
1734 |
// The return value is a handle that is needed to
|
|
|
1735 |
// remove this connection with dojo.disconnect.
|
|
|
1736 |
//
|
|
|
1737 |
// obj:
|
|
|
1738 |
// The source object for the event function.
|
|
|
1739 |
// Defaults to dojo.global if null.
|
|
|
1740 |
// If obj is a DOM node, the connection is delegated
|
|
|
1741 |
// to the DOM event manager (unless dontFix is true).
|
|
|
1742 |
//
|
|
|
1743 |
// event:
|
|
|
1744 |
// String name of the event function in obj.
|
|
|
1745 |
// I.e. identifies a property obj[event].
|
|
|
1746 |
//
|
|
|
1747 |
// context:
|
|
|
1748 |
// The object that method will receive as "this".
|
|
|
1749 |
//
|
|
|
1750 |
// If context is null and method is a function, then method
|
|
|
1751 |
// inherits the context of event.
|
|
|
1752 |
//
|
|
|
1753 |
// If method is a string then context must be the source
|
|
|
1754 |
// object object for method (context[method]). If context is null,
|
|
|
1755 |
// dojo.global is used.
|
|
|
1756 |
//
|
|
|
1757 |
// method:
|
|
|
1758 |
// A function reference, or name of a function in context.
|
|
|
1759 |
// The function identified by method fires after event does.
|
|
|
1760 |
// method receives the same arguments as the event.
|
|
|
1761 |
// See context argument comments for information on method's scope.
|
|
|
1762 |
//
|
|
|
1763 |
// dontFix:
|
|
|
1764 |
// If obj is a DOM node, set dontFix to true to prevent delegation
|
|
|
1765 |
// of this connection to the DOM event manager.
|
|
|
1766 |
//
|
|
|
1767 |
// example:
|
|
|
1768 |
// When obj.onchange(), do ui.update():
|
|
|
1769 |
// | dojo.connect(obj, "onchange", ui, "update");
|
|
|
1770 |
// | dojo.connect(obj, "onchange", ui, ui.update); // same
|
|
|
1771 |
//
|
|
|
1772 |
// example:
|
|
|
1773 |
// Using return value for disconnect:
|
|
|
1774 |
// | var link = dojo.connect(obj, "onchange", ui, "update");
|
|
|
1775 |
// | ...
|
|
|
1776 |
// | dojo.disconnect(link);
|
|
|
1777 |
//
|
|
|
1778 |
// example:
|
|
|
1779 |
// When onglobalevent executes, watcher.handler is invoked:
|
|
|
1780 |
// | dojo.connect(null, "onglobalevent", watcher, "handler");
|
|
|
1781 |
//
|
|
|
1782 |
// example:
|
|
|
1783 |
// When ob.onCustomEvent executes, customEventHandler is invoked:
|
|
|
1784 |
// | dojo.connect(ob, "onCustomEvent", null, "customEventHandler");
|
|
|
1785 |
// | dojo.connect(ob, "onCustomEvent", "customEventHandler"); // same
|
|
|
1786 |
//
|
|
|
1787 |
// example:
|
|
|
1788 |
// When ob.onCustomEvent executes, customEventHandler is invoked
|
|
|
1789 |
// with the same scope (this):
|
|
|
1790 |
// | dojo.connect(ob, "onCustomEvent", null, customEventHandler);
|
|
|
1791 |
// | dojo.connect(ob, "onCustomEvent", customEventHandler); // same
|
|
|
1792 |
//
|
|
|
1793 |
// example:
|
|
|
1794 |
// When globalEvent executes, globalHandler is invoked
|
|
|
1795 |
// with the same scope (this):
|
|
|
1796 |
// | dojo.connect(null, "globalEvent", null, globalHandler);
|
|
|
1797 |
// | dojo.connect("globalEvent", globalHandler); // same
|
|
|
1798 |
|
|
|
1799 |
// normalize arguments
|
|
|
1800 |
var a=arguments, args=[], i=0;
|
|
|
1801 |
// if a[0] is a String, obj was ommited
|
|
|
1802 |
args.push(dojo.isString(a[0]) ? null : a[i++], a[i++]);
|
|
|
1803 |
// if the arg-after-next is a String or Function, context was NOT omitted
|
|
|
1804 |
var a1 = a[i+1];
|
|
|
1805 |
args.push(dojo.isString(a1)||dojo.isFunction(a1) ? a[i++] : null, a[i++]);
|
|
|
1806 |
// absorb any additional arguments
|
|
|
1807 |
for(var l=a.length; i<l; i++){ args.push(a[i]); }
|
|
|
1808 |
// do the actual work
|
|
|
1809 |
return dojo._connect.apply(this, args); /*Handle*/
|
|
|
1810 |
}
|
|
|
1811 |
|
|
|
1812 |
// used by non-browser hostenvs. always overriden by event.js
|
|
|
1813 |
dojo._connect = function(obj, event, context, method){
|
|
|
1814 |
var l=dojo._listener, h=l.add(obj, event, dojo.hitch(context, method));
|
|
|
1815 |
return [obj, event, h, l]; // Handle
|
|
|
1816 |
}
|
|
|
1817 |
|
|
|
1818 |
dojo.disconnect = function(/*Handle*/ handle){
|
|
|
1819 |
// summary:
|
|
|
1820 |
// Remove a link created by dojo.connect.
|
|
|
1821 |
// description:
|
|
|
1822 |
// Removes the connection between event and the method referenced by handle.
|
|
|
1823 |
// handle:
|
|
|
1824 |
// the return value of the dojo.connect call that created the connection.
|
|
|
1825 |
if(handle && handle[0] !== undefined){
|
|
|
1826 |
dojo._disconnect.apply(this, handle);
|
|
|
1827 |
// let's not keep this reference
|
|
|
1828 |
delete handle[0];
|
|
|
1829 |
}
|
|
|
1830 |
}
|
|
|
1831 |
|
|
|
1832 |
dojo._disconnect = function(obj, event, handle, listener){
|
|
|
1833 |
listener.remove(obj, event, handle);
|
|
|
1834 |
}
|
|
|
1835 |
|
|
|
1836 |
// topic publish/subscribe
|
|
|
1837 |
|
|
|
1838 |
dojo._topics = {};
|
|
|
1839 |
|
|
|
1840 |
dojo.subscribe = function(/*String*/ topic, /*Object|null*/ context, /*String|Function*/ method){
|
|
|
1841 |
// summary:
|
|
|
1842 |
// Attach a listener to a named topic. The listener function is invoked whenever the
|
|
|
1843 |
// named topic is published (see: dojo.publish).
|
|
|
1844 |
// Returns a handle which is needed to unsubscribe this listener.
|
|
|
1845 |
// context:
|
|
|
1846 |
// Scope in which method will be invoked, or null for default scope.
|
|
|
1847 |
// method:
|
|
|
1848 |
// The name of a function in context, or a function reference. This is the function that
|
|
|
1849 |
// is invoked when topic is published.
|
|
|
1850 |
// example:
|
|
|
1851 |
// | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
|
|
|
1852 |
// | dojo.publish("alerts", [ "read this", "hello world" ]);
|
|
|
1853 |
|
|
|
1854 |
// support for 2 argument invocation (omitting context) depends on hitch
|
|
|
1855 |
return [topic, dojo._listener.add(dojo._topics, topic, dojo.hitch(context, method))]; /*Handle*/
|
|
|
1856 |
}
|
|
|
1857 |
|
|
|
1858 |
dojo.unsubscribe = function(/*Handle*/ handle){
|
|
|
1859 |
// summary:
|
|
|
1860 |
// Remove a topic listener.
|
|
|
1861 |
// handle:
|
|
|
1862 |
// The handle returned from a call to subscribe.
|
|
|
1863 |
// example:
|
|
|
1864 |
// | var alerter = dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
|
|
|
1865 |
// | ...
|
|
|
1866 |
// | dojo.unsubscribe(alerter);
|
|
|
1867 |
if(handle){
|
|
|
1868 |
dojo._listener.remove(dojo._topics, handle[0], handle[1]);
|
|
|
1869 |
}
|
|
|
1870 |
}
|
|
|
1871 |
|
|
|
1872 |
dojo.publish = function(/*String*/ topic, /*Array*/ args){
|
|
|
1873 |
// summary:
|
|
|
1874 |
// Invoke all listener method subscribed to topic.
|
|
|
1875 |
// topic:
|
|
|
1876 |
// The name of the topic to publish.
|
|
|
1877 |
// args:
|
|
|
1878 |
// An array of arguments. The arguments will be applied
|
|
|
1879 |
// to each topic subscriber (as first class parameters, via apply).
|
|
|
1880 |
// example:
|
|
|
1881 |
// | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
|
|
|
1882 |
// | dojo.publish("alerts", [ "read this", "hello world" ]);
|
|
|
1883 |
|
|
|
1884 |
// Note that args is an array, which is more efficient vs variable length
|
|
|
1885 |
// argument list. Ideally, var args would be implemented via Array
|
|
|
1886 |
// throughout the APIs.
|
|
|
1887 |
var f = dojo._topics[topic];
|
|
|
1888 |
if(f){
|
|
|
1889 |
f.apply(this, args||[]);
|
|
|
1890 |
}
|
|
|
1891 |
}
|
|
|
1892 |
|
|
|
1893 |
dojo.connectPublisher = function( /*String*/ topic,
|
|
|
1894 |
/*Object|null*/ obj,
|
|
|
1895 |
/*String*/ event){
|
|
|
1896 |
// summary:
|
|
|
1897 |
// Ensure that everytime obj.event() is called, a message is published
|
|
|
1898 |
// on the topic. Returns a handle which can be passed to
|
|
|
1899 |
// dojo.disconnect() to disable subsequent automatic publication on
|
|
|
1900 |
// the topic.
|
|
|
1901 |
// topic:
|
|
|
1902 |
// The name of the topic to publish.
|
|
|
1903 |
// obj:
|
|
|
1904 |
// The source object for the event function. Defaults to dojo.global
|
|
|
1905 |
// if null.
|
|
|
1906 |
// event:
|
|
|
1907 |
// The name of the event function in obj.
|
|
|
1908 |
// I.e. identifies a property obj[event].
|
|
|
1909 |
// example:
|
|
|
1910 |
// | dojo.connectPublisher("/ajax/start", dojo, "xhrGet"};
|
|
|
1911 |
var pf = function(){ dojo.publish(topic, arguments); }
|
|
|
1912 |
return (event) ? dojo.connect(obj, event, pf) : dojo.connect(obj, pf); //Handle
|
|
|
1913 |
};
|
|
|
1914 |
|
|
|
1915 |
}
|
|
|
1916 |
|
|
|
1917 |
if(!dojo._hasResource["dojo._base.Deferred"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
1918 |
dojo._hasResource["dojo._base.Deferred"] = true;
|
|
|
1919 |
dojo.provide("dojo._base.Deferred");
|
|
|
1920 |
|
|
|
1921 |
|
|
|
1922 |
dojo.Deferred = function(/*Function?*/ canceller){
|
|
|
1923 |
// summary:
|
|
|
1924 |
// Encapsulates a sequence of callbacks in response to a value that
|
|
|
1925 |
// may not yet be available. This is modeled after the Deferred class
|
|
|
1926 |
// from Twisted <http://twistedmatrix.com>.
|
|
|
1927 |
// description:
|
|
|
1928 |
// JavaScript has no threads, and even if it did, threads are hard.
|
|
|
1929 |
// Deferreds are a way of abstracting non-blocking events, such as the
|
|
|
1930 |
// final response to an XMLHttpRequest. Deferreds create a promise to
|
|
|
1931 |
// return a response a some point in the future and an easy way to
|
|
|
1932 |
// register your interest in receiving that response.
|
|
|
1933 |
//
|
|
|
1934 |
// The most important methods for Deffered users are:
|
|
|
1935 |
//
|
|
|
1936 |
// * addCallback(handler)
|
|
|
1937 |
// * addErrback(handler)
|
|
|
1938 |
// * callback(result)
|
|
|
1939 |
// * errback(result)
|
|
|
1940 |
//
|
|
|
1941 |
// In general, when a function returns a Deferred, users then "fill
|
|
|
1942 |
// in" the second half of the contract by registering callbacks and
|
|
|
1943 |
// error handlers. You may register as many callback and errback
|
|
|
1944 |
// handlers as you like and they will be executed in the order
|
|
|
1945 |
// registered when a result is provided. Usually this result is
|
|
|
1946 |
// provided as the result of an asynchronous operation. The code
|
|
|
1947 |
// "managing" the Deferred (the code that made the promise to provide
|
|
|
1948 |
// an answer later) will use the callback() and errback() methods to
|
|
|
1949 |
// communicate with registered listeners about the result of the
|
|
|
1950 |
// operation. At this time, all registered result handlers are called
|
|
|
1951 |
// *with the most recent result value*.
|
|
|
1952 |
//
|
|
|
1953 |
// Deferred callback handlers are treated as a chain, and each item in
|
|
|
1954 |
// the chain is required to return a value that will be fed into
|
|
|
1955 |
// successive handlers. The most minimal callback may be registered
|
|
|
1956 |
// like this:
|
|
|
1957 |
//
|
|
|
1958 |
// | var d = new dojo.Deferred();
|
|
|
1959 |
// | d.addCallback(function(result){ return result; });
|
|
|
1960 |
//
|
|
|
1961 |
// Perhaps the most common mistake when first using Deferreds is to
|
|
|
1962 |
// forget to return a value (in most cases, the value you were
|
|
|
1963 |
// passed).
|
|
|
1964 |
//
|
|
|
1965 |
// The sequence of callbacks is internally represented as a list of
|
|
|
1966 |
// 2-tuples containing the callback/errback pair. For example, the
|
|
|
1967 |
// following call sequence:
|
|
|
1968 |
//
|
|
|
1969 |
// | var d = new dojo.Deferred();
|
|
|
1970 |
// | d.addCallback(myCallback);
|
|
|
1971 |
// | d.addErrback(myErrback);
|
|
|
1972 |
// | d.addBoth(myBoth);
|
|
|
1973 |
// | d.addCallbacks(myCallback, myErrback);
|
|
|
1974 |
//
|
|
|
1975 |
// is translated into a Deferred with the following internal
|
|
|
1976 |
// representation:
|
|
|
1977 |
//
|
|
|
1978 |
// | [
|
|
|
1979 |
// | [myCallback, null],
|
|
|
1980 |
// | [null, myErrback],
|
|
|
1981 |
// | [myBoth, myBoth],
|
|
|
1982 |
// | [myCallback, myErrback]
|
|
|
1983 |
// | ]
|
|
|
1984 |
//
|
|
|
1985 |
// The Deferred also keeps track of its current status (fired). Its
|
|
|
1986 |
// status may be one of three things:
|
|
|
1987 |
//
|
|
|
1988 |
// * -1: no value yet (initial condition)
|
|
|
1989 |
// * 0: success
|
|
|
1990 |
// * 1: error
|
|
|
1991 |
//
|
|
|
1992 |
// A Deferred will be in the error state if one of the following three
|
|
|
1993 |
// conditions are met:
|
|
|
1994 |
//
|
|
|
1995 |
// 1. The result given to callback or errback is "instanceof" Error
|
|
|
1996 |
// 2. The previous callback or errback raised an exception while
|
|
|
1997 |
// executing
|
|
|
1998 |
// 3. The previous callback or errback returned a value
|
|
|
1999 |
// "instanceof" Error
|
|
|
2000 |
//
|
|
|
2001 |
// Otherwise, the Deferred will be in the success state. The state of
|
|
|
2002 |
// the Deferred determines the next element in the callback sequence
|
|
|
2003 |
// to run.
|
|
|
2004 |
//
|
|
|
2005 |
// When a callback or errback occurs with the example deferred chain,
|
|
|
2006 |
// something equivalent to the following will happen (imagine
|
|
|
2007 |
// that exceptions are caught and returned):
|
|
|
2008 |
//
|
|
|
2009 |
// | // d.callback(result) or d.errback(result)
|
|
|
2010 |
// | if(!(result instanceof Error)){
|
|
|
2011 |
// | result = myCallback(result);
|
|
|
2012 |
// | }
|
|
|
2013 |
// | if(result instanceof Error){
|
|
|
2014 |
// | result = myErrback(result);
|
|
|
2015 |
// | }
|
|
|
2016 |
// | result = myBoth(result);
|
|
|
2017 |
// | if(result instanceof Error){
|
|
|
2018 |
// | result = myErrback(result);
|
|
|
2019 |
// | }else{
|
|
|
2020 |
// | result = myCallback(result);
|
|
|
2021 |
// | }
|
|
|
2022 |
//
|
|
|
2023 |
// The result is then stored away in case another step is added to the
|
|
|
2024 |
// callback sequence. Since the Deferred already has a value
|
|
|
2025 |
// available, any new callbacks added will be called immediately.
|
|
|
2026 |
//
|
|
|
2027 |
// There are two other "advanced" details about this implementation
|
|
|
2028 |
// that are useful:
|
|
|
2029 |
//
|
|
|
2030 |
// Callbacks are allowed to return Deferred instances themselves, so
|
|
|
2031 |
// you can build complicated sequences of events with ease.
|
|
|
2032 |
//
|
|
|
2033 |
// The creator of the Deferred may specify a canceller. The canceller
|
|
|
2034 |
// is a function that will be called if Deferred.cancel is called
|
|
|
2035 |
// before the Deferred fires. You can use this to implement clean
|
|
|
2036 |
// aborting of an XMLHttpRequest, etc. Note that cancel will fire the
|
|
|
2037 |
// deferred with a CancelledError (unless your canceller returns
|
|
|
2038 |
// another kind of error), so the errbacks should be prepared to
|
|
|
2039 |
// handle that error for cancellable Deferreds.
|
|
|
2040 |
// example:
|
|
|
2041 |
// | var deferred = new dojo.Deferred();
|
|
|
2042 |
// | setTimeout(function(){ deferred.callback({success: true}); }, 1000);
|
|
|
2043 |
// | return deferred;
|
|
|
2044 |
// example:
|
|
|
2045 |
// Deferred objects are often used when making code asynchronous. It
|
|
|
2046 |
// may be easiest to write functions in a synchronous manner and then
|
|
|
2047 |
// split code using a deferred to trigger a response to a long-lived
|
|
|
2048 |
// operation. For example, instead of register a callback function to
|
|
|
2049 |
// denote when a rendering operation completes, the function can
|
|
|
2050 |
// simply return a deferred:
|
|
|
2051 |
//
|
|
|
2052 |
// | // callback style:
|
|
|
2053 |
// | function renderLotsOfData(data, callback){
|
|
|
2054 |
// | var success = false
|
|
|
2055 |
// | try{
|
|
|
2056 |
// | for(var x in data){
|
|
|
2057 |
// | renderDataitem(data[x]);
|
|
|
2058 |
// | }
|
|
|
2059 |
// | success = true;
|
|
|
2060 |
// | }catch(e){ }
|
|
|
2061 |
// | if(callback){
|
|
|
2062 |
// | callback(success);
|
|
|
2063 |
// | }
|
|
|
2064 |
// | }
|
|
|
2065 |
//
|
|
|
2066 |
// | // using callback style
|
|
|
2067 |
// | renderLotsOfData(someDataObj, function(success){
|
|
|
2068 |
// | // handles success or failure
|
|
|
2069 |
// | if(!success){
|
|
|
2070 |
// | promptUserToRecover();
|
|
|
2071 |
// | }
|
|
|
2072 |
// | });
|
|
|
2073 |
// | // NOTE: no way to add another callback here!!
|
|
|
2074 |
// example:
|
|
|
2075 |
// Using a Deferred doesn't simplify the sending code any, but it
|
|
|
2076 |
// provides a standard interface for callers and senders alike,
|
|
|
2077 |
// providing both with a simple way to service multiple callbacks for
|
|
|
2078 |
// an operation and freeing both sides from worrying about details
|
|
|
2079 |
// such as "did this get called already?". With Deferreds, new
|
|
|
2080 |
// callbacks can be added at any time.
|
|
|
2081 |
//
|
|
|
2082 |
// | // Deferred style:
|
|
|
2083 |
// | function renderLotsOfData(data){
|
|
|
2084 |
// | var d = new dojo.Deferred();
|
|
|
2085 |
// | try{
|
|
|
2086 |
// | for(var x in data){
|
|
|
2087 |
// | renderDataitem(data[x]);
|
|
|
2088 |
// | }
|
|
|
2089 |
// | d.callback(true);
|
|
|
2090 |
// | }catch(e){
|
|
|
2091 |
// | d.errback(new Error("rendering failed"));
|
|
|
2092 |
// | }
|
|
|
2093 |
// | return d;
|
|
|
2094 |
// | }
|
|
|
2095 |
//
|
|
|
2096 |
// | // using Deferred style
|
|
|
2097 |
// | renderLotsOfData(someDataObj).addErrback(function(){
|
|
|
2098 |
// | promptUserToRecover();
|
|
|
2099 |
// | });
|
|
|
2100 |
// | // NOTE: addErrback and addCallback both return the Deferred
|
|
|
2101 |
// | // again, so we could chain adding callbacks or save the
|
|
|
2102 |
// | // deferred for later should we need to be notified again.
|
|
|
2103 |
// example:
|
|
|
2104 |
// In this example, renderLotsOfData is syncrhonous and so both
|
|
|
2105 |
// versions are pretty artificial. Putting the data display on a
|
|
|
2106 |
// timeout helps show why Deferreds rock:
|
|
|
2107 |
//
|
|
|
2108 |
// | // Deferred style and async func
|
|
|
2109 |
// | function renderLotsOfData(data){
|
|
|
2110 |
// | var d = new dojo.Deferred();
|
|
|
2111 |
// | setTimeout(function(){
|
|
|
2112 |
// | try{
|
|
|
2113 |
// | for(var x in data){
|
|
|
2114 |
// | renderDataitem(data[x]);
|
|
|
2115 |
// | }
|
|
|
2116 |
// | d.callback(true);
|
|
|
2117 |
// | }catch(e){
|
|
|
2118 |
// | d.errback(new Error("rendering failed"));
|
|
|
2119 |
// | }
|
|
|
2120 |
// | }, 100);
|
|
|
2121 |
// | return d;
|
|
|
2122 |
// | }
|
|
|
2123 |
//
|
|
|
2124 |
// | // using Deferred style
|
|
|
2125 |
// | renderLotsOfData(someDataObj).addErrback(function(){
|
|
|
2126 |
// | promptUserToRecover();
|
|
|
2127 |
// | });
|
|
|
2128 |
//
|
|
|
2129 |
// Note that the caller doesn't have to change his code at all to
|
|
|
2130 |
// handle the asynchronous case.
|
|
|
2131 |
|
|
|
2132 |
this.chain = [];
|
|
|
2133 |
this.id = this._nextId();
|
|
|
2134 |
this.fired = -1;
|
|
|
2135 |
this.paused = 0;
|
|
|
2136 |
this.results = [null, null];
|
|
|
2137 |
this.canceller = canceller;
|
|
|
2138 |
this.silentlyCancelled = false;
|
|
|
2139 |
};
|
|
|
2140 |
|
|
|
2141 |
dojo.extend(dojo.Deferred, {
|
|
|
2142 |
/*
|
|
|
2143 |
makeCalled: function(){
|
|
|
2144 |
// summary:
|
|
|
2145 |
// returns a new, empty deferred, which is already in the called
|
|
|
2146 |
// state. Calling callback() or errback() on this deferred will
|
|
|
2147 |
// yeild an error and adding new handlers to it will result in
|
|
|
2148 |
// them being called immediately.
|
|
|
2149 |
var deferred = new dojo.Deferred();
|
|
|
2150 |
deferred.callback();
|
|
|
2151 |
return deferred;
|
|
|
2152 |
},
|
|
|
2153 |
|
|
|
2154 |
toString: function(){
|
|
|
2155 |
var state;
|
|
|
2156 |
if(this.fired == -1){
|
|
|
2157 |
state = 'unfired';
|
|
|
2158 |
}else{
|
|
|
2159 |
state = this.fired ? 'success' : 'error';
|
|
|
2160 |
}
|
|
|
2161 |
return 'Deferred(' + this.id + ', ' + state + ')';
|
|
|
2162 |
},
|
|
|
2163 |
*/
|
|
|
2164 |
|
|
|
2165 |
_nextId: (function(){
|
|
|
2166 |
var n = 1;
|
|
|
2167 |
return function(){ return n++; };
|
|
|
2168 |
})(),
|
|
|
2169 |
|
|
|
2170 |
cancel: function(){
|
|
|
2171 |
// summary:
|
|
|
2172 |
// Cancels a Deferred that has not yet received a value, or is
|
|
|
2173 |
// waiting on another Deferred as its value.
|
|
|
2174 |
// description:
|
|
|
2175 |
// If a canceller is defined, the canceller is called. If the
|
|
|
2176 |
// canceller did not return an error, or there was no canceller,
|
|
|
2177 |
// then the errback chain is started.
|
|
|
2178 |
var err;
|
|
|
2179 |
if(this.fired == -1){
|
|
|
2180 |
if(this.canceller){
|
|
|
2181 |
err = this.canceller(this);
|
|
|
2182 |
}else{
|
|
|
2183 |
this.silentlyCancelled = true;
|
|
|
2184 |
}
|
|
|
2185 |
if(this.fired == -1){
|
|
|
2186 |
if(!(err instanceof Error)){
|
|
|
2187 |
var res = err;
|
|
|
2188 |
err = new Error("Deferred Cancelled");
|
|
|
2189 |
err.dojoType = "cancel";
|
|
|
2190 |
err.cancelResult = res;
|
|
|
2191 |
}
|
|
|
2192 |
this.errback(err);
|
|
|
2193 |
}
|
|
|
2194 |
}else if( (this.fired == 0) &&
|
|
|
2195 |
(this.results[0] instanceof dojo.Deferred)
|
|
|
2196 |
){
|
|
|
2197 |
this.results[0].cancel();
|
|
|
2198 |
}
|
|
|
2199 |
},
|
|
|
2200 |
|
|
|
2201 |
|
|
|
2202 |
_resback: function(res){
|
|
|
2203 |
// summary:
|
|
|
2204 |
// The private primitive that means either callback or errback
|
|
|
2205 |
this.fired = ((res instanceof Error) ? 1 : 0);
|
|
|
2206 |
this.results[this.fired] = res;
|
|
|
2207 |
this._fire();
|
|
|
2208 |
},
|
|
|
2209 |
|
|
|
2210 |
_check: function(){
|
|
|
2211 |
if(this.fired != -1){
|
|
|
2212 |
if(!this.silentlyCancelled){
|
|
|
2213 |
throw new Error("already called!");
|
|
|
2214 |
}
|
|
|
2215 |
this.silentlyCancelled = false;
|
|
|
2216 |
return;
|
|
|
2217 |
}
|
|
|
2218 |
},
|
|
|
2219 |
|
|
|
2220 |
callback: function(res){
|
|
|
2221 |
// summary: Begin the callback sequence with a non-error value.
|
|
|
2222 |
|
|
|
2223 |
/*
|
|
|
2224 |
callback or errback should only be called once on a given
|
|
|
2225 |
Deferred.
|
|
|
2226 |
*/
|
|
|
2227 |
this._check();
|
|
|
2228 |
this._resback(res);
|
|
|
2229 |
},
|
|
|
2230 |
|
|
|
2231 |
errback: function(/*Error*/res){
|
|
|
2232 |
// summary:
|
|
|
2233 |
// Begin the callback sequence with an error result.
|
|
|
2234 |
this._check();
|
|
|
2235 |
if(!(res instanceof Error)){
|
|
|
2236 |
res = new Error(res);
|
|
|
2237 |
}
|
|
|
2238 |
this._resback(res);
|
|
|
2239 |
},
|
|
|
2240 |
|
|
|
2241 |
addBoth: function(/*Function||Object*/cb, /*Optional, String*/cbfn){
|
|
|
2242 |
// summary:
|
|
|
2243 |
// Add the same function as both a callback and an errback as the
|
|
|
2244 |
// next element on the callback sequence. This is useful for code
|
|
|
2245 |
// that you want to guarantee to run, e.g. a finalizer.
|
|
|
2246 |
var enclosed = dojo.hitch(cb, cbfn);
|
|
|
2247 |
if(arguments.length > 2){
|
|
|
2248 |
enclosed = dojo.partial(enclosed, arguments, 2);
|
|
|
2249 |
}
|
|
|
2250 |
return this.addCallbacks(enclosed, enclosed);
|
|
|
2251 |
},
|
|
|
2252 |
|
|
|
2253 |
addCallback: function(cb, cbfn){
|
|
|
2254 |
// summary:
|
|
|
2255 |
// Add a single callback to the end of the callback sequence.
|
|
|
2256 |
var enclosed = dojo.hitch(cb, cbfn);
|
|
|
2257 |
if(arguments.length > 2){
|
|
|
2258 |
enclosed = dojo.partial(enclosed, arguments, 2);
|
|
|
2259 |
}
|
|
|
2260 |
return this.addCallbacks(enclosed, null);
|
|
|
2261 |
},
|
|
|
2262 |
|
|
|
2263 |
addErrback: function(cb, cbfn){
|
|
|
2264 |
// summary:
|
|
|
2265 |
// Add a single callback to the end of the callback sequence.
|
|
|
2266 |
var enclosed = dojo.hitch(cb, cbfn);
|
|
|
2267 |
if(arguments.length > 2){
|
|
|
2268 |
enclosed = dojo.partial(enclosed, arguments, 2);
|
|
|
2269 |
}
|
|
|
2270 |
return this.addCallbacks(null, enclosed);
|
|
|
2271 |
},
|
|
|
2272 |
|
|
|
2273 |
addCallbacks: function(cb, eb){
|
|
|
2274 |
// summary:
|
|
|
2275 |
// Add separate callback and errback to the end of the callback
|
|
|
2276 |
// sequence.
|
|
|
2277 |
this.chain.push([cb, eb])
|
|
|
2278 |
if(this.fired >= 0){
|
|
|
2279 |
this._fire();
|
|
|
2280 |
}
|
|
|
2281 |
return this;
|
|
|
2282 |
},
|
|
|
2283 |
|
|
|
2284 |
_fire: function(){
|
|
|
2285 |
// summary:
|
|
|
2286 |
// Used internally to exhaust the callback sequence when a result
|
|
|
2287 |
// is available.
|
|
|
2288 |
var chain = this.chain;
|
|
|
2289 |
var fired = this.fired;
|
|
|
2290 |
var res = this.results[fired];
|
|
|
2291 |
var self = this;
|
|
|
2292 |
var cb = null;
|
|
|
2293 |
while(
|
|
|
2294 |
(chain.length > 0) &&
|
|
|
2295 |
(this.paused == 0)
|
|
|
2296 |
){
|
|
|
2297 |
// Array
|
|
|
2298 |
var f = chain.shift()[fired];
|
|
|
2299 |
if(!f){ continue; }
|
|
|
2300 |
try{
|
|
|
2301 |
res = f(res);
|
|
|
2302 |
fired = ((res instanceof Error) ? 1 : 0);
|
|
|
2303 |
if(res instanceof dojo.Deferred){
|
|
|
2304 |
cb = function(res){
|
|
|
2305 |
self._resback(res);
|
|
|
2306 |
// inlined from _pause()
|
|
|
2307 |
self.paused--;
|
|
|
2308 |
if(
|
|
|
2309 |
(self.paused == 0) &&
|
|
|
2310 |
(self.fired >= 0)
|
|
|
2311 |
){
|
|
|
2312 |
self._fire();
|
|
|
2313 |
}
|
|
|
2314 |
}
|
|
|
2315 |
// inlined from _unpause
|
|
|
2316 |
this.paused++;
|
|
|
2317 |
}
|
|
|
2318 |
}catch(err){
|
|
|
2319 |
console.debug(err);
|
|
|
2320 |
fired = 1;
|
|
|
2321 |
res = err;
|
|
|
2322 |
}
|
|
|
2323 |
}
|
|
|
2324 |
this.fired = fired;
|
|
|
2325 |
this.results[fired] = res;
|
|
|
2326 |
if((cb)&&(this.paused)){
|
|
|
2327 |
// this is for "tail recursion" in case the dependent
|
|
|
2328 |
// deferred is already fired
|
|
|
2329 |
res.addBoth(cb);
|
|
|
2330 |
}
|
|
|
2331 |
}
|
|
|
2332 |
});
|
|
|
2333 |
|
|
|
2334 |
}
|
|
|
2335 |
|
|
|
2336 |
if(!dojo._hasResource["dojo._base.json"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
2337 |
dojo._hasResource["dojo._base.json"] = true;
|
|
|
2338 |
dojo.provide("dojo._base.json");
|
|
|
2339 |
|
|
|
2340 |
dojo.fromJson = function(/*String*/ json){
|
|
|
2341 |
// summary:
|
|
|
2342 |
// evaluates the passed string-form of a JSON object
|
|
|
2343 |
// json:
|
|
|
2344 |
// a string literal of a JSON item, for instance:
|
|
|
2345 |
// '{ "foo": [ "bar", 1, { "baz": "thud" } ] }'
|
|
|
2346 |
// return:
|
|
|
2347 |
// An object, the result of the evaluation
|
|
|
2348 |
|
|
|
2349 |
// FIXME: should this accept mozilla's optional second arg?
|
|
|
2350 |
try {
|
|
|
2351 |
return eval("(" + json + ")");
|
|
|
2352 |
}catch(e){
|
|
|
2353 |
console.debug(e);
|
|
|
2354 |
return json;
|
|
|
2355 |
}
|
|
|
2356 |
}
|
|
|
2357 |
|
|
|
2358 |
dojo._escapeString = function(/*String*/str){
|
|
|
2359 |
//summary:
|
|
|
2360 |
// Adds escape sequences for non-visual characters, double quote and
|
|
|
2361 |
// backslash and surrounds with double quotes to form a valid string
|
|
|
2362 |
// literal.
|
|
|
2363 |
return ('"' + str.replace(/(["\\])/g, '\\$1') + '"'
|
|
|
2364 |
).replace(/[\f]/g, "\\f"
|
|
|
2365 |
).replace(/[\b]/g, "\\b"
|
|
|
2366 |
).replace(/[\n]/g, "\\n"
|
|
|
2367 |
).replace(/[\t]/g, "\\t"
|
|
|
2368 |
).replace(/[\r]/g, "\\r"); // string
|
|
|
2369 |
}
|
|
|
2370 |
|
|
|
2371 |
dojo.toJsonIndentStr = "\t";
|
|
|
2372 |
dojo.toJson = function(/*Object*/ it, /*Boolean?*/ prettyPrint, /*String?*/ _indentStr){
|
|
|
2373 |
// summary:
|
|
|
2374 |
// Create a JSON serialization of an object.
|
|
|
2375 |
// Note that this doesn't check for infinite recursion, so don't do that!
|
|
|
2376 |
//
|
|
|
2377 |
// it:
|
|
|
2378 |
// an object to be serialized. Objects may define their own
|
|
|
2379 |
// serialization via a special "__json__" or "json" function
|
|
|
2380 |
// property. If a specialized serializer has been defined, it will
|
|
|
2381 |
// be used as a fallback.
|
|
|
2382 |
//
|
|
|
2383 |
// prettyPrint:
|
|
|
2384 |
// if true, we indent objects and arrays to make the output prettier.
|
|
|
2385 |
// The variable dojo.toJsonIndentStr is used as the indent string
|
|
|
2386 |
// -- to use something other than the default (tab),
|
|
|
2387 |
// change that variable before calling dojo.toJson().
|
|
|
2388 |
//
|
|
|
2389 |
// _indentStr:
|
|
|
2390 |
// private variable for recursive calls when pretty printing, do not use.
|
|
|
2391 |
//
|
|
|
2392 |
// return:
|
|
|
2393 |
// a String representing the serialized version of the passed object.
|
|
|
2394 |
|
|
|
2395 |
_indentStr = _indentStr || "";
|
|
|
2396 |
var nextIndent = (prettyPrint ? _indentStr + dojo.toJsonIndentStr : "");
|
|
|
2397 |
var newLine = (prettyPrint ? "\n" : "");
|
|
|
2398 |
var objtype = typeof(it);
|
|
|
2399 |
if(objtype == "undefined"){
|
|
|
2400 |
return "undefined";
|
|
|
2401 |
}else if((objtype == "number")||(objtype == "boolean")){
|
|
|
2402 |
return it + "";
|
|
|
2403 |
}else if(it === null){
|
|
|
2404 |
return "null";
|
|
|
2405 |
}
|
|
|
2406 |
if(dojo.isString(it)){
|
|
|
2407 |
return dojo._escapeString(it);
|
|
|
2408 |
}
|
|
|
2409 |
if(it.nodeType && it.cloneNode){ // isNode
|
|
|
2410 |
return ""; // FIXME: would something like outerHTML be better here?
|
|
|
2411 |
}
|
|
|
2412 |
// recurse
|
|
|
2413 |
var recurse = arguments.callee;
|
|
|
2414 |
// short-circuit for objects that support "json" serialization
|
|
|
2415 |
// if they return "self" then just pass-through...
|
|
|
2416 |
var newObj;
|
|
|
2417 |
if(typeof it.__json__ == "function"){
|
|
|
2418 |
newObj = it.__json__();
|
|
|
2419 |
if(it !== newObj){
|
|
|
2420 |
return recurse(newObj, prettyPrint, nextIndent);
|
|
|
2421 |
}
|
|
|
2422 |
}
|
|
|
2423 |
if(typeof it.json == "function"){
|
|
|
2424 |
newObj = it.json();
|
|
|
2425 |
if(it !== newObj){
|
|
|
2426 |
return recurse(newObj, prettyPrint, nextIndent);
|
|
|
2427 |
}
|
|
|
2428 |
}
|
|
|
2429 |
// array
|
|
|
2430 |
if(dojo.isArray(it)){
|
|
|
2431 |
var res = [];
|
|
|
2432 |
for(var i = 0; i < it.length; i++){
|
|
|
2433 |
var val = recurse(it[i], prettyPrint, nextIndent);
|
|
|
2434 |
if(typeof(val) != "string"){
|
|
|
2435 |
val = "undefined";
|
|
|
2436 |
}
|
|
|
2437 |
res.push(newLine + nextIndent + val);
|
|
|
2438 |
}
|
|
|
2439 |
return "[" + res.join(", ") + newLine + _indentStr + "]";
|
|
|
2440 |
}
|
|
|
2441 |
/*
|
|
|
2442 |
// look in the registry
|
|
|
2443 |
try {
|
|
|
2444 |
window.o = it;
|
|
|
2445 |
newObj = dojo.json.jsonRegistry.match(it);
|
|
|
2446 |
return recurse(newObj, prettyPrint, nextIndent);
|
|
|
2447 |
}catch(e){
|
|
|
2448 |
// console.debug(e);
|
|
|
2449 |
}
|
|
|
2450 |
// it's a function with no adapter, skip it
|
|
|
2451 |
*/
|
|
|
2452 |
if(objtype == "function"){
|
|
|
2453 |
return null;
|
|
|
2454 |
}
|
|
|
2455 |
// generic object code path
|
|
|
2456 |
var output = [];
|
|
|
2457 |
for(var key in it){
|
|
|
2458 |
var keyStr;
|
|
|
2459 |
if(typeof(key) == "number"){
|
|
|
2460 |
keyStr = '"' + key + '"';
|
|
|
2461 |
}else if(typeof(key) == "string"){
|
|
|
2462 |
keyStr = dojo._escapeString(key);
|
|
|
2463 |
}else{
|
|
|
2464 |
// skip non-string or number keys
|
|
|
2465 |
continue;
|
|
|
2466 |
}
|
|
|
2467 |
val = recurse(it[key], prettyPrint, nextIndent);
|
|
|
2468 |
if(typeof(val) != "string"){
|
|
|
2469 |
// skip non-serializable values
|
|
|
2470 |
continue;
|
|
|
2471 |
}
|
|
|
2472 |
// FIXME: use += on Moz!!
|
|
|
2473 |
// MOW NOTE: using += is a pain because you have to account for the dangling comma...
|
|
|
2474 |
output.push(newLine + nextIndent + keyStr + ": " + val);
|
|
|
2475 |
}
|
|
|
2476 |
return "{" + output.join(", ") + newLine + _indentStr + "}";
|
|
|
2477 |
}
|
|
|
2478 |
|
|
|
2479 |
}
|
|
|
2480 |
|
|
|
2481 |
if(!dojo._hasResource["dojo._base.array"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
2482 |
dojo._hasResource["dojo._base.array"] = true;
|
|
|
2483 |
|
|
|
2484 |
dojo.provide("dojo._base.array");
|
|
|
2485 |
|
|
|
2486 |
(function(){
|
|
|
2487 |
var _getParts = function(arr, obj, cb){
|
|
|
2488 |
return [
|
|
|
2489 |
(dojo.isString(arr) ? arr.split("") : arr),
|
|
|
2490 |
(obj||dojo.global),
|
|
|
2491 |
// FIXME: cache the anonymous functions we create here?
|
|
|
2492 |
(dojo.isString(cb) ? (new Function("item", "index", "array", cb)) : cb)
|
|
|
2493 |
];
|
|
|
2494 |
}
|
|
|
2495 |
|
|
|
2496 |
dojo.mixin(dojo, {
|
|
|
2497 |
indexOf: function( /*Array*/ array,
|
|
|
2498 |
/*Object*/ value,
|
|
|
2499 |
/*Integer?*/ fromIndex,
|
|
|
2500 |
/*Boolean?*/ findLast){
|
|
|
2501 |
// summary:
|
|
|
2502 |
// locates the first index of the provided value in the
|
|
|
2503 |
// passed array. If the value is not found, -1 is returned.
|
|
|
2504 |
// description:
|
|
|
2505 |
// For details on this method, see:
|
|
|
2506 |
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf
|
|
|
2507 |
|
|
|
2508 |
var i = 0, step = 1, end = array.length;
|
|
|
2509 |
if(findLast){
|
|
|
2510 |
i = end - 1;
|
|
|
2511 |
step = end = -1;
|
|
|
2512 |
}
|
|
|
2513 |
for(i = fromIndex || i; i != end; i += step){
|
|
|
2514 |
if(array[i] == value){ return i; }
|
|
|
2515 |
}
|
|
|
2516 |
return -1; // Number
|
|
|
2517 |
},
|
|
|
2518 |
|
|
|
2519 |
lastIndexOf: function(/*Array*/array, /*Object*/value, /*Integer?*/fromIndex){
|
|
|
2520 |
// summary:
|
|
|
2521 |
// locates the last index of the provided value in the passed array.
|
|
|
2522 |
// If the value is not found, -1 is returned.
|
|
|
2523 |
// description:
|
|
|
2524 |
// For details on this method, see:
|
|
|
2525 |
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf
|
|
|
2526 |
return dojo.indexOf(array, value, fromIndex, true); // Number
|
|
|
2527 |
},
|
|
|
2528 |
|
|
|
2529 |
forEach: function(/*Array*/arr, /*Function*/callback, /*Object?*/obj){
|
|
|
2530 |
// summary:
|
|
|
2531 |
// for every item in arr, call callback with that item as its
|
|
|
2532 |
// only parameter.
|
|
|
2533 |
// description:
|
|
|
2534 |
// Return values are ignored. This function
|
|
|
2535 |
// corresponds (and wraps) the JavaScript 1.6 forEach method. For
|
|
|
2536 |
// more details, see:
|
|
|
2537 |
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach
|
|
|
2538 |
|
|
|
2539 |
// match the behavior of the built-in forEach WRT empty arrs
|
|
|
2540 |
if(!arr || !arr.length){ return; }
|
|
|
2541 |
|
|
|
2542 |
// FIXME: there are several ways of handilng thisObject. Is
|
|
|
2543 |
// dojo.global always the default context?
|
|
|
2544 |
var _p = _getParts(arr, obj, callback); arr = _p[0];
|
|
|
2545 |
for(var i=0,l=_p[0].length; i<l; i++){
|
|
|
2546 |
_p[2].call(_p[1], arr[i], i, arr);
|
|
|
2547 |
}
|
|
|
2548 |
},
|
|
|
2549 |
|
|
|
2550 |
_everyOrSome: function(/*Boolean*/every, /*Array*/arr, /*Function*/callback, /*Object?*/obj){
|
|
|
2551 |
var _p = _getParts(arr, obj, callback); arr = _p[0];
|
|
|
2552 |
for(var i = 0, l = arr.length; i < l; i++){
|
|
|
2553 |
var result = !!_p[2].call(_p[1], arr[i], i, arr);
|
|
|
2554 |
if(every ^ result){
|
|
|
2555 |
return result; // Boolean
|
|
|
2556 |
}
|
|
|
2557 |
}
|
|
|
2558 |
return every; // Boolean
|
|
|
2559 |
},
|
|
|
2560 |
|
|
|
2561 |
every: function(/*Array*/arr, /*Function*/callback, /*Object?*/thisObject){
|
|
|
2562 |
// summary:
|
|
|
2563 |
// Determines whether or not every item in the array satisfies the
|
|
|
2564 |
// condition implemented by callback.
|
|
|
2565 |
// description:
|
|
|
2566 |
// The parameter thisObject may be used to
|
|
|
2567 |
// scope the call to callback. The function signature is derived
|
|
|
2568 |
// from the JavaScript 1.6 Array.every() function. More
|
|
|
2569 |
// information on this can be found here:
|
|
|
2570 |
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every
|
|
|
2571 |
// example:
|
|
|
2572 |
// | dojo.every([1, 2, 3, 4], function(item){ return item>1; });
|
|
|
2573 |
// returns false
|
|
|
2574 |
// example:
|
|
|
2575 |
// | dojo.every([1, 2, 3, 4], function(item){ return item>0; });
|
|
|
2576 |
// returns true
|
|
|
2577 |
return this._everyOrSome(true, arr, callback, thisObject); // Boolean
|
|
|
2578 |
},
|
|
|
2579 |
|
|
|
2580 |
some: function(/*Array*/arr, /*Function*/callback, /*Object?*/thisObject){
|
|
|
2581 |
// summary:
|
|
|
2582 |
// Determines whether or not any item in the array satisfies the
|
|
|
2583 |
// condition implemented by callback.
|
|
|
2584 |
// description:
|
|
|
2585 |
// The parameter thisObject may be used to
|
|
|
2586 |
// scope the call to callback. The function signature is derived
|
|
|
2587 |
// from the JavaScript 1.6 Array.some() function. More
|
|
|
2588 |
// information on this can be found here:
|
|
|
2589 |
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some
|
|
|
2590 |
// example:
|
|
|
2591 |
// | dojo.some([1, 2, 3, 4], function(item){ return item>1; });
|
|
|
2592 |
// returns true
|
|
|
2593 |
// example:
|
|
|
2594 |
// | dojo.some([1, 2, 3, 4], function(item){ return item<1; });
|
|
|
2595 |
// returns false
|
|
|
2596 |
return this._everyOrSome(false, arr, callback, thisObject); // Boolean
|
|
|
2597 |
},
|
|
|
2598 |
|
|
|
2599 |
map: function(/*Array*/arr, /*Function*/func, /*Function?*/obj){
|
|
|
2600 |
// summary:
|
|
|
2601 |
// applies a function to each element of an Array and creates
|
|
|
2602 |
// an Array with the results
|
|
|
2603 |
// description:
|
|
|
2604 |
// Returns a new array constituted from the return values of
|
|
|
2605 |
// passing each element of arr into unary_func. The obj parameter
|
|
|
2606 |
// may be passed to enable the passed function to be called in
|
|
|
2607 |
// that scope. In environments that support JavaScript 1.6, this
|
|
|
2608 |
// function is a passthrough to the built-in map() function
|
|
|
2609 |
// provided by Array instances. For details on this, see:
|
|
|
2610 |
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:map
|
|
|
2611 |
// example:
|
|
|
2612 |
// | dojo.map([1, 2, 3, 4], function(item){ return item+1 });
|
|
|
2613 |
// returns [2, 3, 4, 5]
|
|
|
2614 |
var _p = _getParts(arr, obj, func); arr = _p[0];
|
|
|
2615 |
var outArr = ((arguments[3]) ? (new arguments[3]()) : []);
|
|
|
2616 |
for(var i=0;i<arr.length;++i){
|
|
|
2617 |
outArr.push(_p[2].call(_p[1], arr[i], i, arr));
|
|
|
2618 |
}
|
|
|
2619 |
return outArr; // Array
|
|
|
2620 |
},
|
|
|
2621 |
|
|
|
2622 |
filter: function(/*Array*/arr, /*Function*/callback, /*Object?*/obj){
|
|
|
2623 |
// summary:
|
|
|
2624 |
// Returns a new Array with those items from arr that match the
|
|
|
2625 |
// condition implemented by callback. ob may be used to
|
|
|
2626 |
// scope the call to callback. The function signature is derived
|
|
|
2627 |
// from the JavaScript 1.6 Array.filter() function.
|
|
|
2628 |
//
|
|
|
2629 |
// More information on the JS 1.6 API can be found here:
|
|
|
2630 |
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:filter
|
|
|
2631 |
// example:
|
|
|
2632 |
// | dojo.filter([1, 2, 3, 4], function(item){ return item>1; });
|
|
|
2633 |
// returns [2, 3, 4]
|
|
|
2634 |
|
|
|
2635 |
var _p = _getParts(arr, obj, callback); arr = _p[0];
|
|
|
2636 |
var outArr = [];
|
|
|
2637 |
for(var i = 0; i < arr.length; i++){
|
|
|
2638 |
if(_p[2].call(_p[1], arr[i], i, arr)){
|
|
|
2639 |
outArr.push(arr[i]);
|
|
|
2640 |
}
|
|
|
2641 |
}
|
|
|
2642 |
return outArr; // Array
|
|
|
2643 |
}
|
|
|
2644 |
});
|
|
|
2645 |
})();
|
|
|
2646 |
|
|
|
2647 |
}
|
|
|
2648 |
|
|
|
2649 |
if(!dojo._hasResource["dojo._base.Color"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
2650 |
dojo._hasResource["dojo._base.Color"] = true;
|
|
|
2651 |
dojo.provide("dojo._base.Color");
|
|
|
2652 |
|
|
|
2653 |
|
|
|
2654 |
|
|
|
2655 |
dojo.Color = function(/*Array|String|Object*/ color){
|
|
|
2656 |
// summary:
|
|
|
2657 |
// takes a named string, hex string, array of rgb or rgba values,
|
|
|
2658 |
// an object with r, g, b, and a properties, or another dojo.Color object
|
|
|
2659 |
if(color){ this.setColor(color); }
|
|
|
2660 |
};
|
|
|
2661 |
|
|
|
2662 |
// FIXME: there's got to be a more space-efficient way to encode or discover these!! Use hex?
|
|
|
2663 |
dojo.Color.named = {
|
|
|
2664 |
black: [0,0,0],
|
|
|
2665 |
silver: [192,192,192],
|
|
|
2666 |
gray: [128,128,128],
|
|
|
2667 |
white: [255,255,255],
|
|
|
2668 |
maroon: [128,0,0],
|
|
|
2669 |
red: [255,0,0],
|
|
|
2670 |
purple: [128,0,128],
|
|
|
2671 |
fuchsia: [255,0,255],
|
|
|
2672 |
green: [0,128,0],
|
|
|
2673 |
lime: [0,255,0],
|
|
|
2674 |
olive: [128,128,0],
|
|
|
2675 |
yellow: [255,255,0],
|
|
|
2676 |
navy: [0,0,128],
|
|
|
2677 |
blue: [0,0,255],
|
|
|
2678 |
teal: [0,128,128],
|
|
|
2679 |
aqua: [0,255,255]
|
|
|
2680 |
};
|
|
|
2681 |
|
|
|
2682 |
|
|
|
2683 |
dojo.extend(dojo.Color, {
|
|
|
2684 |
r: 255, g: 255, b: 255, a: 1,
|
|
|
2685 |
_set: function(r, g, b, a){
|
|
|
2686 |
var t = this; t.r = r; t.g = g; t.b = b; t.a = a;
|
|
|
2687 |
},
|
|
|
2688 |
setColor: function(/*Array|String|Object*/ color){
|
|
|
2689 |
// summary:
|
|
|
2690 |
// takes a named string, hex string, array of rgb or rgba values,
|
|
|
2691 |
// an object with r, g, b, and a properties, or another dojo.Color object
|
|
|
2692 |
var d = dojo;
|
|
|
2693 |
if(d.isString(color)){
|
|
|
2694 |
d.colorFromString(color, this);
|
|
|
2695 |
}else if(d.isArray(color)){
|
|
|
2696 |
d.colorFromArray(color, this);
|
|
|
2697 |
}else{
|
|
|
2698 |
this._set(color.r, color.g, color.b, color.a);
|
|
|
2699 |
if(!(color instanceof d.Color)){ this.sanitize(); }
|
|
|
2700 |
}
|
|
|
2701 |
return this; // dojo.Color
|
|
|
2702 |
},
|
|
|
2703 |
sanitize: function(){
|
|
|
2704 |
// summary:
|
|
|
2705 |
// makes sure that the object has correct attributes
|
|
|
2706 |
// description:
|
|
|
2707 |
// the default implementation does nothing, include dojo.colors to
|
|
|
2708 |
// augment it to real checks
|
|
|
2709 |
return this; // dojo.Color
|
|
|
2710 |
},
|
|
|
2711 |
toRgb: function(){
|
|
|
2712 |
// summary: returns 3 component array of rgb values
|
|
|
2713 |
var t = this;
|
|
|
2714 |
return [t.r, t.g, t.b]; // Array
|
|
|
2715 |
},
|
|
|
2716 |
toRgba: function(){
|
|
|
2717 |
// summary: returns a 4 component array of rgba values
|
|
|
2718 |
var t = this;
|
|
|
2719 |
return [t.r, t.g, t.b, t.a]; // Array
|
|
|
2720 |
},
|
|
|
2721 |
toHex: function(){
|
|
|
2722 |
// summary: returns a css color string in hexadecimal representation
|
|
|
2723 |
var arr = dojo.map(["r", "g", "b"], function(x){
|
|
|
2724 |
var s = this[x].toString(16);
|
|
|
2725 |
return s.length < 2 ? "0" + s : s;
|
|
|
2726 |
}, this);
|
|
|
2727 |
return "#" + arr.join(""); // String
|
|
|
2728 |
},
|
|
|
2729 |
toCss: function(/*Boolean?*/ includeAlpha){
|
|
|
2730 |
// summary: returns a css color string in rgb(a) representation
|
|
|
2731 |
var t = this, rgb = t.r + ", " + t.g + ", " + t.b;
|
|
|
2732 |
return (includeAlpha ? "rgba(" + rgb + ", " + t.a : "rgb(" + rgb) + ")"; // String
|
|
|
2733 |
},
|
|
|
2734 |
toString: function(){
|
|
|
2735 |
// summary: returns a visual representation of the color
|
|
|
2736 |
return this.toCss(true); // String
|
|
|
2737 |
}
|
|
|
2738 |
});
|
|
|
2739 |
|
|
|
2740 |
dojo.blendColors = function(
|
|
|
2741 |
/*dojo.Color*/ start,
|
|
|
2742 |
/*dojo.Color*/ end,
|
|
|
2743 |
/*Number*/ weight,
|
|
|
2744 |
/*dojo.Color?*/ obj
|
|
|
2745 |
){
|
|
|
2746 |
// summary:
|
|
|
2747 |
// blend colors end and start with weight from 0 to 1, 0.5 being a 50/50 blend,
|
|
|
2748 |
// can reuse a previously allocated dojo.Color object for the result
|
|
|
2749 |
var d = dojo, t = obj || new dojo.Color();
|
|
|
2750 |
d.forEach(["r", "g", "b", "a"], function(x){
|
|
|
2751 |
t[x] = start[x] + (end[x] - start[x]) * weight;
|
|
|
2752 |
if(x != "a"){ t[x] = Math.round(t[x]); }
|
|
|
2753 |
});
|
|
|
2754 |
return t.sanitize(); // dojo.Color
|
|
|
2755 |
};
|
|
|
2756 |
|
|
|
2757 |
dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){
|
|
|
2758 |
// summary: get rgb(a) array from css-style color declarations
|
|
|
2759 |
var m = color.toLowerCase().match(/^rgba?\(([\s\.,0-9]+)\)/);
|
|
|
2760 |
return m && dojo.colorFromArray(m[1].split(/\s*,\s*/), obj); // dojo.Color
|
|
|
2761 |
};
|
|
|
2762 |
|
|
|
2763 |
dojo.colorFromHex = function(/*String*/ color, /*dojo.Color?*/ obj){
|
|
|
2764 |
// summary: converts a hex string with a '#' prefix to a color object.
|
|
|
2765 |
// Supports 12-bit #rgb shorthand.
|
|
|
2766 |
var d = dojo, t = obj || new d.Color(),
|
|
|
2767 |
bits = (color.length == 4) ? 4 : 8,
|
|
|
2768 |
mask = (1 << bits) - 1;
|
|
|
2769 |
color = Number("0x" + color.substr(1));
|
|
|
2770 |
if(isNaN(color)){
|
|
|
2771 |
return null; // dojo.Color
|
|
|
2772 |
}
|
|
|
2773 |
d.forEach(["b", "g", "r"], function(x){
|
|
|
2774 |
var c = color & mask;
|
|
|
2775 |
color >>= bits;
|
|
|
2776 |
t[x] = bits == 4 ? 17 * c : c;
|
|
|
2777 |
});
|
|
|
2778 |
t.a = 1;
|
|
|
2779 |
return t; // dojo.Color
|
|
|
2780 |
};
|
|
|
2781 |
|
|
|
2782 |
dojo.colorFromArray = function(/*Array*/ a, /*dojo.Color?*/ obj){
|
|
|
2783 |
// summary: builds a color from 1, 2, 3, or 4 element array
|
|
|
2784 |
var t = obj || new dojo.Color();
|
|
|
2785 |
t._set(Number(a[0]), Number(a[1]), Number(a[2]), Number(a[3]));
|
|
|
2786 |
if(isNaN(t.a)){ t.a = 1; }
|
|
|
2787 |
return t.sanitize(); // dojo.Color
|
|
|
2788 |
};
|
|
|
2789 |
|
|
|
2790 |
dojo.colorFromString = function(/*String*/ str, /*dojo.Color?*/ obj){
|
|
|
2791 |
// summary:
|
|
|
2792 |
// parses str for a color value.
|
|
|
2793 |
// description:
|
|
|
2794 |
// Acceptable input values for str may include arrays of any form
|
|
|
2795 |
// accepted by dojo.colorFromArray, hex strings such as "#aaaaaa", or
|
|
|
2796 |
// rgb or rgba strings such as "rgb(133, 200, 16)" or "rgba(10, 10,
|
|
|
2797 |
// 10, 50)"
|
|
|
2798 |
// returns:
|
|
|
2799 |
// a dojo.Color object. If obj is passed, it will be the return value.
|
|
|
2800 |
var a = dojo.Color.named[str];
|
|
|
2801 |
return a && dojo.colorFromArray(a, obj) || dojo.colorFromRgb(str, obj) || dojo.colorFromHex(str, obj);
|
|
|
2802 |
};
|
|
|
2803 |
|
|
|
2804 |
}
|
|
|
2805 |
|
|
|
2806 |
if(!dojo._hasResource["dojo._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
2807 |
dojo._hasResource["dojo._base"] = true;
|
|
|
2808 |
dojo.provide("dojo._base");
|
|
|
2809 |
|
|
|
2810 |
|
|
|
2811 |
|
|
|
2812 |
|
|
|
2813 |
|
|
|
2814 |
|
|
|
2815 |
|
|
|
2816 |
|
|
|
2817 |
|
|
|
2818 |
|
|
|
2819 |
|
|
|
2820 |
|
|
|
2821 |
|
|
|
2822 |
|
|
|
2823 |
|
|
|
2824 |
(function(){
|
|
|
2825 |
if(djConfig.require){
|
|
|
2826 |
for(var x=0; x<djConfig.require.length; x++){
|
|
|
2827 |
dojo["require"](djConfig.require[x]);
|
|
|
2828 |
}
|
|
|
2829 |
}
|
|
|
2830 |
})();
|
|
|
2831 |
|
|
|
2832 |
}
|
|
|
2833 |
|
|
|
2834 |
if(!dojo._hasResource["dojo._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
2835 |
dojo._hasResource["dojo._base.window"] = true;
|
|
|
2836 |
dojo.provide("dojo._base.window");
|
|
|
2837 |
|
|
|
2838 |
dojo._gearsObject = function(){
|
|
|
2839 |
// summary:
|
|
|
2840 |
// factory method to get a Google Gears plugin instance to
|
|
|
2841 |
// expose in the browser runtime environment, if present
|
|
|
2842 |
var factory;
|
|
|
2843 |
var results;
|
|
|
2844 |
|
|
|
2845 |
var gearsObj = dojo.getObject("google.gears");
|
|
|
2846 |
if(gearsObj){ return gearsObj; } // already defined elsewhere
|
|
|
2847 |
|
|
|
2848 |
if(typeof GearsFactory != "undefined"){ // Firefox
|
|
|
2849 |
factory = new GearsFactory();
|
|
|
2850 |
}else{
|
|
|
2851 |
if(dojo.isIE){
|
|
|
2852 |
// IE
|
|
|
2853 |
try{
|
|
|
2854 |
factory = new ActiveXObject("Gears.Factory");
|
|
|
2855 |
}catch(e){
|
|
|
2856 |
// ok to squelch; there's no gears factory. move on.
|
|
|
2857 |
}
|
|
|
2858 |
}else if(navigator.mimeTypes["application/x-googlegears"]){
|
|
|
2859 |
// Safari?
|
|
|
2860 |
factory = document.createElement("object");
|
|
|
2861 |
factory.setAttribute("type", "application/x-googlegears");
|
|
|
2862 |
factory.setAttribute("width", 0);
|
|
|
2863 |
factory.setAttribute("height", 0);
|
|
|
2864 |
factory.style.display = "none";
|
|
|
2865 |
document.documentElement.appendChild(factory);
|
|
|
2866 |
}
|
|
|
2867 |
}
|
|
|
2868 |
|
|
|
2869 |
// still nothing?
|
|
|
2870 |
if(!factory){ return null; }
|
|
|
2871 |
|
|
|
2872 |
// define the global objects now; don't overwrite them though if they
|
|
|
2873 |
// were somehow set internally by the Gears plugin, which is on their
|
|
|
2874 |
// dev roadmap for the future
|
|
|
2875 |
dojo.setObject("google.gears.factory", factory);
|
|
|
2876 |
return dojo.getObject("google.gears");
|
|
|
2877 |
};
|
|
|
2878 |
|
|
|
2879 |
// see if we have Google Gears installed, and if
|
|
|
2880 |
// so, make it available in the runtime environment
|
|
|
2881 |
// and in the Google standard 'google.gears' global object
|
|
|
2882 |
dojo.isGears = (!!dojo._gearsObject())||0;
|
|
|
2883 |
|
|
|
2884 |
// @global: dojo.doc
|
|
|
2885 |
|
|
|
2886 |
// summary:
|
|
|
2887 |
// Current document object. 'dojo.doc' can be modified
|
|
|
2888 |
// for temporary context shifting. Also see dojo.withDoc().
|
|
|
2889 |
// description:
|
|
|
2890 |
// Refer to dojo.doc rather
|
|
|
2891 |
// than referring to 'window.document' to ensure your code runs
|
|
|
2892 |
// correctly in managed contexts.
|
|
|
2893 |
dojo.doc = window["document"] || null;
|
|
|
2894 |
|
|
|
2895 |
dojo.body = function(){
|
|
|
2896 |
// summary:
|
|
|
2897 |
// return the body object associated with dojo.doc
|
|
|
2898 |
|
|
|
2899 |
// Note: document.body is not defined for a strict xhtml document
|
|
|
2900 |
// Would like to memoize this, but dojo.doc can change vi dojo.withDoc().
|
|
|
2901 |
return dojo.doc.body || dojo.doc.getElementsByTagName("body")[0];
|
|
|
2902 |
}
|
|
|
2903 |
|
|
|
2904 |
dojo.setContext = function(/*Object*/globalObject, /*DocumentElement*/globalDocument){
|
|
|
2905 |
// summary:
|
|
|
2906 |
// changes the behavior of many core Dojo functions that deal with
|
|
|
2907 |
// namespace and DOM lookup, changing them to work in a new global
|
|
|
2908 |
// context. The varibles dojo.global and dojo.doc
|
|
|
2909 |
// are modified as a result of calling this function.
|
|
|
2910 |
dojo.global = globalObject;
|
|
|
2911 |
dojo.doc = globalDocument;
|
|
|
2912 |
};
|
|
|
2913 |
|
|
|
2914 |
dojo._fireCallback = function(callback, context, cbArguments){
|
|
|
2915 |
// FIXME: should migrate to using "dojo.isString"!
|
|
|
2916 |
if(context && dojo.isString(callback)){
|
|
|
2917 |
callback = context[callback];
|
|
|
2918 |
}
|
|
|
2919 |
return (context ? callback.apply(context, cbArguments || [ ]) : callback());
|
|
|
2920 |
}
|
|
|
2921 |
|
|
|
2922 |
dojo.withGlobal = function( /*Object*/globalObject,
|
|
|
2923 |
/*Function*/callback,
|
|
|
2924 |
/*Object?*/thisObject,
|
|
|
2925 |
/*Array?*/cbArguments){
|
|
|
2926 |
// summary:
|
|
|
2927 |
// Call callback with globalObject as dojo.global and
|
|
|
2928 |
// globalObject.document as dojo.doc. If provided, globalObject
|
|
|
2929 |
// will be executed in the context of object thisObject
|
|
|
2930 |
// description:
|
|
|
2931 |
// When callback() returns or throws an error, the dojo.global
|
|
|
2932 |
// and dojo.doc will be restored to its previous state.
|
|
|
2933 |
var rval;
|
|
|
2934 |
var oldGlob = dojo.global;
|
|
|
2935 |
var oldDoc = dojo.doc;
|
|
|
2936 |
try{
|
|
|
2937 |
dojo.setContext(globalObject, globalObject.document);
|
|
|
2938 |
rval = dojo._fireCallback(callback, thisObject, cbArguments);
|
|
|
2939 |
}finally{
|
|
|
2940 |
dojo.setContext(oldGlob, oldDoc);
|
|
|
2941 |
}
|
|
|
2942 |
return rval;
|
|
|
2943 |
}
|
|
|
2944 |
|
|
|
2945 |
dojo.withDoc = function( /*Object*/documentObject,
|
|
|
2946 |
/*Function*/callback,
|
|
|
2947 |
/*Object?*/thisObject,
|
|
|
2948 |
/*Array?*/cbArguments){
|
|
|
2949 |
// summary:
|
|
|
2950 |
// Call callback with documentObject as dojo.doc. If provided,
|
|
|
2951 |
// callback will be executed in the context of object thisObject
|
|
|
2952 |
// description:
|
|
|
2953 |
// When callback() returns or throws an error, the dojo.doc will
|
|
|
2954 |
// be restored to its previous state.
|
|
|
2955 |
var rval;
|
|
|
2956 |
var oldDoc = dojo.doc;
|
|
|
2957 |
try{
|
|
|
2958 |
dojo.doc = documentObject;
|
|
|
2959 |
rval = dojo._fireCallback(callback, thisObject, cbArguments);
|
|
|
2960 |
}finally{
|
|
|
2961 |
dojo.doc = oldDoc;
|
|
|
2962 |
}
|
|
|
2963 |
return rval;
|
|
|
2964 |
};
|
|
|
2965 |
|
|
|
2966 |
//Register any module paths set up in djConfig. Need to do this
|
|
|
2967 |
//in the hostenvs since hostenv_browser can read djConfig from a
|
|
|
2968 |
//script tag's attribute.
|
|
|
2969 |
(function(){
|
|
|
2970 |
var mp = djConfig["modulePaths"];
|
|
|
2971 |
if(mp){
|
|
|
2972 |
for(var param in mp){
|
|
|
2973 |
dojo.registerModulePath(param, mp[param]);
|
|
|
2974 |
}
|
|
|
2975 |
}
|
|
|
2976 |
})();
|
|
|
2977 |
|
|
|
2978 |
}
|
|
|
2979 |
|
|
|
2980 |
if(!dojo._hasResource["dojo._base.event"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
2981 |
dojo._hasResource["dojo._base.event"] = true;
|
|
|
2982 |
dojo.provide("dojo._base.event");
|
|
|
2983 |
|
|
|
2984 |
|
|
|
2985 |
// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
|
|
|
2986 |
|
|
|
2987 |
(function(){
|
|
|
2988 |
// DOM event listener machinery
|
|
|
2989 |
var del = dojo._event_listener = {
|
|
|
2990 |
add: function(/*DOMNode*/node, /*String*/name, /*Function*/fp){
|
|
|
2991 |
if(!node){return;}
|
|
|
2992 |
name = del._normalizeEventName(name);
|
|
|
2993 |
|
|
|
2994 |
fp = del._fixCallback(name, fp);
|
|
|
2995 |
|
|
|
2996 |
var oname = name;
|
|
|
2997 |
if((!dojo.isIE)&&((name == "mouseenter")||(name == "mouseleave"))){
|
|
|
2998 |
var oname = name;
|
|
|
2999 |
var ofp = fp;
|
|
|
3000 |
name = (name == "mouseenter") ? "mouseover" : "mouseout";
|
|
|
3001 |
fp = function(e){
|
|
|
3002 |
// thanks ben!
|
|
|
3003 |
var id = dojo.isDescendant(e.relatedTarget, node);
|
|
|
3004 |
if(id == false){
|
|
|
3005 |
// e.type = oname; // FIXME: doesn't take?
|
|
|
3006 |
return ofp.call(this, e);
|
|
|
3007 |
}
|
|
|
3008 |
}
|
|
|
3009 |
}
|
|
|
3010 |
|
|
|
3011 |
node.addEventListener(name, fp, false);
|
|
|
3012 |
return fp; /*Handle*/
|
|
|
3013 |
},
|
|
|
3014 |
remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){
|
|
|
3015 |
// summary:
|
|
|
3016 |
// clobbers the listener from the node
|
|
|
3017 |
// node:
|
|
|
3018 |
// DOM node to attach the event to
|
|
|
3019 |
// event:
|
|
|
3020 |
// the name of the handler to remove the function from
|
|
|
3021 |
// handle:
|
|
|
3022 |
// the handle returned from add
|
|
|
3023 |
(node)&&(node.removeEventListener(del._normalizeEventName(event), handle, false));
|
|
|
3024 |
},
|
|
|
3025 |
_normalizeEventName: function(/*String*/name){
|
|
|
3026 |
// Generally, name should be lower case, unless it is special
|
|
|
3027 |
// somehow (e.g. a Mozilla DOM event).
|
|
|
3028 |
// Remove 'on'.
|
|
|
3029 |
return (name.slice(0,2)=="on" ? name.slice(2) : name);
|
|
|
3030 |
},
|
|
|
3031 |
_fixCallback: function(/*String*/name, fp){
|
|
|
3032 |
// By default, we only invoke _fixEvent for 'keypress'
|
|
|
3033 |
// If code is added to _fixEvent for other events, we have
|
|
|
3034 |
// to revisit this optimization.
|
|
|
3035 |
// This also applies to _fixEvent overrides for Safari and Opera
|
|
|
3036 |
// below.
|
|
|
3037 |
return (name!="keypress" ? fp : function(e){ return fp.call(this, del._fixEvent(e, this)); });
|
|
|
3038 |
},
|
|
|
3039 |
_fixEvent: function(evt, sender){
|
|
|
3040 |
// _fixCallback only attaches us to keypress.
|
|
|
3041 |
// Switch on evt.type anyway because we might
|
|
|
3042 |
// be called directly from dojo.fixEvent.
|
|
|
3043 |
switch(evt.type){
|
|
|
3044 |
case "keypress":
|
|
|
3045 |
del._setKeyChar(evt);
|
|
|
3046 |
break;
|
|
|
3047 |
}
|
|
|
3048 |
return evt;
|
|
|
3049 |
},
|
|
|
3050 |
_setKeyChar: function(evt){
|
|
|
3051 |
evt.keyChar = (evt.charCode ? String.fromCharCode(evt.charCode) : '');
|
|
|
3052 |
}
|
|
|
3053 |
};
|
|
|
3054 |
|
|
|
3055 |
// DOM events
|
|
|
3056 |
|
|
|
3057 |
dojo.fixEvent = function(/*Event*/evt, /*DOMNode*/sender){
|
|
|
3058 |
// summary:
|
|
|
3059 |
// normalizes properties on the event object including event
|
|
|
3060 |
// bubbling methods, keystroke normalization, and x/y positions
|
|
|
3061 |
// evt: Event
|
|
|
3062 |
// native event object
|
|
|
3063 |
// sender: DOMNode
|
|
|
3064 |
// node to treat as "currentTarget"
|
|
|
3065 |
return del._fixEvent(evt, sender);
|
|
|
3066 |
}
|
|
|
3067 |
|
|
|
3068 |
dojo.stopEvent = function(/*Event*/evt){
|
|
|
3069 |
// summary:
|
|
|
3070 |
// prevents propagation and clobbers the default action of the
|
|
|
3071 |
// passed event
|
|
|
3072 |
// evt: Event
|
|
|
3073 |
// The event object. If omitted, window.event is used on IE.
|
|
|
3074 |
evt.preventDefault();
|
|
|
3075 |
evt.stopPropagation();
|
|
|
3076 |
// NOTE: below, this method is overridden for IE
|
|
|
3077 |
}
|
|
|
3078 |
|
|
|
3079 |
// the default listener to use on dontFix nodes, overriden for IE
|
|
|
3080 |
var node_listener = dojo._listener;
|
|
|
3081 |
|
|
|
3082 |
// Unify connect and event listeners
|
|
|
3083 |
dojo._connect = function(obj, event, context, method, dontFix){
|
|
|
3084 |
// FIXME: need a more strict test
|
|
|
3085 |
var isNode = obj && (obj.nodeType||obj.attachEvent||obj.addEventListener);
|
|
|
3086 |
// choose one of three listener options: raw (connect.js), DOM event on a Node, custom event on a Node
|
|
|
3087 |
// we need the third option to provide leak prevention on broken browsers (IE)
|
|
|
3088 |
var lid = !isNode ? 0 : (!dontFix ? 1 : 2), l = [dojo._listener, del, node_listener][lid];
|
|
|
3089 |
// create a listener
|
|
|
3090 |
var h = l.add(obj, event, dojo.hitch(context, method));
|
|
|
3091 |
// formerly, the disconnect package contained "l" directly, but if client code
|
|
|
3092 |
// leaks the disconnect package (by connecting it to a node), referencing "l"
|
|
|
3093 |
// compounds the problem.
|
|
|
3094 |
// instead we return a listener id, which requires custom _disconnect below.
|
|
|
3095 |
// return disconnect package
|
|
|
3096 |
return [ obj, event, h, lid ];
|
|
|
3097 |
}
|
|
|
3098 |
|
|
|
3099 |
dojo._disconnect = function(obj, event, handle, listener){
|
|
|
3100 |
([dojo._listener, del, node_listener][listener]).remove(obj, event, handle);
|
|
|
3101 |
}
|
|
|
3102 |
|
|
|
3103 |
// Constants
|
|
|
3104 |
|
|
|
3105 |
// Public: client code should test
|
|
|
3106 |
// keyCode against these named constants, as the
|
|
|
3107 |
// actual codes can vary by browser.
|
|
|
3108 |
dojo.keys = {
|
|
|
3109 |
BACKSPACE: 8,
|
|
|
3110 |
TAB: 9,
|
|
|
3111 |
CLEAR: 12,
|
|
|
3112 |
ENTER: 13,
|
|
|
3113 |
SHIFT: 16,
|
|
|
3114 |
CTRL: 17,
|
|
|
3115 |
ALT: 18,
|
|
|
3116 |
PAUSE: 19,
|
|
|
3117 |
CAPS_LOCK: 20,
|
|
|
3118 |
ESCAPE: 27,
|
|
|
3119 |
SPACE: 32,
|
|
|
3120 |
PAGE_UP: 33,
|
|
|
3121 |
PAGE_DOWN: 34,
|
|
|
3122 |
END: 35,
|
|
|
3123 |
HOME: 36,
|
|
|
3124 |
LEFT_ARROW: 37,
|
|
|
3125 |
UP_ARROW: 38,
|
|
|
3126 |
RIGHT_ARROW: 39,
|
|
|
3127 |
DOWN_ARROW: 40,
|
|
|
3128 |
INSERT: 45,
|
|
|
3129 |
DELETE: 46,
|
|
|
3130 |
HELP: 47,
|
|
|
3131 |
LEFT_WINDOW: 91,
|
|
|
3132 |
RIGHT_WINDOW: 92,
|
|
|
3133 |
SELECT: 93,
|
|
|
3134 |
NUMPAD_0: 96,
|
|
|
3135 |
NUMPAD_1: 97,
|
|
|
3136 |
NUMPAD_2: 98,
|
|
|
3137 |
NUMPAD_3: 99,
|
|
|
3138 |
NUMPAD_4: 100,
|
|
|
3139 |
NUMPAD_5: 101,
|
|
|
3140 |
NUMPAD_6: 102,
|
|
|
3141 |
NUMPAD_7: 103,
|
|
|
3142 |
NUMPAD_8: 104,
|
|
|
3143 |
NUMPAD_9: 105,
|
|
|
3144 |
NUMPAD_MULTIPLY: 106,
|
|
|
3145 |
NUMPAD_PLUS: 107,
|
|
|
3146 |
NUMPAD_ENTER: 108,
|
|
|
3147 |
NUMPAD_MINUS: 109,
|
|
|
3148 |
NUMPAD_PERIOD: 110,
|
|
|
3149 |
NUMPAD_DIVIDE: 111,
|
|
|
3150 |
F1: 112,
|
|
|
3151 |
F2: 113,
|
|
|
3152 |
F3: 114,
|
|
|
3153 |
F4: 115,
|
|
|
3154 |
F5: 116,
|
|
|
3155 |
F6: 117,
|
|
|
3156 |
F7: 118,
|
|
|
3157 |
F8: 119,
|
|
|
3158 |
F9: 120,
|
|
|
3159 |
F10: 121,
|
|
|
3160 |
F11: 122,
|
|
|
3161 |
F12: 123,
|
|
|
3162 |
F13: 124,
|
|
|
3163 |
F14: 125,
|
|
|
3164 |
F15: 126,
|
|
|
3165 |
NUM_LOCK: 144,
|
|
|
3166 |
SCROLL_LOCK: 145
|
|
|
3167 |
};
|
|
|
3168 |
|
|
|
3169 |
// IE event normalization
|
|
|
3170 |
if(dojo.isIE){
|
|
|
3171 |
var _trySetKeyCode = function(e, code){
|
|
|
3172 |
try{
|
|
|
3173 |
// squelch errors when keyCode is read-only
|
|
|
3174 |
// (e.g. if keyCode is ctrl or shift)
|
|
|
3175 |
return (e.keyCode = code);
|
|
|
3176 |
}catch(e){
|
|
|
3177 |
return 0;
|
|
|
3178 |
}
|
|
|
3179 |
}
|
|
|
3180 |
|
|
|
3181 |
// by default, use the standard listener
|
|
|
3182 |
var iel = dojo._listener;
|
|
|
3183 |
// dispatcher tracking property
|
|
|
3184 |
if(!djConfig._allow_leaks){
|
|
|
3185 |
// custom listener that handles leak protection for DOM events
|
|
|
3186 |
node_listener = iel = dojo._ie_listener = {
|
|
|
3187 |
// support handler indirection: event handler functions are
|
|
|
3188 |
// referenced here. Event dispatchers hold only indices.
|
|
|
3189 |
handlers: [],
|
|
|
3190 |
// add a listener to an object
|
|
|
3191 |
add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
|
|
|
3192 |
source = source || dojo.global;
|
|
|
3193 |
var f = source[method];
|
|
|
3194 |
if(!f||!f._listeners){
|
|
|
3195 |
var d = dojo._getIeDispatcher();
|
|
|
3196 |
// original target function is special
|
|
|
3197 |
d.target = f && (ieh.push(f) - 1);
|
|
|
3198 |
// dispatcher holds a list of indices into handlers table
|
|
|
3199 |
d._listeners = [];
|
|
|
3200 |
// redirect source to dispatcher
|
|
|
3201 |
f = source[method] = d;
|
|
|
3202 |
}
|
|
|
3203 |
return f._listeners.push(ieh.push(listener) - 1) ; /*Handle*/
|
|
|
3204 |
},
|
|
|
3205 |
// remove a listener from an object
|
|
|
3206 |
remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
|
|
|
3207 |
var f = (source||dojo.global)[method], l = f&&f._listeners;
|
|
|
3208 |
if(f && l && handle--){
|
|
|
3209 |
delete ieh[l[handle]];
|
|
|
3210 |
delete l[handle];
|
|
|
3211 |
}
|
|
|
3212 |
}
|
|
|
3213 |
};
|
|
|
3214 |
// alias used above
|
|
|
3215 |
var ieh = iel.handlers;
|
|
|
3216 |
}
|
|
|
3217 |
|
|
|
3218 |
dojo.mixin(del, {
|
|
|
3219 |
add: function(/*DOMNode*/node, /*String*/event, /*Function*/fp){
|
|
|
3220 |
if(!node){return;} // undefined
|
|
|
3221 |
event = del._normalizeEventName(event);
|
|
|
3222 |
if(event=="onkeypress"){
|
|
|
3223 |
// we need to listen to onkeydown to synthesize
|
|
|
3224 |
// keypress events that otherwise won't fire
|
|
|
3225 |
// on IE
|
|
|
3226 |
var kd = node.onkeydown;
|
|
|
3227 |
if(!kd||!kd._listeners||!kd._stealthKeydown){
|
|
|
3228 |
// we simply ignore this connection when disconnecting
|
|
|
3229 |
// because it's side-effects are harmless
|
|
|
3230 |
del.add(node, "onkeydown", del._stealthKeyDown);
|
|
|
3231 |
// we only want one stealth listener per node
|
|
|
3232 |
node.onkeydown._stealthKeydown = true;
|
|
|
3233 |
}
|
|
|
3234 |
}
|
|
|
3235 |
return iel.add(node, event, del._fixCallback(fp));
|
|
|
3236 |
},
|
|
|
3237 |
remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){
|
|
|
3238 |
iel.remove(node, del._normalizeEventName(event), handle);
|
|
|
3239 |
},
|
|
|
3240 |
_normalizeEventName: function(/*String*/eventName){
|
|
|
3241 |
// Generally, eventName should be lower case, unless it is
|
|
|
3242 |
// special somehow (e.g. a Mozilla event)
|
|
|
3243 |
// ensure 'on'
|
|
|
3244 |
return (eventName.slice(0,2)!="on" ? "on"+eventName : eventName);
|
|
|
3245 |
},
|
|
|
3246 |
_nop: function(){},
|
|
|
3247 |
_fixEvent: function(/*Event*/evt, /*DOMNode*/sender){
|
|
|
3248 |
// summary:
|
|
|
3249 |
// normalizes properties on the event object including event
|
|
|
3250 |
// bubbling methods, keystroke normalization, and x/y positions
|
|
|
3251 |
// evt: native event object
|
|
|
3252 |
// sender: node to treat as "currentTarget"
|
|
|
3253 |
if(!evt){
|
|
|
3254 |
var w = (sender)&&((sender.ownerDocument || sender.document || sender).parentWindow)||window;
|
|
|
3255 |
evt = w.event;
|
|
|
3256 |
}
|
|
|
3257 |
if(!evt){return(evt);}
|
|
|
3258 |
evt.target = evt.srcElement;
|
|
|
3259 |
evt.currentTarget = (sender || evt.srcElement);
|
|
|
3260 |
evt.layerX = evt.offsetX;
|
|
|
3261 |
evt.layerY = evt.offsetY;
|
|
|
3262 |
// FIXME: scroll position query is duped from dojo.html to
|
|
|
3263 |
// avoid dependency on that entire module. Now that HTML is in
|
|
|
3264 |
// Base, we should convert back to something similar there.
|
|
|
3265 |
var se = evt.srcElement, doc = (se && se.ownerDocument) || document;
|
|
|
3266 |
// DO NOT replace the following to use dojo.body(), in IE, document.documentElement should be used
|
|
|
3267 |
// here rather than document.body
|
|
|
3268 |
var docBody = ((dojo.isIE<6)||(doc["compatMode"]=="BackCompat")) ? doc.body : doc.documentElement;
|
|
|
3269 |
var offset = dojo._getIeDocumentElementOffset();
|
|
|
3270 |
evt.pageX = evt.clientX + dojo._fixIeBiDiScrollLeft(docBody.scrollLeft || 0) - offset.x;
|
|
|
3271 |
evt.pageY = evt.clientY + (docBody.scrollTop || 0) - offset.y;
|
|
|
3272 |
if(evt.type == "mouseover"){
|
|
|
3273 |
evt.relatedTarget = evt.fromElement;
|
|
|
3274 |
}
|
|
|
3275 |
if(evt.type == "mouseout"){
|
|
|
3276 |
evt.relatedTarget = evt.toElement;
|
|
|
3277 |
}
|
|
|
3278 |
evt.stopPropagation = del._stopPropagation;
|
|
|
3279 |
evt.preventDefault = del._preventDefault;
|
|
|
3280 |
return del._fixKeys(evt);
|
|
|
3281 |
},
|
|
|
3282 |
_fixKeys: function(evt){
|
|
|
3283 |
switch(evt.type){
|
|
|
3284 |
case "keypress":
|
|
|
3285 |
var c = ("charCode" in evt ? evt.charCode : evt.keyCode);
|
|
|
3286 |
if (c==10){
|
|
|
3287 |
// CTRL-ENTER is CTRL-ASCII(10) on IE, but CTRL-ENTER on Mozilla
|
|
|
3288 |
c=0;
|
|
|
3289 |
evt.keyCode = 13;
|
|
|
3290 |
}else if(c==13||c==27){
|
|
|
3291 |
c=0; // Mozilla considers ENTER and ESC non-printable
|
|
|
3292 |
}else if(c==3){
|
|
|
3293 |
c=99; // Mozilla maps CTRL-BREAK to CTRL-c
|
|
|
3294 |
}
|
|
|
3295 |
// Mozilla sets keyCode to 0 when there is a charCode
|
|
|
3296 |
// but that stops the event on IE.
|
|
|
3297 |
evt.charCode = c;
|
|
|
3298 |
del._setKeyChar(evt);
|
|
|
3299 |
break;
|
|
|
3300 |
}
|
|
|
3301 |
return evt;
|
|
|
3302 |
},
|
|
|
3303 |
// some ctrl-key combinations (mostly w/punctuation) do not emit a char code in IE
|
|
|
3304 |
// we map those virtual key codes to ascii here
|
|
|
3305 |
// not valid for all (non-US) keyboards, so maybe we shouldn't bother
|
|
|
3306 |
_punctMap: {
|
|
|
3307 |
106:42,
|
|
|
3308 |
111:47,
|
|
|
3309 |
186:59,
|
|
|
3310 |
187:43,
|
|
|
3311 |
188:44,
|
|
|
3312 |
189:45,
|
|
|
3313 |
190:46,
|
|
|
3314 |
191:47,
|
|
|
3315 |
192:96,
|
|
|
3316 |
219:91,
|
|
|
3317 |
220:92,
|
|
|
3318 |
221:93,
|
|
|
3319 |
222:39
|
|
|
3320 |
},
|
|
|
3321 |
_stealthKeyDown: function(evt){
|
|
|
3322 |
// IE doesn't fire keypress for most non-printable characters.
|
|
|
3323 |
// other browsers do, we simulate it here.
|
|
|
3324 |
var kp=evt.currentTarget.onkeypress;
|
|
|
3325 |
// only works if kp exists and is a dispatcher
|
|
|
3326 |
if(!kp||!kp._listeners)return;
|
|
|
3327 |
// munge key/charCode
|
|
|
3328 |
var k=evt.keyCode;
|
|
|
3329 |
// These are Windows Virtual Key Codes
|
|
|
3330 |
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
|
|
|
3331 |
var unprintable = (k!=13)&&(k!=32)&&(k!=27)&&(k<48||k>90)&&(k<96||k>111)&&(k<186||k>192)&&(k<219||k>222);
|
|
|
3332 |
// synthesize keypress for most unprintables and CTRL-keys
|
|
|
3333 |
if(unprintable||evt.ctrlKey){
|
|
|
3334 |
var c = (unprintable ? 0 : k);
|
|
|
3335 |
if(evt.ctrlKey){
|
|
|
3336 |
if(k==3 || k==13){
|
|
|
3337 |
return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively
|
|
|
3338 |
}else if(c>95 && c<106){
|
|
|
3339 |
c -= 48; // map CTRL-[numpad 0-9] to ASCII
|
|
|
3340 |
}else if((!evt.shiftKey)&&(c>=65&&c<=90)){
|
|
|
3341 |
c += 32; // map CTRL-[A-Z] to lowercase
|
|
|
3342 |
}else{
|
|
|
3343 |
c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
|
|
|
3344 |
}
|
|
|
3345 |
}
|
|
|
3346 |
// simulate a keypress event
|
|
|
3347 |
var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
|
|
|
3348 |
kp.call(evt.currentTarget, faux);
|
|
|
3349 |
evt.cancelBubble = faux.cancelBubble;
|
|
|
3350 |
evt.returnValue = faux.returnValue;
|
|
|
3351 |
_trySetKeyCode(evt, faux.keyCode);
|
|
|
3352 |
}
|
|
|
3353 |
},
|
|
|
3354 |
// Called in Event scope
|
|
|
3355 |
_stopPropagation: function(){
|
|
|
3356 |
this.cancelBubble = true;
|
|
|
3357 |
},
|
|
|
3358 |
_preventDefault: function(){
|
|
|
3359 |
// Setting keyCode to 0 is the only way to prevent certain keypresses (namely
|
|
|
3360 |
// ctrl-combinations that correspond to menu accelerator keys).
|
|
|
3361 |
// Otoh, it prevents upstream listeners from getting this information
|
|
|
3362 |
// Try to split the difference here by clobbering keyCode only for ctrl
|
|
|
3363 |
// combinations. If you still need to access the key upstream, bubbledKeyCode is
|
|
|
3364 |
// provided as a workaround.
|
|
|
3365 |
this.bubbledKeyCode = this.keyCode;
|
|
|
3366 |
if(this.ctrlKey){_trySetKeyCode(this, 0);}
|
|
|
3367 |
this.returnValue = false;
|
|
|
3368 |
}
|
|
|
3369 |
});
|
|
|
3370 |
|
|
|
3371 |
// override stopEvent for IE
|
|
|
3372 |
dojo.stopEvent = function(evt){
|
|
|
3373 |
evt = evt || window.event;
|
|
|
3374 |
del._stopPropagation.call(evt);
|
|
|
3375 |
del._preventDefault.call(evt);
|
|
|
3376 |
}
|
|
|
3377 |
}
|
|
|
3378 |
|
|
|
3379 |
del._synthesizeEvent = function(evt, props){
|
|
|
3380 |
var faux = dojo.mixin({}, evt, props);
|
|
|
3381 |
del._setKeyChar(faux);
|
|
|
3382 |
// FIXME: would prefer to use dojo.hitch: dojo.hitch(evt, evt.preventDefault);
|
|
|
3383 |
// but it throws an error when preventDefault is invoked on Safari
|
|
|
3384 |
// does Event.preventDefault not support "apply" on Safari?
|
|
|
3385 |
faux.preventDefault = function(){ evt.preventDefault(); };
|
|
|
3386 |
faux.stopPropagation = function(){ evt.stopPropagation(); };
|
|
|
3387 |
return faux;
|
|
|
3388 |
}
|
|
|
3389 |
|
|
|
3390 |
// Opera event normalization
|
|
|
3391 |
if(dojo.isOpera){
|
|
|
3392 |
dojo.mixin(del, {
|
|
|
3393 |
_fixEvent: function(evt, sender){
|
|
|
3394 |
switch(evt.type){
|
|
|
3395 |
case "keypress":
|
|
|
3396 |
var c = evt.which;
|
|
|
3397 |
if(c==3){
|
|
|
3398 |
c=99; // Mozilla maps CTRL-BREAK to CTRL-c
|
|
|
3399 |
}
|
|
|
3400 |
// can't trap some keys at all, like INSERT and DELETE
|
|
|
3401 |
// there is no differentiating info between DELETE and ".", or INSERT and "-"
|
|
|
3402 |
c = ((c<41)&&(!evt.shiftKey) ? 0 : c);
|
|
|
3403 |
if((evt.ctrlKey)&&(!evt.shiftKey)&&(c>=65)&&(c<=90)){
|
|
|
3404 |
// lowercase CTRL-[A-Z] keys
|
|
|
3405 |
c += 32;
|
|
|
3406 |
}
|
|
|
3407 |
return del._synthesizeEvent(evt, { charCode: c });
|
|
|
3408 |
}
|
|
|
3409 |
return evt;
|
|
|
3410 |
}
|
|
|
3411 |
});
|
|
|
3412 |
}
|
|
|
3413 |
|
|
|
3414 |
// Safari event normalization
|
|
|
3415 |
if(dojo.isSafari){
|
|
|
3416 |
dojo.mixin(del, {
|
|
|
3417 |
_fixEvent: function(evt, sender){
|
|
|
3418 |
switch(evt.type){
|
|
|
3419 |
case "keypress":
|
|
|
3420 |
var c = evt.charCode, s = evt.shiftKey, k = evt.keyCode;
|
|
|
3421 |
// FIXME: This is a hack, suggest we rethink keyboard strategy.
|
|
|
3422 |
// Arrow and page keys have 0 "keyCode" in keypress events.on Safari for Windows
|
|
|
3423 |
k = k || identifierMap[evt.keyIdentifier] || 0;
|
|
|
3424 |
if(evt.keyIdentifier=="Enter"){
|
|
|
3425 |
c = 0; // differentiate Enter from CTRL-m (both code 13)
|
|
|
3426 |
}else if((evt.ctrlKey)&&(c>0)&&(c<27)){
|
|
|
3427 |
c += 96; // map CTRL-[A-Z] codes to ASCII
|
|
|
3428 |
} else if (c==dojo.keys.SHIFT_TAB) {
|
|
|
3429 |
c = dojo.keys.TAB; // morph SHIFT_TAB into TAB + shiftKey: true
|
|
|
3430 |
s = true;
|
|
|
3431 |
} else {
|
|
|
3432 |
c = (c>=32 && c<63232 ? c : 0); // avoid generating keyChar for non-printables
|
|
|
3433 |
}
|
|
|
3434 |
return del._synthesizeEvent(evt, {charCode: c, shiftKey: s, keyCode: k});
|
|
|
3435 |
}
|
|
|
3436 |
return evt;
|
|
|
3437 |
}
|
|
|
3438 |
});
|
|
|
3439 |
|
|
|
3440 |
dojo.mixin(dojo.keys, {
|
|
|
3441 |
SHIFT_TAB: 25,
|
|
|
3442 |
UP_ARROW: 63232,
|
|
|
3443 |
DOWN_ARROW: 63233,
|
|
|
3444 |
LEFT_ARROW: 63234,
|
|
|
3445 |
RIGHT_ARROW: 63235,
|
|
|
3446 |
F1: 63236,
|
|
|
3447 |
F2: 63237,
|
|
|
3448 |
F3: 63238,
|
|
|
3449 |
F4: 63239,
|
|
|
3450 |
F5: 63240,
|
|
|
3451 |
F6: 63241,
|
|
|
3452 |
F7: 63242,
|
|
|
3453 |
F8: 63243,
|
|
|
3454 |
F9: 63244,
|
|
|
3455 |
F10: 63245,
|
|
|
3456 |
F11: 63246,
|
|
|
3457 |
F12: 63247,
|
|
|
3458 |
PAUSE: 63250,
|
|
|
3459 |
DELETE: 63272,
|
|
|
3460 |
HOME: 63273,
|
|
|
3461 |
END: 63275,
|
|
|
3462 |
PAGE_UP: 63276,
|
|
|
3463 |
PAGE_DOWN: 63277,
|
|
|
3464 |
INSERT: 63302,
|
|
|
3465 |
PRINT_SCREEN: 63248,
|
|
|
3466 |
SCROLL_LOCK: 63249,
|
|
|
3467 |
NUM_LOCK: 63289
|
|
|
3468 |
});
|
|
|
3469 |
var dk = dojo.keys, identifierMap = { "Up": dk.UP_ARROW, "Down": dk.DOWN_ARROW, "Left": dk.LEFT_ARROW, "Right": dk.RIGHT_ARROW, "PageUp": dk.PAGE_UP, "PageDown": dk.PAGE_DOWN };
|
|
|
3470 |
}
|
|
|
3471 |
})();
|
|
|
3472 |
|
|
|
3473 |
if(dojo.isIE){
|
|
|
3474 |
// keep this out of the closure
|
|
|
3475 |
// closing over 'iel' or 'ieh' b0rks leak prevention
|
|
|
3476 |
// ls[i] is an index into the master handler array
|
|
|
3477 |
dojo._getIeDispatcher = function(){
|
|
|
3478 |
return function(){
|
|
|
3479 |
var ap=Array.prototype, h=dojo._ie_listener.handlers, c=arguments.callee, ls=c._listeners, t=h[c.target];
|
|
|
3480 |
// return value comes from original target function
|
|
|
3481 |
var r = t && t.apply(this, arguments);
|
|
|
3482 |
// invoke listeners after target function
|
|
|
3483 |
for(var i in ls){
|
|
|
3484 |
if(!(i in ap)){
|
|
|
3485 |
h[ls[i]].apply(this, arguments);
|
|
|
3486 |
}
|
|
|
3487 |
}
|
|
|
3488 |
return r;
|
|
|
3489 |
}
|
|
|
3490 |
}
|
|
|
3491 |
// keep this out of the closure to reduce RAM allocation
|
|
|
3492 |
dojo._event_listener._fixCallback = function(fp){
|
|
|
3493 |
var f = dojo._event_listener._fixEvent;
|
|
|
3494 |
return function(e){ return fp.call(this, f(e, this)); };
|
|
|
3495 |
}
|
|
|
3496 |
}
|
|
|
3497 |
|
|
|
3498 |
}
|
|
|
3499 |
|
|
|
3500 |
if(!dojo._hasResource["dojo._base.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
3501 |
dojo._hasResource["dojo._base.html"] = true;
|
|
|
3502 |
|
|
|
3503 |
dojo.provide("dojo._base.html");
|
|
|
3504 |
|
|
|
3505 |
// FIXME: need to add unit tests for all the semi-public methods
|
|
|
3506 |
|
|
|
3507 |
try{
|
|
|
3508 |
document.execCommand("BackgroundImageCache", false, true);
|
|
|
3509 |
}catch(e){
|
|
|
3510 |
// sane browsers don't have cache "issues"
|
|
|
3511 |
}
|
|
|
3512 |
|
|
|
3513 |
// =============================
|
|
|
3514 |
// DOM Functions
|
|
|
3515 |
// =============================
|
|
|
3516 |
|
|
|
3517 |
/*=====
|
|
|
3518 |
dojo.byId = function(id, doc){
|
|
|
3519 |
// summary:
|
|
|
3520 |
// similar to other library's "$" function, takes a
|
|
|
3521 |
// string representing a DOM id or a DomNode
|
|
|
3522 |
// and returns the corresponding DomNode. If a Node is
|
|
|
3523 |
// passed, this function is a no-op. Returns a
|
|
|
3524 |
// single DOM node or null, working around several
|
|
|
3525 |
// browser-specific bugs to do so.
|
|
|
3526 |
// id: String|DOMNode
|
|
|
3527 |
// DOM id or DOM Node
|
|
|
3528 |
// doc: DocumentElement
|
|
|
3529 |
// Document to work in. Defaults to the current value of
|
|
|
3530 |
// dojo.doc. Can be used to retreive
|
|
|
3531 |
// node references from other documents.
|
|
|
3532 |
=====*/
|
|
|
3533 |
if(dojo.isIE || dojo.isOpera){
|
|
|
3534 |
dojo.byId = function(id, doc){
|
|
|
3535 |
if(dojo.isString(id)){
|
|
|
3536 |
var _d = doc || dojo.doc;
|
|
|
3537 |
var te = _d.getElementById(id);
|
|
|
3538 |
// attributes.id.value is better than just id in case the
|
|
|
3539 |
// user has a name=id inside a form
|
|
|
3540 |
if(te && te.attributes.id.value == id){
|
|
|
3541 |
return te;
|
|
|
3542 |
}else{
|
|
|
3543 |
var eles = _d.all[id];
|
|
|
3544 |
if(!eles){ return; }
|
|
|
3545 |
if(!eles.length){ return eles; }
|
|
|
3546 |
// if more than 1, choose first with the correct id
|
|
|
3547 |
var i=0;
|
|
|
3548 |
while((te=eles[i++])){
|
|
|
3549 |
if(te.attributes.id.value == id){ return te; }
|
|
|
3550 |
}
|
|
|
3551 |
}
|
|
|
3552 |
}else{
|
|
|
3553 |
return id; // DomNode
|
|
|
3554 |
}
|
|
|
3555 |
}
|
|
|
3556 |
}else{
|
|
|
3557 |
dojo.byId = function(id, doc){
|
|
|
3558 |
if(dojo.isString(id)){
|
|
|
3559 |
return (doc || dojo.doc).getElementById(id);
|
|
|
3560 |
}else{
|
|
|
3561 |
return id; // DomNode
|
|
|
3562 |
}
|
|
|
3563 |
}
|
|
|
3564 |
}
|
|
|
3565 |
/*=====
|
|
|
3566 |
}
|
|
|
3567 |
=====*/
|
|
|
3568 |
|
|
|
3569 |
(function(){
|
|
|
3570 |
/*
|
|
|
3571 |
dojo.createElement = function(obj, parent, position){
|
|
|
3572 |
// TODO: need to finish this!
|
|
|
3573 |
}
|
|
|
3574 |
*/
|
|
|
3575 |
|
|
|
3576 |
var _destroyContainer = null;
|
|
|
3577 |
dojo._destroyElement = function(/*String||DomNode*/node){
|
|
|
3578 |
// summary:
|
|
|
3579 |
// removes node from its parent, clobbers it and all of its
|
|
|
3580 |
// children.
|
|
|
3581 |
// node:
|
|
|
3582 |
// the element to be destroyed, either as an ID or a reference
|
|
|
3583 |
|
|
|
3584 |
node = dojo.byId(node);
|
|
|
3585 |
try{
|
|
|
3586 |
if(!_destroyContainer){
|
|
|
3587 |
_destroyContainer = document.createElement("div");
|
|
|
3588 |
}
|
|
|
3589 |
_destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node);
|
|
|
3590 |
// NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature
|
|
|
3591 |
_destroyContainer.innerHTML = "";
|
|
|
3592 |
}catch(e){
|
|
|
3593 |
/* squelch */
|
|
|
3594 |
}
|
|
|
3595 |
};
|
|
|
3596 |
|
|
|
3597 |
dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){
|
|
|
3598 |
// summary:
|
|
|
3599 |
// Returns true if node is a descendant of ancestor
|
|
|
3600 |
// node: id or node reference to test
|
|
|
3601 |
// ancestor: id or node reference of potential parent to test against
|
|
|
3602 |
try{
|
|
|
3603 |
node = dojo.byId(node);
|
|
|
3604 |
ancestor = dojo.byId(ancestor);
|
|
|
3605 |
while(node){
|
|
|
3606 |
if(node === ancestor){
|
|
|
3607 |
return true; // Boolean
|
|
|
3608 |
}
|
|
|
3609 |
node = node.parentNode;
|
|
|
3610 |
}
|
|
|
3611 |
}catch(e){ return -1; /* squelch */ }
|
|
|
3612 |
return false; // Boolean
|
|
|
3613 |
};
|
|
|
3614 |
|
|
|
3615 |
dojo.setSelectable = function(/*DomNode|String*/node, /*Boolean*/selectable){
|
|
|
3616 |
// summary: enable or disable selection on a node
|
|
|
3617 |
// node:
|
|
|
3618 |
// id or reference to node
|
|
|
3619 |
// selectable:
|
|
|
3620 |
node = dojo.byId(node);
|
|
|
3621 |
if(dojo.isMozilla){
|
|
|
3622 |
node.style.MozUserSelect = selectable ? "" : "none";
|
|
|
3623 |
}else if(dojo.isKhtml){
|
|
|
3624 |
node.style.KhtmlUserSelect = selectable ? "auto" : "none";
|
|
|
3625 |
}else if(dojo.isIE){
|
|
|
3626 |
node.unselectable = selectable ? "" : "on";
|
|
|
3627 |
dojo.query("*", node).forEach(function(descendant){
|
|
|
3628 |
descendant.unselectable = selectable ? "" : "on";
|
|
|
3629 |
});
|
|
|
3630 |
}
|
|
|
3631 |
//FIXME: else? Opera?
|
|
|
3632 |
};
|
|
|
3633 |
|
|
|
3634 |
var _insertBefore = function(/*Node*/node, /*Node*/ref){
|
|
|
3635 |
ref.parentNode.insertBefore(node, ref);
|
|
|
3636 |
return true; // boolean
|
|
|
3637 |
}
|
|
|
3638 |
|
|
|
3639 |
var _insertAfter = function(/*Node*/node, /*Node*/ref){
|
|
|
3640 |
// summary:
|
|
|
3641 |
// Try to insert node after ref
|
|
|
3642 |
var pn = ref.parentNode;
|
|
|
3643 |
if(ref == pn.lastChild){
|
|
|
3644 |
pn.appendChild(node);
|
|
|
3645 |
}else{
|
|
|
3646 |
return _insertBefore(node, ref.nextSibling); // boolean
|
|
|
3647 |
}
|
|
|
3648 |
return true; // boolean
|
|
|
3649 |
}
|
|
|
3650 |
|
|
|
3651 |
dojo.place = function(/*String|DomNode*/node, /*String|DomNode*/refNode, /*String|Number*/position){
|
|
|
3652 |
// summary:
|
|
|
3653 |
// attempt to insert node in relation to ref based on position
|
|
|
3654 |
// node:
|
|
|
3655 |
// id or reference to node to place relative to refNode
|
|
|
3656 |
// refNode:
|
|
|
3657 |
// id or reference of node to use as basis for placement
|
|
|
3658 |
// position:
|
|
|
3659 |
// string noting the position of node relative to refNode or a
|
|
|
3660 |
// number indicating the location in the childNodes collection of
|
|
|
3661 |
// refNode. Accepted string values are:
|
|
|
3662 |
// * before
|
|
|
3663 |
// * after
|
|
|
3664 |
// * first
|
|
|
3665 |
// * last
|
|
|
3666 |
// "first" and "last" indicate positions as children of refNode.
|
|
|
3667 |
|
|
|
3668 |
// FIXME: need to write tests for this!!!!
|
|
|
3669 |
if(!node || !refNode || position === undefined){
|
|
|
3670 |
return false; // boolean
|
|
|
3671 |
}
|
|
|
3672 |
node = dojo.byId(node);
|
|
|
3673 |
refNode = dojo.byId(refNode);
|
|
|
3674 |
if(typeof position == "number"){
|
|
|
3675 |
var cn = refNode.childNodes;
|
|
|
3676 |
if((position == 0 && cn.length == 0) ||
|
|
|
3677 |
cn.length == position){
|
|
|
3678 |
refNode.appendChild(node); return true;
|
|
|
3679 |
}
|
|
|
3680 |
if(position == 0){
|
|
|
3681 |
return _insertBefore(node, refNode.firstChild);
|
|
|
3682 |
}
|
|
|
3683 |
return _insertAfter(node, cn[position-1]);
|
|
|
3684 |
}
|
|
|
3685 |
switch(position.toLowerCase()){
|
|
|
3686 |
case "before":
|
|
|
3687 |
return _insertBefore(node, refNode); // boolean
|
|
|
3688 |
case "after":
|
|
|
3689 |
return _insertAfter(node, refNode); // boolean
|
|
|
3690 |
case "first":
|
|
|
3691 |
if(refNode.firstChild){
|
|
|
3692 |
return _insertBefore(node, refNode.firstChild); // boolean
|
|
|
3693 |
}else{
|
|
|
3694 |
refNode.appendChild(node);
|
|
|
3695 |
return true; // boolean
|
|
|
3696 |
}
|
|
|
3697 |
break;
|
|
|
3698 |
default: // aka: last
|
|
|
3699 |
refNode.appendChild(node);
|
|
|
3700 |
return true; // boolean
|
|
|
3701 |
}
|
|
|
3702 |
}
|
|
|
3703 |
|
|
|
3704 |
// Box functions will assume this model.
|
|
|
3705 |
// On IE/Opera, BORDER_BOX will be set if the primary document is in quirks mode.
|
|
|
3706 |
// Can be set to change behavior of box setters.
|
|
|
3707 |
|
|
|
3708 |
// can be either:
|
|
|
3709 |
// "border-box"
|
|
|
3710 |
// "content-box" (default)
|
|
|
3711 |
dojo.boxModel = "content-box";
|
|
|
3712 |
|
|
|
3713 |
// We punt per-node box mode testing completely.
|
|
|
3714 |
// If anybody cares, we can provide an additional (optional) unit
|
|
|
3715 |
// that overrides existing code to include per-node box sensitivity.
|
|
|
3716 |
|
|
|
3717 |
// Opera documentation claims that Opera 9 uses border-box in BackCompat mode.
|
|
|
3718 |
// but experiments (Opera 9.10.8679 on Windows Vista) indicate that it actually continues to use content-box.
|
|
|
3719 |
// IIRC, earlier versions of Opera did in fact use border-box.
|
|
|
3720 |
// Opera guys, this is really confusing. Opera being broken in quirks mode is not our fault.
|
|
|
3721 |
|
|
|
3722 |
if(dojo.isIE /*|| dojo.isOpera*/){
|
|
|
3723 |
var _dcm = document.compatMode;
|
|
|
3724 |
// client code may have to adjust if compatMode varies across iframes
|
|
|
3725 |
dojo.boxModel = (_dcm=="BackCompat")||(_dcm=="QuirksMode")||(dojo.isIE<6) ? "border-box" : "content-box";
|
|
|
3726 |
}
|
|
|
3727 |
|
|
|
3728 |
// =============================
|
|
|
3729 |
// Style Functions
|
|
|
3730 |
// =============================
|
|
|
3731 |
|
|
|
3732 |
// getComputedStyle drives most of the style code.
|
|
|
3733 |
// Wherever possible, reuse the returned object.
|
|
|
3734 |
//
|
|
|
3735 |
// API functions below that need to access computed styles accept an
|
|
|
3736 |
// optional computedStyle parameter.
|
|
|
3737 |
//
|
|
|
3738 |
// If this parameter is omitted, the functions will call getComputedStyle themselves.
|
|
|
3739 |
//
|
|
|
3740 |
// This way, calling code can access computedStyle once, and then pass the reference to
|
|
|
3741 |
// multiple API functions.
|
|
|
3742 |
//
|
|
|
3743 |
// This is a faux declaration to take pity on the doc tool
|
|
|
3744 |
|
|
|
3745 |
/*=====
|
|
|
3746 |
dojo.getComputedStyle = function(node){
|
|
|
3747 |
// summary:
|
|
|
3748 |
// Returns a "computed style" object.
|
|
|
3749 |
// description:
|
|
|
3750 |
// get "computed style" object which can be used to gather
|
|
|
3751 |
// information about the current state of the rendered node.
|
|
|
3752 |
//
|
|
|
3753 |
// Note that this may behave differently on different browsers.
|
|
|
3754 |
// Values may have different formats and value encodings across
|
|
|
3755 |
// browsers.
|
|
|
3756 |
//
|
|
|
3757 |
// Use the dojo.style() method for more consistent (pixelized)
|
|
|
3758 |
// return values.
|
|
|
3759 |
// node: DOMNode
|
|
|
3760 |
// a reference to a DOM node. Does NOT support taking an
|
|
|
3761 |
// ID string for speed reasons.
|
|
|
3762 |
// example:
|
|
|
3763 |
// | dojo.getComputedStyle(dojo.byId('foo')).borderWidth;
|
|
|
3764 |
return; // CSS2Properties
|
|
|
3765 |
}
|
|
|
3766 |
=====*/
|
|
|
3767 |
|
|
|
3768 |
var gcs, dv = document.defaultView;
|
|
|
3769 |
if(dojo.isSafari){
|
|
|
3770 |
gcs = function(/*DomNode*/node){
|
|
|
3771 |
var s = dv.getComputedStyle(node, null);
|
|
|
3772 |
if(!s && node.style){
|
|
|
3773 |
node.style.display = "";
|
|
|
3774 |
s = dv.getComputedStyle(node, null);
|
|
|
3775 |
}
|
|
|
3776 |
return s || {};
|
|
|
3777 |
};
|
|
|
3778 |
}else if(dojo.isIE){
|
|
|
3779 |
gcs = function(node){
|
|
|
3780 |
return node.currentStyle;
|
|
|
3781 |
};
|
|
|
3782 |
}else{
|
|
|
3783 |
gcs = function(node){
|
|
|
3784 |
return dv.getComputedStyle(node, null);
|
|
|
3785 |
};
|
|
|
3786 |
}
|
|
|
3787 |
dojo.getComputedStyle = gcs;
|
|
|
3788 |
|
|
|
3789 |
if(!dojo.isIE){
|
|
|
3790 |
dojo._toPixelValue = function(element, value){
|
|
|
3791 |
// style values can be floats, client code may want
|
|
|
3792 |
// to round for integer pixels.
|
|
|
3793 |
return parseFloat(value) || 0;
|
|
|
3794 |
}
|
|
|
3795 |
}else{
|
|
|
3796 |
dojo._toPixelValue = function(element, avalue){
|
|
|
3797 |
if(!avalue){ return 0; }
|
|
|
3798 |
// on IE7, medium is usually 4 pixels
|
|
|
3799 |
if(avalue=="medium"){ return 4; }
|
|
|
3800 |
// style values can be floats, client code may
|
|
|
3801 |
// want to round this value for integer pixels.
|
|
|
3802 |
if(avalue.slice && (avalue.slice(-2)=='px')){ return parseFloat(avalue); }
|
|
|
3803 |
with(element){
|
|
|
3804 |
var sLeft = style.left;
|
|
|
3805 |
var rsLeft = runtimeStyle.left;
|
|
|
3806 |
runtimeStyle.left = currentStyle.left;
|
|
|
3807 |
try{
|
|
|
3808 |
// 'avalue' may be incompatible with style.left, which can cause IE to throw
|
|
|
3809 |
// this has been observed for border widths using "thin", "medium", "thick" constants
|
|
|
3810 |
// those particular constants could be trapped by a lookup
|
|
|
3811 |
// but perhaps there are more
|
|
|
3812 |
style.left = avalue;
|
|
|
3813 |
avalue = style.pixelLeft;
|
|
|
3814 |
}catch(e){
|
|
|
3815 |
avalue = 0;
|
|
|
3816 |
}
|
|
|
3817 |
style.left = sLeft;
|
|
|
3818 |
runtimeStyle.left = rsLeft;
|
|
|
3819 |
}
|
|
|
3820 |
return avalue;
|
|
|
3821 |
}
|
|
|
3822 |
}
|
|
|
3823 |
|
|
|
3824 |
// FIXME: there opacity quirks on FF that we haven't ported over. Hrm.
|
|
|
3825 |
/*=====
|
|
|
3826 |
dojo._getOpacity = function(node){
|
|
|
3827 |
// summary:
|
|
|
3828 |
// Returns the current opacity of the passed node as a
|
|
|
3829 |
// floating-point value between 0 and 1.
|
|
|
3830 |
// node: DomNode
|
|
|
3831 |
// a reference to a DOM node. Does NOT support taking an
|
|
|
3832 |
// ID string for speed reasons.
|
|
|
3833 |
// return: Number between 0 and 1
|
|
|
3834 |
}
|
|
|
3835 |
=====*/
|
|
|
3836 |
|
|
|
3837 |
dojo._getOpacity = (dojo.isIE ? function(node){
|
|
|
3838 |
try{
|
|
|
3839 |
return (node.filters.alpha.opacity / 100); // Number
|
|
|
3840 |
}catch(e){
|
|
|
3841 |
return 1; // Number
|
|
|
3842 |
}
|
|
|
3843 |
} : function(node){
|
|
|
3844 |
return dojo.getComputedStyle(node).opacity;
|
|
|
3845 |
}
|
|
|
3846 |
);
|
|
|
3847 |
|
|
|
3848 |
/*=====
|
|
|
3849 |
dojo._setOpacity = function(node, opacity){
|
|
|
3850 |
// summary:
|
|
|
3851 |
// set the opacity of the passed node portably. Returns the
|
|
|
3852 |
// new opacity of the node.
|
|
|
3853 |
// node: DOMNode
|
|
|
3854 |
// a reference to a DOM node. Does NOT support taking an
|
|
|
3855 |
// ID string for performance reasons.
|
|
|
3856 |
// opacity: Number
|
|
|
3857 |
// A Number between 0 and 1. 0 specifies transparent.
|
|
|
3858 |
// return: Number between 0 and 1
|
|
|
3859 |
}
|
|
|
3860 |
=====*/
|
|
|
3861 |
|
|
|
3862 |
dojo._setOpacity = (dojo.isIE ? function(/*DomNode*/node, /*Number*/opacity){
|
|
|
3863 |
if(opacity == 1){
|
|
|
3864 |
// on IE7 Alpha(Filter opacity=100) makes text look fuzzy so remove it altogether (bug #2661)
|
|
|
3865 |
node.style.cssText = node.style.cssText.replace(/FILTER:[^;]*;/i, "");
|
|
|
3866 |
if(node.nodeName.toLowerCase() == "tr"){
|
|
|
3867 |
dojo.query("> td", node).forEach(function(i){
|
|
|
3868 |
i.style.cssText = i.style.cssText.replace(/FILTER:[^;]*;/i, "");
|
|
|
3869 |
});
|
|
|
3870 |
}
|
|
|
3871 |
}else{
|
|
|
3872 |
var o = "Alpha(Opacity="+(opacity*100)+")";
|
|
|
3873 |
node.style.filter = o;
|
|
|
3874 |
}
|
|
|
3875 |
if(node.nodeName.toLowerCase() == "tr"){
|
|
|
3876 |
dojo.query("> td", node).forEach(function(i){
|
|
|
3877 |
i.style.filter = o;
|
|
|
3878 |
});
|
|
|
3879 |
}
|
|
|
3880 |
return opacity;
|
|
|
3881 |
} : function(node, opacity){
|
|
|
3882 |
return node.style.opacity = opacity;
|
|
|
3883 |
}
|
|
|
3884 |
);
|
|
|
3885 |
|
|
|
3886 |
var _pixelNamesCache = {
|
|
|
3887 |
width: true, height: true, left: true, top: true
|
|
|
3888 |
};
|
|
|
3889 |
var _toStyleValue = function(node, type, value){
|
|
|
3890 |
type = type.toLowerCase();
|
|
|
3891 |
if(_pixelNamesCache[type] === true){
|
|
|
3892 |
return dojo._toPixelValue(node, value)
|
|
|
3893 |
}else if(_pixelNamesCache[type] === false){
|
|
|
3894 |
return value;
|
|
|
3895 |
}else{
|
|
|
3896 |
if(dojo.isOpera && type == "cssText"){
|
|
|
3897 |
// FIXME: add workaround for #2855 here
|
|
|
3898 |
}
|
|
|
3899 |
if(
|
|
|
3900 |
(type.indexOf("margin") >= 0) ||
|
|
|
3901 |
// (type.indexOf("border") >= 0) ||
|
|
|
3902 |
(type.indexOf("padding") >= 0) ||
|
|
|
3903 |
(type.indexOf("width") >= 0) ||
|
|
|
3904 |
(type.indexOf("height") >= 0) ||
|
|
|
3905 |
(type.indexOf("max") >= 0) ||
|
|
|
3906 |
(type.indexOf("min") >= 0) ||
|
|
|
3907 |
(type.indexOf("offset") >= 0)
|
|
|
3908 |
){
|
|
|
3909 |
_pixelNamesCache[type] = true;
|
|
|
3910 |
return dojo._toPixelValue(node, value)
|
|
|
3911 |
}else{
|
|
|
3912 |
_pixelNamesCache[type] = false;
|
|
|
3913 |
return value;
|
|
|
3914 |
}
|
|
|
3915 |
}
|
|
|
3916 |
}
|
|
|
3917 |
|
|
|
3918 |
// public API
|
|
|
3919 |
|
|
|
3920 |
dojo.style = function(/*DomNode|String*/ node, /*String*/style, /*String?*/value){
|
|
|
3921 |
// summary:
|
|
|
3922 |
// gets or sets a style property on node. If 2 arguments are
|
|
|
3923 |
// passed, acts as a getter. If value is passed, acts as a setter
|
|
|
3924 |
// for the property.
|
|
|
3925 |
// node:
|
|
|
3926 |
// id or reference to node to get/set style for
|
|
|
3927 |
// style:
|
|
|
3928 |
// the style property to set in DOM-accessor format
|
|
|
3929 |
// ("borderWidth", not "border-width").
|
|
|
3930 |
// value:
|
|
|
3931 |
// optional. If passed, sets value on the node for style, handling
|
|
|
3932 |
// cross-browser concerns.
|
|
|
3933 |
var n=dojo.byId(node), args=arguments.length, op=(style=="opacity");
|
|
|
3934 |
if(args==3){
|
|
|
3935 |
return op ? dojo._setOpacity(n, value) : n.style[style] = value; /*Number*/
|
|
|
3936 |
}
|
|
|
3937 |
if(args==2 && op){
|
|
|
3938 |
return dojo._getOpacity(n);
|
|
|
3939 |
}
|
|
|
3940 |
var s = dojo.getComputedStyle(n);
|
|
|
3941 |
return (args == 1) ? s : _toStyleValue(n, style, s[style]); /* CSS2Properties||String||Number */
|
|
|
3942 |
}
|
|
|
3943 |
|
|
|
3944 |
// =============================
|
|
|
3945 |
// Box Functions
|
|
|
3946 |
// =============================
|
|
|
3947 |
|
|
|
3948 |
dojo._getPadExtents = function(/*DomNode*/n, /*Object*/computedStyle){
|
|
|
3949 |
// summary:
|
|
|
3950 |
// Returns object with special values specifically useful for node
|
|
|
3951 |
// fitting.
|
|
|
3952 |
// l/t = left/top padding (respectively)
|
|
|
3953 |
// w = the total of the left and right padding
|
|
|
3954 |
// h = the total of the top and bottom padding
|
|
|
3955 |
// If 'node' has position, l/t forms the origin for child nodes.
|
|
|
3956 |
// The w/h are used for calculating boxes.
|
|
|
3957 |
// Normally application code will not need to invoke this
|
|
|
3958 |
// directly, and will use the ...box... functions instead.
|
|
|
3959 |
var
|
|
|
3960 |
s=computedStyle||gcs(n),
|
|
|
3961 |
px=dojo._toPixelValue,
|
|
|
3962 |
l=px(n, s.paddingLeft),
|
|
|
3963 |
t=px(n, s.paddingTop);
|
|
|
3964 |
return {
|
|
|
3965 |
l: l,
|
|
|
3966 |
t: t,
|
|
|
3967 |
w: l+px(n, s.paddingRight),
|
|
|
3968 |
h: t+px(n, s.paddingBottom)
|
|
|
3969 |
};
|
|
|
3970 |
}
|
|
|
3971 |
|
|
|
3972 |
dojo._getBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
|
|
|
3973 |
// summary:
|
|
|
3974 |
// returns an object with properties useful for noting the border
|
|
|
3975 |
// dimensions.
|
|
|
3976 |
// l/t = the sum of left/top border (respectively)
|
|
|
3977 |
// w = the sum of the left and right border
|
|
|
3978 |
// h = the sum of the top and bottom border
|
|
|
3979 |
// The w/h are used for calculating boxes.
|
|
|
3980 |
// Normally application code will not need to invoke this
|
|
|
3981 |
// directly, and will use the ...box... functions instead.
|
|
|
3982 |
var
|
|
|
3983 |
ne='none',
|
|
|
3984 |
px=dojo._toPixelValue,
|
|
|
3985 |
s=computedStyle||gcs(n),
|
|
|
3986 |
bl=(s.borderLeftStyle!=ne ? px(n, s.borderLeftWidth) : 0),
|
|
|
3987 |
bt=(s.borderTopStyle!=ne ? px(n, s.borderTopWidth) : 0);
|
|
|
3988 |
return {
|
|
|
3989 |
l: bl,
|
|
|
3990 |
t: bt,
|
|
|
3991 |
w: bl + (s.borderRightStyle!=ne ? px(n, s.borderRightWidth) : 0),
|
|
|
3992 |
h: bt + (s.borderBottomStyle!=ne ? px(n, s.borderBottomWidth) : 0)
|
|
|
3993 |
};
|
|
|
3994 |
}
|
|
|
3995 |
|
|
|
3996 |
dojo._getPadBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
|
|
|
3997 |
// summary:
|
|
|
3998 |
// returns object with properties useful for box fitting with
|
|
|
3999 |
// regards to padding.
|
|
|
4000 |
// l/t = the sum of left/top padding and left/top border (respectively)
|
|
|
4001 |
// w = the sum of the left and right padding and border
|
|
|
4002 |
// h = the sum of the top and bottom padding and border
|
|
|
4003 |
// The w/h are used for calculating boxes.
|
|
|
4004 |
// Normally application code will not need to invoke this
|
|
|
4005 |
// directly, and will use the ...box... functions instead.
|
|
|
4006 |
var
|
|
|
4007 |
s=computedStyle||gcs(n),
|
|
|
4008 |
p=dojo._getPadExtents(n, s),
|
|
|
4009 |
b=dojo._getBorderExtents(n, s);
|
|
|
4010 |
return {
|
|
|
4011 |
l: p.l + b.l,
|
|
|
4012 |
t: p.t + b.t,
|
|
|
4013 |
w: p.w + b.w,
|
|
|
4014 |
h: p.h + b.h
|
|
|
4015 |
};
|
|
|
4016 |
}
|
|
|
4017 |
|
|
|
4018 |
dojo._getMarginExtents = function(n, computedStyle){
|
|
|
4019 |
// summary:
|
|
|
4020 |
// returns object with properties useful for box fitting with
|
|
|
4021 |
// regards to box margins (i.e., the outer-box).
|
|
|
4022 |
// l/t = marginLeft, marginTop, respectively
|
|
|
4023 |
// w = total width, margin inclusive
|
|
|
4024 |
// h = total height, margin inclusive
|
|
|
4025 |
// The w/h are used for calculating boxes.
|
|
|
4026 |
// Normally application code will not need to invoke this
|
|
|
4027 |
// directly, and will use the ...box... functions instead.
|
|
|
4028 |
var
|
|
|
4029 |
s=computedStyle||gcs(n),
|
|
|
4030 |
px=dojo._toPixelValue,
|
|
|
4031 |
l=px(n, s.marginLeft),
|
|
|
4032 |
t=px(n, s.marginTop),
|
|
|
4033 |
r=px(n, s.marginRight),
|
|
|
4034 |
b=px(n, s.marginBottom);
|
|
|
4035 |
if (dojo.isSafari && (s.position != "absolute")){
|
|
|
4036 |
// FIXME: Safari's version of the computed right margin
|
|
|
4037 |
// is the space between our right edge and the right edge
|
|
|
4038 |
// of our offsetParent.
|
|
|
4039 |
// What we are looking for is the actual margin value as
|
|
|
4040 |
// determined by CSS.
|
|
|
4041 |
// Hack solution is to assume left/right margins are the same.
|
|
|
4042 |
r = l;
|
|
|
4043 |
}
|
|
|
4044 |
return {
|
|
|
4045 |
l: l,
|
|
|
4046 |
t: t,
|
|
|
4047 |
w: l+r,
|
|
|
4048 |
h: t+b
|
|
|
4049 |
};
|
|
|
4050 |
}
|
|
|
4051 |
|
|
|
4052 |
// Box getters work in any box context because offsetWidth/clientWidth
|
|
|
4053 |
// are invariant wrt box context
|
|
|
4054 |
//
|
|
|
4055 |
// They do *not* work for display: inline objects that have padding styles
|
|
|
4056 |
// because the user agent ignores padding (it's bogus styling in any case)
|
|
|
4057 |
//
|
|
|
4058 |
// Be careful with IMGs because they are inline or block depending on
|
|
|
4059 |
// browser and browser mode.
|
|
|
4060 |
|
|
|
4061 |
// Although it would be easier to read, there are not separate versions of
|
|
|
4062 |
// _getMarginBox for each browser because:
|
|
|
4063 |
// 1. the branching is not expensive
|
|
|
4064 |
// 2. factoring the shared code wastes cycles (function call overhead)
|
|
|
4065 |
// 3. duplicating the shared code wastes bytes
|
|
|
4066 |
|
|
|
4067 |
dojo._getMarginBox = function(/*DomNode*/node, /*Object*/computedStyle){
|
|
|
4068 |
// summary:
|
|
|
4069 |
// returns an object that encodes the width, height, left and top
|
|
|
4070 |
// positions of the node's margin box.
|
|
|
4071 |
var s = computedStyle||gcs(node), me = dojo._getMarginExtents(node, s);
|
|
|
4072 |
var l = node.offsetLeft - me.l, t = node.offsetTop - me.t;
|
|
|
4073 |
if(dojo.isMoz){
|
|
|
4074 |
// Mozilla:
|
|
|
4075 |
// If offsetParent has a computed overflow != visible, the offsetLeft is decreased
|
|
|
4076 |
// by the parent's border.
|
|
|
4077 |
// We don't want to compute the parent's style, so instead we examine node's
|
|
|
4078 |
// computed left/top which is more stable.
|
|
|
4079 |
var sl = parseFloat(s.left), st = parseFloat(s.top);
|
|
|
4080 |
if(!isNaN(sl) && !isNaN(st)){
|
|
|
4081 |
l = sl, t = st;
|
|
|
4082 |
}else{
|
|
|
4083 |
// If child's computed left/top are not parseable as a number (e.g. "auto"), we
|
|
|
4084 |
// have no choice but to examine the parent's computed style.
|
|
|
4085 |
var p = node.parentNode;
|
|
|
4086 |
if(p && p.style){
|
|
|
4087 |
var pcs = gcs(p);
|
|
|
4088 |
if(pcs.overflow != "visible"){
|
|
|
4089 |
var be = dojo._getBorderExtents(p, pcs);
|
|
|
4090 |
l += be.l, t += be.t;
|
|
|
4091 |
}
|
|
|
4092 |
}
|
|
|
4093 |
}
|
|
|
4094 |
}else if(dojo.isOpera){
|
|
|
4095 |
// On Opera, offsetLeft includes the parent's border
|
|
|
4096 |
var p = node.parentNode;
|
|
|
4097 |
if(p){
|
|
|
4098 |
var be = dojo._getBorderExtents(p);
|
|
|
4099 |
l -= be.l, t -= be.t;
|
|
|
4100 |
}
|
|
|
4101 |
}
|
|
|
4102 |
return {
|
|
|
4103 |
l: l,
|
|
|
4104 |
t: t,
|
|
|
4105 |
w: node.offsetWidth + me.w,
|
|
|
4106 |
h: node.offsetHeight + me.h
|
|
|
4107 |
};
|
|
|
4108 |
}
|
|
|
4109 |
|
|
|
4110 |
dojo._getContentBox = function(node, computedStyle){
|
|
|
4111 |
// summary:
|
|
|
4112 |
// Returns an object that encodes the width, height, left and top
|
|
|
4113 |
// positions of the node's content box, irrespective of the
|
|
|
4114 |
// current box model.
|
|
|
4115 |
|
|
|
4116 |
// clientWidth/Height are important since the automatically account for scrollbars
|
|
|
4117 |
// fallback to offsetWidth/Height for special cases (see #3378)
|
|
|
4118 |
var s=computedStyle||gcs(node), pe=dojo._getPadExtents(node, s), be=dojo._getBorderExtents(node, s), w=node.clientWidth, h;
|
|
|
4119 |
if(!w){
|
|
|
4120 |
w=node.offsetWidth, h=node.offsetHeight;
|
|
|
4121 |
}else{
|
|
|
4122 |
h=node.clientHeight, be.w = be.h = 0;
|
|
|
4123 |
}
|
|
|
4124 |
// On Opera, offsetLeft includes the parent's border
|
|
|
4125 |
if(dojo.isOpera){ pe.l += be.l; pe.t += be.t; };
|
|
|
4126 |
return {
|
|
|
4127 |
l: pe.l,
|
|
|
4128 |
t: pe.t,
|
|
|
4129 |
w: w - pe.w - be.w,
|
|
|
4130 |
h: h - pe.h - be.h
|
|
|
4131 |
};
|
|
|
4132 |
}
|
|
|
4133 |
|
|
|
4134 |
dojo._getBorderBox = function(node, computedStyle){
|
|
|
4135 |
var s=computedStyle||gcs(node), pe=dojo._getPadExtents(node, s), cb=dojo._getContentBox(node, s);
|
|
|
4136 |
return {
|
|
|
4137 |
l: cb.l - pe.l,
|
|
|
4138 |
t: cb.t - pe.t,
|
|
|
4139 |
w: cb.w + pe.w,
|
|
|
4140 |
h: cb.h + pe.h
|
|
|
4141 |
};
|
|
|
4142 |
}
|
|
|
4143 |
|
|
|
4144 |
// Box setters depend on box context because interpretation of width/height styles
|
|
|
4145 |
// vary wrt box context.
|
|
|
4146 |
//
|
|
|
4147 |
// The value of dojo.boxModel is used to determine box context.
|
|
|
4148 |
// dojo.boxModel can be set directly to change behavior.
|
|
|
4149 |
//
|
|
|
4150 |
// Beware of display: inline objects that have padding styles
|
|
|
4151 |
// because the user agent ignores padding (it's a bogus setup anyway)
|
|
|
4152 |
//
|
|
|
4153 |
// Be careful with IMGs because they are inline or block depending on
|
|
|
4154 |
// browser and browser mode.
|
|
|
4155 |
//
|
|
|
4156 |
// Elements other than DIV may have special quirks, like built-in
|
|
|
4157 |
// margins or padding, or values not detectable via computedStyle.
|
|
|
4158 |
// In particular, margins on TABLE do not seems to appear
|
|
|
4159 |
// at all in computedStyle on Mozilla.
|
|
|
4160 |
|
|
|
4161 |
dojo._setBox = function(/*DomNode*/node, /*Number?*/l, /*Number?*/t, /*Number?*/w, /*Number?*/h, /*String?*/u){
|
|
|
4162 |
// summary:
|
|
|
4163 |
// sets width/height/left/top in the current (native) box-model
|
|
|
4164 |
// dimentions. Uses the unit passed in u.
|
|
|
4165 |
// node: DOM Node reference. Id string not supported for performance reasons.
|
|
|
4166 |
// l: optional. left offset from parent.
|
|
|
4167 |
// t: optional. top offset from parent.
|
|
|
4168 |
// w: optional. width in current box model.
|
|
|
4169 |
// h: optional. width in current box model.
|
|
|
4170 |
// u: optional. unit measure to use for other measures. Defaults to "px".
|
|
|
4171 |
u = u || "px";
|
|
|
4172 |
with(node.style){
|
|
|
4173 |
if(!isNaN(l)){ left = l+u; }
|
|
|
4174 |
if(!isNaN(t)){ top = t+u; }
|
|
|
4175 |
if(w>=0){ width = w+u; }
|
|
|
4176 |
if(h>=0){ height = h+u; }
|
|
|
4177 |
}
|
|
|
4178 |
}
|
|
|
4179 |
|
|
|
4180 |
dojo._usesBorderBox = function(/*DomNode*/node){
|
|
|
4181 |
// summary:
|
|
|
4182 |
// True if the node uses border-box layout.
|
|
|
4183 |
|
|
|
4184 |
// We could test the computed style of node to see if a particular box
|
|
|
4185 |
// has been specified, but there are details and we choose not to bother.
|
|
|
4186 |
var n = node.tagName;
|
|
|
4187 |
// For whatever reason, TABLE and BUTTON are always border-box by default.
|
|
|
4188 |
// If you have assigned a different box to either one via CSS then
|
|
|
4189 |
// box functions will break.
|
|
|
4190 |
return dojo.boxModel=="border-box" || n=="TABLE" || n=="BUTTON"; // boolean
|
|
|
4191 |
}
|
|
|
4192 |
|
|
|
4193 |
dojo._setContentSize = function(/*DomNode*/node, /*Number*/widthPx, /*Number*/heightPx, /*Object*/computedStyle){
|
|
|
4194 |
// summary:
|
|
|
4195 |
// Sets the size of the node's contents, irrespective of margins,
|
|
|
4196 |
// padding, or borders.
|
|
|
4197 |
var bb = dojo._usesBorderBox(node);
|
|
|
4198 |
if(bb){
|
|
|
4199 |
var pb = dojo._getPadBorderExtents(node, computedStyle);
|
|
|
4200 |
if(widthPx>=0){ widthPx += pb.w; }
|
|
|
4201 |
if(heightPx>=0){ heightPx += pb.h; }
|
|
|
4202 |
}
|
|
|
4203 |
dojo._setBox(node, NaN, NaN, widthPx, heightPx);
|
|
|
4204 |
}
|
|
|
4205 |
|
|
|
4206 |
dojo._setMarginBox = function(/*DomNode*/node, /*Number?*/leftPx, /*Number?*/topPx,
|
|
|
4207 |
/*Number?*/widthPx, /*Number?*/heightPx,
|
|
|
4208 |
/*Object*/computedStyle){
|
|
|
4209 |
// summary:
|
|
|
4210 |
// sets the size of the node's margin box and palcement
|
|
|
4211 |
// (left/top), irrespective of box model. Think of it as a
|
|
|
4212 |
// passthrough to dojo._setBox that handles box-model vagaries for
|
|
|
4213 |
// you.
|
|
|
4214 |
|
|
|
4215 |
var s = computedStyle || dojo.getComputedStyle(node);
|
|
|
4216 |
// Some elements have special padding, margin, and box-model settings.
|
|
|
4217 |
// To use box functions you may need to set padding, margin explicitly.
|
|
|
4218 |
// Controlling box-model is harder, in a pinch you might set dojo.boxModel.
|
|
|
4219 |
var bb=dojo._usesBorderBox(node),
|
|
|
4220 |
pb=bb ? _nilExtents : dojo._getPadBorderExtents(node, s),
|
|
|
4221 |
mb=dojo._getMarginExtents(node, s);
|
|
|
4222 |
if(widthPx>=0){ widthPx = Math.max(widthPx - pb.w - mb.w, 0); }
|
|
|
4223 |
if(heightPx>=0){ heightPx = Math.max(heightPx - pb.h - mb.h, 0); }
|
|
|
4224 |
dojo._setBox(node, leftPx, topPx, widthPx, heightPx);
|
|
|
4225 |
}
|
|
|
4226 |
|
|
|
4227 |
var _nilExtents = { l:0, t:0, w:0, h:0 };
|
|
|
4228 |
|
|
|
4229 |
// public API
|
|
|
4230 |
|
|
|
4231 |
dojo.marginBox = function(/*DomNode|String*/node, /*Object?*/box){
|
|
|
4232 |
// summary:
|
|
|
4233 |
// getter/setter for the margin-box of node.
|
|
|
4234 |
// description:
|
|
|
4235 |
// Returns an object in the expected format of box (regardless
|
|
|
4236 |
// if box is passed). The object might look like:
|
|
|
4237 |
// { l: 50, t: 200, w: 300: h: 150 }
|
|
|
4238 |
// for a node offset from its parent 50px to the left, 200px from
|
|
|
4239 |
// the top with a margin width of 300px and a margin-height of
|
|
|
4240 |
// 150px.
|
|
|
4241 |
// node:
|
|
|
4242 |
// id or reference to DOM Node to get/set box for
|
|
|
4243 |
// box:
|
|
|
4244 |
// optional. If passed, denotes that dojo.marginBox() should
|
|
|
4245 |
// update/set the margin box for node. Box is an object in the
|
|
|
4246 |
// above format. All properties are optional if passed.
|
|
|
4247 |
var n=dojo.byId(node), s=gcs(n), b=box;
|
|
|
4248 |
return !b ? dojo._getMarginBox(n, s) : dojo._setMarginBox(n, b.l, b.t, b.w, b.h, s); // Object
|
|
|
4249 |
}
|
|
|
4250 |
|
|
|
4251 |
dojo.contentBox = function(/*DomNode|String*/node, /*Object?*/box){
|
|
|
4252 |
// summary:
|
|
|
4253 |
// getter/setter for the content-box of node.
|
|
|
4254 |
// description:
|
|
|
4255 |
// Returns an object in the expected format of box (regardless if box is passed).
|
|
|
4256 |
// The object might look like:
|
|
|
4257 |
// { l: 50, t: 200, w: 300: h: 150 }
|
|
|
4258 |
// for a node offset from its parent 50px to the left, 200px from
|
|
|
4259 |
// the top with a content width of 300px and a content-height of
|
|
|
4260 |
// 150px. Note that the content box may have a much larger border
|
|
|
4261 |
// or margin box, depending on the box model currently in use and
|
|
|
4262 |
// CSS values set/inherited for node.
|
|
|
4263 |
// node:
|
|
|
4264 |
// id or reference to DOM Node to get/set box for
|
|
|
4265 |
// box:
|
|
|
4266 |
// optional. If passed, denotes that dojo.contentBox() should
|
|
|
4267 |
// update/set the content box for node. Box is an object in the
|
|
|
4268 |
// above format. All properties are optional if passed.
|
|
|
4269 |
var n=dojo.byId(node), s=gcs(n), b=box;
|
|
|
4270 |
return !b ? dojo._getContentBox(n, s) : dojo._setContentSize(n, b.w, b.h, s); // Object
|
|
|
4271 |
}
|
|
|
4272 |
|
|
|
4273 |
// =============================
|
|
|
4274 |
// Positioning
|
|
|
4275 |
// =============================
|
|
|
4276 |
|
|
|
4277 |
var _sumAncestorProperties = function(node, prop){
|
|
|
4278 |
if(!(node = (node||0).parentNode)){return 0};
|
|
|
4279 |
var val, retVal = 0, _b = dojo.body();
|
|
|
4280 |
while(node && node.style){
|
|
|
4281 |
if(gcs(node).position == "fixed"){
|
|
|
4282 |
return 0;
|
|
|
4283 |
}
|
|
|
4284 |
val = node[prop];
|
|
|
4285 |
if(val){
|
|
|
4286 |
retVal += val - 0;
|
|
|
4287 |
// opera and khtml #body & #html has the same values, we only
|
|
|
4288 |
// need one value
|
|
|
4289 |
if(node == _b){ break; }
|
|
|
4290 |
}
|
|
|
4291 |
node = node.parentNode;
|
|
|
4292 |
}
|
|
|
4293 |
return retVal; // integer
|
|
|
4294 |
}
|
|
|
4295 |
|
|
|
4296 |
dojo._docScroll = function(){
|
|
|
4297 |
var _b = dojo.body();
|
|
|
4298 |
var _w = dojo.global;
|
|
|
4299 |
var de = dojo.doc.documentElement;
|
|
|
4300 |
return {
|
|
|
4301 |
y: (_w.pageYOffset || de.scrollTop || _b.scrollTop || 0),
|
|
|
4302 |
x: (_w.pageXOffset || dojo._fixIeBiDiScrollLeft(de.scrollLeft) || _b.scrollLeft || 0)
|
|
|
4303 |
};
|
|
|
4304 |
};
|
|
|
4305 |
|
|
|
4306 |
dojo._isBodyLtr = function(){
|
|
|
4307 |
//FIXME: could check html and body tags directly instead of computed style? need to ignore case, accept empty values
|
|
|
4308 |
return !("_bodyLtr" in dojo) ?
|
|
|
4309 |
dojo._bodyLtr = dojo.getComputedStyle(dojo.body()).direction == "ltr" :
|
|
|
4310 |
dojo._bodyLtr; // Boolean
|
|
|
4311 |
}
|
|
|
4312 |
|
|
|
4313 |
dojo._getIeDocumentElementOffset = function(){
|
|
|
4314 |
// summary
|
|
|
4315 |
// The following values in IE contain an offset:
|
|
|
4316 |
// event.clientX
|
|
|
4317 |
// event.clientY
|
|
|
4318 |
// node.getBoundingClientRect().left
|
|
|
4319 |
// node.getBoundingClientRect().top
|
|
|
4320 |
// But other position related values do not contain this offset, such as
|
|
|
4321 |
// node.offsetLeft, node.offsetTop, node.style.left and node.style.top.
|
|
|
4322 |
// The offset is always (2, 2) in LTR direction. When the body is in RTL
|
|
|
4323 |
// direction, the offset counts the width of left scroll bar's width.
|
|
|
4324 |
// This function computes the actual offset.
|
|
|
4325 |
|
|
|
4326 |
//NOTE: assumes we're being called in an IE browser
|
|
|
4327 |
|
|
|
4328 |
var de = dojo.doc.documentElement;
|
|
|
4329 |
if(dojo.isIE >= 7){
|
|
|
4330 |
return {x: de.getBoundingClientRect().left, y: de.getBoundingClientRect().top}; // Object
|
|
|
4331 |
}else{
|
|
|
4332 |
// IE 6.0
|
|
|
4333 |
return {x: dojo._isBodyLtr() || window.parent == window ?
|
|
|
4334 |
de.clientLeft : de.offsetWidth - de.clientWidth - de.clientLeft,
|
|
|
4335 |
y: de.clientTop}; // Object
|
|
|
4336 |
}
|
|
|
4337 |
};
|
|
|
4338 |
|
|
|
4339 |
dojo._fixIeBiDiScrollLeft = function(/*Integer*/ scrollLeft){
|
|
|
4340 |
// In RTL direction, scrollLeft should be a negative value, but IE
|
|
|
4341 |
// returns a positive one. All codes using documentElement.scrollLeft
|
|
|
4342 |
// must call this function to fix this error, otherwise the position
|
|
|
4343 |
// will offset to right when there is a horizonal scrollbar.
|
|
|
4344 |
if(dojo.isIE && !dojo._isBodyLtr()){
|
|
|
4345 |
var de = dojo.doc.documentElement;
|
|
|
4346 |
return scrollLeft + de.clientWidth - de.scrollWidth; // Integer
|
|
|
4347 |
}
|
|
|
4348 |
return scrollLeft; // Integer
|
|
|
4349 |
}
|
|
|
4350 |
|
|
|
4351 |
dojo._abs = function(/*DomNode*/node, /*Boolean?*/includeScroll){
|
|
|
4352 |
// summary:
|
|
|
4353 |
// Gets the absolute position of the passed element based on the
|
|
|
4354 |
// document itself. Returns an object of the form:
|
|
|
4355 |
// { x: 100, y: 300 }
|
|
|
4356 |
// if includeScroll is passed, the x and y values will include any
|
|
|
4357 |
// document offsets that may affect the position relative to the
|
|
|
4358 |
// viewport.
|
|
|
4359 |
|
|
|
4360 |
// FIXME: need to decide in the brave-new-world if we're going to be
|
|
|
4361 |
// margin-box or border-box.
|
|
|
4362 |
var ownerDocument = node.ownerDocument;
|
|
|
4363 |
var ret = {
|
|
|
4364 |
x: 0,
|
|
|
4365 |
y: 0
|
|
|
4366 |
};
|
|
|
4367 |
var hasScroll = false;
|
|
|
4368 |
|
|
|
4369 |
// targetBoxType == "border-box"
|
|
|
4370 |
var db = dojo.body();
|
|
|
4371 |
if(dojo.isIE){
|
|
|
4372 |
var client = node.getBoundingClientRect();
|
|
|
4373 |
var offset = dojo._getIeDocumentElementOffset();
|
|
|
4374 |
ret.x = client.left - offset.x;
|
|
|
4375 |
ret.y = client.top - offset.y;
|
|
|
4376 |
}else if(ownerDocument["getBoxObjectFor"]){
|
|
|
4377 |
// mozilla
|
|
|
4378 |
var bo = ownerDocument.getBoxObjectFor(node);
|
|
|
4379 |
ret.x = bo.x - _sumAncestorProperties(node, "scrollLeft");
|
|
|
4380 |
ret.y = bo.y - _sumAncestorProperties(node, "scrollTop");
|
|
|
4381 |
}else{
|
|
|
4382 |
if(node["offsetParent"]){
|
|
|
4383 |
hasScroll = true;
|
|
|
4384 |
var endNode;
|
|
|
4385 |
// in Safari, if the node is an absolutely positioned child of
|
|
|
4386 |
// the body and the body has a margin the offset of the child
|
|
|
4387 |
// and the body contain the body's margins, so we need to end
|
|
|
4388 |
// at the body
|
|
|
4389 |
// FIXME: getting contrary results to the above in latest WebKit.
|
|
|
4390 |
if(dojo.isSafari &&
|
|
|
4391 |
//(node.style.getPropertyValue("position") == "absolute") &&
|
|
|
4392 |
(gcs(node).position == "absolute") &&
|
|
|
4393 |
(node.parentNode == db)){
|
|
|
4394 |
endNode = db;
|
|
|
4395 |
}else{
|
|
|
4396 |
endNode = db.parentNode;
|
|
|
4397 |
}
|
|
|
4398 |
if(node.parentNode != db){
|
|
|
4399 |
var nd = node;
|
|
|
4400 |
if(dojo.isOpera || (dojo.isSafari >= 3)){ nd = db; }
|
|
|
4401 |
ret.x -= _sumAncestorProperties(nd, "scrollLeft");
|
|
|
4402 |
ret.y -= _sumAncestorProperties(nd, "scrollTop");
|
|
|
4403 |
}
|
|
|
4404 |
var curnode = node;
|
|
|
4405 |
do{
|
|
|
4406 |
var n = curnode["offsetLeft"];
|
|
|
4407 |
//FIXME: ugly hack to workaround the submenu in
|
|
|
4408 |
//popupmenu2 does not shown up correctly in opera.
|
|
|
4409 |
//Someone have a better workaround?
|
|
|
4410 |
if(!dojo.isOpera || n>0){
|
|
|
4411 |
ret.x += isNaN(n) ? 0 : n;
|
|
|
4412 |
}
|
|
|
4413 |
var m = curnode["offsetTop"];
|
|
|
4414 |
ret.y += isNaN(m) ? 0 : m;
|
|
|
4415 |
curnode = curnode.offsetParent;
|
|
|
4416 |
}while((curnode != endNode)&&curnode);
|
|
|
4417 |
}else if(node["x"]&&node["y"]){
|
|
|
4418 |
ret.x += isNaN(node.x) ? 0 : node.x;
|
|
|
4419 |
ret.y += isNaN(node.y) ? 0 : node.y;
|
|
|
4420 |
}
|
|
|
4421 |
}
|
|
|
4422 |
// account for document scrolling
|
|
|
4423 |
// if offsetParent is used, ret value already includes scroll position
|
|
|
4424 |
// so we may have to actually remove that value if !includeScroll
|
|
|
4425 |
if(hasScroll || includeScroll){
|
|
|
4426 |
var scroll = dojo._docScroll();
|
|
|
4427 |
var m = hasScroll ? (!includeScroll ? -1 : 0) : 1;
|
|
|
4428 |
ret.y += m*scroll.y;
|
|
|
4429 |
ret.x += m*scroll.x;
|
|
|
4430 |
}
|
|
|
4431 |
|
|
|
4432 |
return ret; // object
|
|
|
4433 |
}
|
|
|
4434 |
|
|
|
4435 |
// FIXME: need a setter for coords or a moveTo!!
|
|
|
4436 |
dojo.coords = function(/*DomNode|String*/node, /*Boolean?*/includeScroll){
|
|
|
4437 |
// summary:
|
|
|
4438 |
// Returns an object that measures margin box width/height and
|
|
|
4439 |
// absolute positioning data from dojo._abs(). Return value will
|
|
|
4440 |
// be in the form:
|
|
|
4441 |
// { l: 50, t: 200, w: 300: h: 150, x: 100, y: 300 }
|
|
|
4442 |
// does not act as a setter. If includeScroll is passed, the x and
|
|
|
4443 |
// y params are affected as one would expect in dojo._abs().
|
|
|
4444 |
var n=dojo.byId(node), s=gcs(n), mb=dojo._getMarginBox(n, s);
|
|
|
4445 |
var abs = dojo._abs(n, includeScroll);
|
|
|
4446 |
mb.x = abs.x;
|
|
|
4447 |
mb.y = abs.y;
|
|
|
4448 |
return mb;
|
|
|
4449 |
}
|
|
|
4450 |
})();
|
|
|
4451 |
|
|
|
4452 |
// =============================
|
|
|
4453 |
// (CSS) Class Functions
|
|
|
4454 |
// =============================
|
|
|
4455 |
|
|
|
4456 |
dojo.hasClass = function(/*DomNode|String*/node, /*String*/classStr){
|
|
|
4457 |
// summary:
|
|
|
4458 |
// Returns whether or not the specified classes are a portion of the
|
|
|
4459 |
// class list currently applied to the node.
|
|
|
4460 |
return ((" "+dojo.byId(node).className+" ").indexOf(" "+classStr+" ") >= 0); // Boolean
|
|
|
4461 |
};
|
|
|
4462 |
|
|
|
4463 |
dojo.addClass = function(/*DomNode|String*/node, /*String*/classStr){
|
|
|
4464 |
// summary:
|
|
|
4465 |
// Adds the specified classes to the end of the class list on the
|
|
|
4466 |
// passed node.
|
|
|
4467 |
node = dojo.byId(node);
|
|
|
4468 |
var cls = node.className;
|
|
|
4469 |
if((" "+cls+" ").indexOf(" "+classStr+" ") < 0){
|
|
|
4470 |
node.className = cls + (cls ? ' ' : '') + classStr;
|
|
|
4471 |
}
|
|
|
4472 |
};
|
|
|
4473 |
|
|
|
4474 |
dojo.removeClass = function(/*DomNode|String*/node, /*String*/classStr){
|
|
|
4475 |
// summary: Removes the specified classes from node.
|
|
|
4476 |
node = dojo.byId(node);
|
|
|
4477 |
var t = dojo.trim((" " + node.className + " ").replace(" " + classStr + " ", " "));
|
|
|
4478 |
if(node.className != t){ node.className = t; }
|
|
|
4479 |
};
|
|
|
4480 |
|
|
|
4481 |
dojo.toggleClass = function(/*DomNode|String*/node, /*String*/classStr, /*Boolean?*/condition){
|
|
|
4482 |
// summary:
|
|
|
4483 |
// Adds a class to node if not present, or removes if present.
|
|
|
4484 |
// Pass a boolean condition if you want to explicitly add or remove.
|
|
|
4485 |
// condition:
|
|
|
4486 |
// If passed, true means to add the class, false means to remove.
|
|
|
4487 |
if(condition === undefined){
|
|
|
4488 |
condition = !dojo.hasClass(node, classStr);
|
|
|
4489 |
}
|
|
|
4490 |
dojo[condition ? "addClass" : "removeClass"](node, classStr);
|
|
|
4491 |
};
|
|
|
4492 |
|
|
|
4493 |
}
|
|
|
4494 |
|
|
|
4495 |
if(!dojo._hasResource["dojo._base.NodeList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
4496 |
dojo._hasResource["dojo._base.NodeList"] = true;
|
|
|
4497 |
dojo.provide("dojo._base.NodeList");
|
|
|
4498 |
|
|
|
4499 |
|
|
|
4500 |
|
|
|
4501 |
(function(){
|
|
|
4502 |
|
|
|
4503 |
var d = dojo;
|
|
|
4504 |
|
|
|
4505 |
var tnl = function(arr){
|
|
|
4506 |
arr.constructor = dojo.NodeList;
|
|
|
4507 |
dojo._mixin(arr, dojo.NodeList.prototype);
|
|
|
4508 |
return arr;
|
|
|
4509 |
}
|
|
|
4510 |
|
|
|
4511 |
dojo.NodeList = function(){
|
|
|
4512 |
// summary:
|
|
|
4513 |
// dojo.NodeList is as subclass of Array which adds syntactic
|
|
|
4514 |
// sugar for chaining, common iteration operations, animation,
|
|
|
4515 |
// and node manipulation. NodeLists are most often returned as
|
|
|
4516 |
// the result of dojo.query() calls.
|
|
|
4517 |
// example:
|
|
|
4518 |
// create a node list from a node
|
|
|
4519 |
// | new dojo.NodeList(dojo.byId("foo"));
|
|
|
4520 |
|
|
|
4521 |
return tnl(Array.apply(null, arguments));
|
|
|
4522 |
}
|
|
|
4523 |
|
|
|
4524 |
dojo.NodeList._wrap = tnl;
|
|
|
4525 |
|
|
|
4526 |
dojo.extend(dojo.NodeList, {
|
|
|
4527 |
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array#Methods
|
|
|
4528 |
|
|
|
4529 |
// FIXME: handle return values for #3244
|
|
|
4530 |
// http://trac.dojotoolkit.org/ticket/3244
|
|
|
4531 |
|
|
|
4532 |
// FIXME:
|
|
|
4533 |
// need to wrap or implement:
|
|
|
4534 |
// join (perhaps w/ innerHTML/outerHTML overload for toString() of items?)
|
|
|
4535 |
// reduce
|
|
|
4536 |
// reduceRight
|
|
|
4537 |
|
|
|
4538 |
slice: function(/*===== begin, end =====*/){
|
|
|
4539 |
// summary:
|
|
|
4540 |
// Returns a new NodeList, maintaining this one in place
|
|
|
4541 |
// description:
|
|
|
4542 |
// This method behaves exactly like the Array.slice method
|
|
|
4543 |
// with the caveat that it returns a dojo.NodeList and not a
|
|
|
4544 |
// raw Array. For more details, see:
|
|
|
4545 |
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:slice
|
|
|
4546 |
// begin: Integer
|
|
|
4547 |
// Can be a positive or negative integer, with positive
|
|
|
4548 |
// integers noting the offset to begin at, and negative
|
|
|
4549 |
// integers denoting an offset from the end (i.e., to the left
|
|
|
4550 |
// of the end)
|
|
|
4551 |
// end: Integer?
|
|
|
4552 |
// Optional parameter to describe what position relative to
|
|
|
4553 |
// the NodeList's zero index to end the slice at. Like begin,
|
|
|
4554 |
// can be positive or negative.
|
|
|
4555 |
var a = dojo._toArray(arguments);
|
|
|
4556 |
return tnl(a.slice.apply(this, a));
|
|
|
4557 |
},
|
|
|
4558 |
|
|
|
4559 |
splice: function(/*===== index, howmany, item =====*/){
|
|
|
4560 |
// summary:
|
|
|
4561 |
// Returns a new NodeList, manipulating this NodeList based on
|
|
|
4562 |
// the arguments passed, potentially splicing in new elements
|
|
|
4563 |
// at an offset, optionally deleting elements
|
|
|
4564 |
// description:
|
|
|
4565 |
// This method behaves exactly like the Array.splice method
|
|
|
4566 |
// with the caveat that it returns a dojo.NodeList and not a
|
|
|
4567 |
// raw Array. For more details, see:
|
|
|
4568 |
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:splice
|
|
|
4569 |
// index: Integer
|
|
|
4570 |
// begin can be a positive or negative integer, with positive
|
|
|
4571 |
// integers noting the offset to begin at, and negative
|
|
|
4572 |
// integers denoting an offset from the end (i.e., to the left
|
|
|
4573 |
// of the end)
|
|
|
4574 |
// howmany: Integer?
|
|
|
4575 |
// Optional parameter to describe what position relative to
|
|
|
4576 |
// the NodeList's zero index to end the slice at. Like begin,
|
|
|
4577 |
// can be positive or negative.
|
|
|
4578 |
// item: Object...?
|
|
|
4579 |
// Any number of optional parameters may be passed in to be
|
|
|
4580 |
// spliced into the NodeList
|
|
|
4581 |
// returns:
|
|
|
4582 |
// dojo.NodeList
|
|
|
4583 |
var a = dojo._toArray(arguments);
|
|
|
4584 |
return tnl(a.splice.apply(this, a));
|
|
|
4585 |
},
|
|
|
4586 |
|
|
|
4587 |
concat: function(/*===== item =====*/){
|
|
|
4588 |
// summary:
|
|
|
4589 |
// Returns a new NodeList comprised of items in this NodeList
|
|
|
4590 |
// as well as items passed in as parameters
|
|
|
4591 |
// description:
|
|
|
4592 |
// This method behaves exactly like the Array.concat method
|
|
|
4593 |
// with the caveat that it returns a dojo.NodeList and not a
|
|
|
4594 |
// raw Array. For more details, see:
|
|
|
4595 |
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:concat
|
|
|
4596 |
// item: Object...?
|
|
|
4597 |
// Any number of optional parameters may be passed in to be
|
|
|
4598 |
// spliced into the NodeList
|
|
|
4599 |
// returns:
|
|
|
4600 |
// dojo.NodeList
|
|
|
4601 |
var a = dojo._toArray(arguments, 0, [this]);
|
|
|
4602 |
return tnl(a.concat.apply([], a));
|
|
|
4603 |
},
|
|
|
4604 |
|
|
|
4605 |
indexOf: function(/*Object*/ value, /*Integer?*/ fromIndex){
|
|
|
4606 |
// summary:
|
|
|
4607 |
// see dojo.indexOf(). The primary difference is that the acted-on
|
|
|
4608 |
// array is implicitly this NodeList
|
|
|
4609 |
// value:
|
|
|
4610 |
// The value to search for.
|
|
|
4611 |
// fromIndex:
|
|
|
4612 |
// The loction to start searching from. Optional. Defaults to 0.
|
|
|
4613 |
// description:
|
|
|
4614 |
// For more details on the behavior of indexOf, see:
|
|
|
4615 |
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf
|
|
|
4616 |
// returns:
|
|
|
4617 |
// Positive Integer or 0 for a match, -1 of not found.
|
|
|
4618 |
return d.indexOf(this, value, fromIndex); // Integer
|
|
|
4619 |
},
|
|
|
4620 |
|
|
|
4621 |
lastIndexOf: function(/*===== value, fromIndex =====*/){
|
|
|
4622 |
// summary:
|
|
|
4623 |
// see dojo.lastIndexOf(). The primary difference is that the
|
|
|
4624 |
// acted-on array is implicitly this NodeList
|
|
|
4625 |
// description:
|
|
|
4626 |
// For more details on the behavior of lastIndexOf, see:
|
|
|
4627 |
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf
|
|
|
4628 |
// value: Object
|
|
|
4629 |
// The value to search for.
|
|
|
4630 |
// fromIndex: Integer?
|
|
|
4631 |
// The loction to start searching from. Optional. Defaults to 0.
|
|
|
4632 |
// returns:
|
|
|
4633 |
// Positive Integer or 0 for a match, -1 of not found.
|
|
|
4634 |
return d.lastIndexOf.apply(d, d._toArray(arguments, 0, [this])); // Integer
|
|
|
4635 |
},
|
|
|
4636 |
|
|
|
4637 |
every: function(/*Function*/callback, /*Object?*/thisObject){
|
|
|
4638 |
// summary:
|
|
|
4639 |
// see dojo.every() and:
|
|
|
4640 |
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every
|
|
|
4641 |
// Takes the same structure of arguments and returns as
|
|
|
4642 |
// dojo.every() with the caveat that the passed array is
|
|
|
4643 |
// implicitly this NodeList
|
|
|
4644 |
return d.every(this, callback, thisObject); // Boolean
|
|
|
4645 |
},
|
|
|
4646 |
|
|
|
4647 |
some: function(/*Function*/callback, /*Object?*/thisObject){
|
|
|
4648 |
// summary:
|
|
|
4649 |
// see dojo.some() and:
|
|
|
4650 |
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some
|
|
|
4651 |
// Takes the same structure of arguments and returns as
|
|
|
4652 |
// dojo.some() with the caveat that the passed array is
|
|
|
4653 |
// implicitly this NodeList
|
|
|
4654 |
return d.some(this, callback, thisObject); // Boolean
|
|
|
4655 |
},
|
|
|
4656 |
|
|
|
4657 |
map: function(/*Function*/ func, /*Function?*/ obj){
|
|
|
4658 |
// summary:
|
|
|
4659 |
// see dojo.map(). The primary difference is that the acted-on
|
|
|
4660 |
// array is implicitly this NodeList and the return is a
|
|
|
4661 |
// dojo.NodeList (a subclass of Array)
|
|
|
4662 |
|
|
|
4663 |
return d.map(this, func, obj, d.NodeList); // dojo.NodeList
|
|
|
4664 |
},
|
|
|
4665 |
|
|
|
4666 |
forEach: function(callback, thisObj){
|
|
|
4667 |
// summary:
|
|
|
4668 |
// see dojo.forEach(). The primary difference is that the acted-on
|
|
|
4669 |
// array is implicitly this NodeList
|
|
|
4670 |
|
|
|
4671 |
d.forEach(this, callback, thisObj);
|
|
|
4672 |
return this; // dojo.NodeList non-standard return to allow easier chaining
|
|
|
4673 |
},
|
|
|
4674 |
|
|
|
4675 |
// custom methods
|
|
|
4676 |
|
|
|
4677 |
coords: function(){
|
|
|
4678 |
// summary:
|
|
|
4679 |
// Returns the box objects all elements in a node list as
|
|
|
4680 |
// an Array (*not* a NodeList)
|
|
|
4681 |
|
|
|
4682 |
return d.map(this, d.coords);
|
|
|
4683 |
},
|
|
|
4684 |
|
|
|
4685 |
style: function(/*===== property, value =====*/){
|
|
|
4686 |
// summary:
|
|
|
4687 |
// gets or sets the CSS property for every element in the NodeList
|
|
|
4688 |
// property: String
|
|
|
4689 |
// the CSS property to get/set, in JavaScript notation
|
|
|
4690 |
// ("lineHieght" instead of "line-height")
|
|
|
4691 |
// value: String?
|
|
|
4692 |
// optional. The value to set the property to
|
|
|
4693 |
// return:
|
|
|
4694 |
// if no value is passed, the result is an array of strings.
|
|
|
4695 |
// If a value is passed, the return is this NodeList
|
|
|
4696 |
var aa = d._toArray(arguments, 0, [null]);
|
|
|
4697 |
var s = this.map(function(i){
|
|
|
4698 |
aa[0] = i;
|
|
|
4699 |
return d.style.apply(d, aa);
|
|
|
4700 |
});
|
|
|
4701 |
return (arguments.length > 1) ? this : s; // String||dojo.NodeList
|
|
|
4702 |
},
|
|
|
4703 |
|
|
|
4704 |
styles: function(/*===== property, value =====*/){
|
|
|
4705 |
// summary:
|
|
|
4706 |
// Deprecated. Use NodeList.style instead. Will be removed in
|
|
|
4707 |
// Dojo 1.1. Gets or sets the CSS property for every element
|
|
|
4708 |
// in the NodeList
|
|
|
4709 |
// property: String
|
|
|
4710 |
// the CSS property to get/set, in JavaScript notation
|
|
|
4711 |
// ("lineHieght" instead of "line-height")
|
|
|
4712 |
// value: String?
|
|
|
4713 |
// optional. The value to set the property to
|
|
|
4714 |
// return:
|
|
|
4715 |
// if no value is passed, the result is an array of strings.
|
|
|
4716 |
// If a value is passed, the return is this NodeList
|
|
|
4717 |
d.deprecated("NodeList.styles", "use NodeList.style instead", "1.1");
|
|
|
4718 |
return this.style.apply(this, arguments);
|
|
|
4719 |
},
|
|
|
4720 |
|
|
|
4721 |
addClass: function(/*String*/ className){
|
|
|
4722 |
// summary:
|
|
|
4723 |
// adds the specified class to every node in the list
|
|
|
4724 |
//
|
|
|
4725 |
this.forEach(function(i){ d.addClass(i, className); });
|
|
|
4726 |
return this;
|
|
|
4727 |
},
|
|
|
4728 |
|
|
|
4729 |
removeClass: function(/*String*/ className){
|
|
|
4730 |
this.forEach(function(i){ d.removeClass(i, className); });
|
|
|
4731 |
return this;
|
|
|
4732 |
},
|
|
|
4733 |
|
|
|
4734 |
// FIXME: toggleClass()? connectPublisher()? connectRunOnce()?
|
|
|
4735 |
|
|
|
4736 |
place: function(/*String||Node*/ queryOrNode, /*String*/ position){
|
|
|
4737 |
// summary:
|
|
|
4738 |
// places elements of this node list relative to the first element matched
|
|
|
4739 |
// by queryOrNode. Returns the original NodeList.
|
|
|
4740 |
// queryOrNode:
|
|
|
4741 |
// may be a string representing any valid CSS3 selector or a DOM node.
|
|
|
4742 |
// In the selector case, only the first matching element will be used
|
|
|
4743 |
// for relative positioning.
|
|
|
4744 |
// position:
|
|
|
4745 |
// can be one of:
|
|
|
4746 |
// "last"||"end" (default)
|
|
|
4747 |
// "first||"start"
|
|
|
4748 |
// "before"
|
|
|
4749 |
// "after"
|
|
|
4750 |
// or an offset in the childNodes property
|
|
|
4751 |
var item = d.query(queryOrNode)[0];
|
|
|
4752 |
position = position||"last";
|
|
|
4753 |
|
|
|
4754 |
for(var x=0; x<this.length; x++){
|
|
|
4755 |
d.place(this[x], item, position);
|
|
|
4756 |
}
|
|
|
4757 |
return this; // dojo.NodeList
|
|
|
4758 |
},
|
|
|
4759 |
|
|
|
4760 |
connect: function(/*String*/ methodName, /*Object||Function||String*/ objOrFunc, /*String?*/ funcName){
|
|
|
4761 |
// summary:
|
|
|
4762 |
// attach event handlers to every item of the NodeList. Uses dojo.connect()
|
|
|
4763 |
// so event properties are normalized
|
|
|
4764 |
// methodName:
|
|
|
4765 |
// the name of the method to attach to. For DOM events, this should be
|
|
|
4766 |
// the lower-case name of the event
|
|
|
4767 |
// objOrFunc:
|
|
|
4768 |
// if 2 arguments are passed (methodName, objOrFunc), objOrFunc should
|
|
|
4769 |
// reference a function or be the name of the function in the global
|
|
|
4770 |
// namespace to attach. If 3 arguments are provided
|
|
|
4771 |
// (methodName, objOrFunc, funcName), objOrFunc must be the scope to
|
|
|
4772 |
// locate the bound function in
|
|
|
4773 |
// funcName:
|
|
|
4774 |
// optional. A string naming the function in objOrFunc to bind to the
|
|
|
4775 |
// event. May also be a function reference.
|
|
|
4776 |
// example:
|
|
|
4777 |
// add an onclick handler to every button on the page
|
|
|
4778 |
// | dojo.query("onclick", function(e){
|
|
|
4779 |
// | console.debug("clicked!");
|
|
|
4780 |
// | });
|
|
|
4781 |
// example:
|
|
|
4782 |
// attach foo.bar() to every odd div's onmouseover
|
|
|
4783 |
// | dojo.query("div:nth-child(odd)").onclick("onmouseover", foo, "bar");
|
|
|
4784 |
this.forEach(function(item){
|
|
|
4785 |
d.connect(item, methodName, objOrFunc, funcName);
|
|
|
4786 |
});
|
|
|
4787 |
return this; // dojo.NodeList
|
|
|
4788 |
},
|
|
|
4789 |
|
|
|
4790 |
orphan: function(/*String?*/ simpleFilter){
|
|
|
4791 |
// summary:
|
|
|
4792 |
// removes elements in this list that match the simple
|
|
|
4793 |
// filter from their parents and returns them as a new
|
|
|
4794 |
// NodeList.
|
|
|
4795 |
// simpleFilter: single-expression CSS filter
|
|
|
4796 |
// return: a dojo.NodeList of all of the elements orpahned
|
|
|
4797 |
var orphans = (simpleFilter) ? d._filterQueryResult(this, simpleFilter) : this;
|
|
|
4798 |
orphans.forEach(function(item){
|
|
|
4799 |
if(item["parentNode"]){
|
|
|
4800 |
item.parentNode.removeChild(item);
|
|
|
4801 |
}
|
|
|
4802 |
});
|
|
|
4803 |
return orphans; // dojo.NodeList
|
|
|
4804 |
},
|
|
|
4805 |
|
|
|
4806 |
adopt: function(/*String||Array||DomNode*/ queryOrListOrNode, /*String?*/ position){
|
|
|
4807 |
// summary:
|
|
|
4808 |
// places any/all elements in queryOrListOrNode at a
|
|
|
4809 |
// position relative to the first element in this list.
|
|
|
4810 |
// Returns a dojo.NodeList of the adopted elements.
|
|
|
4811 |
// queryOrListOrNode:
|
|
|
4812 |
// a DOM node or a query string or a query result.
|
|
|
4813 |
// Represents the nodes to be adopted relative to the
|
|
|
4814 |
// first element of this NodeList.
|
|
|
4815 |
// position:
|
|
|
4816 |
// optional. One of:
|
|
|
4817 |
// "last"||"end" (default)
|
|
|
4818 |
// "first||"start"
|
|
|
4819 |
// "before"
|
|
|
4820 |
// "after"
|
|
|
4821 |
// or an offset in the childNodes property
|
|
|
4822 |
var item = this[0];
|
|
|
4823 |
return d.query(queryOrListOrNode).forEach(function(ai){ d.place(ai, item, (position||"last")); }); // dojo.NodeList
|
|
|
4824 |
},
|
|
|
4825 |
|
|
|
4826 |
// FIXME: do we need this?
|
|
|
4827 |
query: function(/*String*/ queryStr){
|
|
|
4828 |
// summary:
|
|
|
4829 |
// Returns a new, flattened NodeList. Elements of the new list
|
|
|
4830 |
// satisfy the passed query but use elements of the
|
|
|
4831 |
// current NodeList as query roots.
|
|
|
4832 |
|
|
|
4833 |
queryStr = queryStr||"";
|
|
|
4834 |
|
|
|
4835 |
// FIXME: probably slow
|
|
|
4836 |
var ret = d.NodeList();
|
|
|
4837 |
this.forEach(function(item){
|
|
|
4838 |
d.query(queryStr, item).forEach(function(subItem){
|
|
|
4839 |
if(typeof subItem != "undefined"){
|
|
|
4840 |
ret.push(subItem);
|
|
|
4841 |
}
|
|
|
4842 |
});
|
|
|
4843 |
});
|
|
|
4844 |
return ret; // dojo.NodeList
|
|
|
4845 |
},
|
|
|
4846 |
|
|
|
4847 |
filter: function(/*String*/ simpleQuery){
|
|
|
4848 |
// summary:
|
|
|
4849 |
// "masks" the built-in javascript filter() method to support
|
|
|
4850 |
// passing a simple string filter in addition to supporting
|
|
|
4851 |
// filtering function objects.
|
|
|
4852 |
// example:
|
|
|
4853 |
// "regular" JS filter syntax as exposed in dojo.filter:
|
|
|
4854 |
// | dojo.query("*").filter(function(item){
|
|
|
4855 |
// | // highlight every paragraph
|
|
|
4856 |
// | return (item.nodeName == "p");
|
|
|
4857 |
// | }).styles("backgroundColor", "yellow");
|
|
|
4858 |
// example:
|
|
|
4859 |
// the same filtering using a CSS selector
|
|
|
4860 |
// | dojo.query("*").filter("p").styles("backgroundColor", "yellow");
|
|
|
4861 |
|
|
|
4862 |
var items = this;
|
|
|
4863 |
var _a = arguments;
|
|
|
4864 |
var r = d.NodeList();
|
|
|
4865 |
var rp = function(t){
|
|
|
4866 |
if(typeof t != "undefined"){
|
|
|
4867 |
r.push(t);
|
|
|
4868 |
}
|
|
|
4869 |
}
|
|
|
4870 |
if(d.isString(simpleQuery)){
|
|
|
4871 |
items = d._filterQueryResult(this, _a[0]);
|
|
|
4872 |
if(_a.length == 1){
|
|
|
4873 |
// if we only got a string query, pass back the filtered results
|
|
|
4874 |
return items; // dojo.NodeList
|
|
|
4875 |
}
|
|
|
4876 |
// if we got a callback, run it over the filtered items
|
|
|
4877 |
d.forEach(d.filter(items, _a[1], _a[2]), rp);
|
|
|
4878 |
return r; // dojo.NodeList
|
|
|
4879 |
}
|
|
|
4880 |
// handle the (callback, [thisObject]) case
|
|
|
4881 |
d.forEach(d.filter(items, _a[0], _a[1]), rp);
|
|
|
4882 |
return r; // dojo.NodeList
|
|
|
4883 |
|
|
|
4884 |
},
|
|
|
4885 |
|
|
|
4886 |
/*
|
|
|
4887 |
// FIXME: should this be "copyTo" and include parenting info?
|
|
|
4888 |
clone: function(){
|
|
|
4889 |
// summary:
|
|
|
4890 |
// creates node clones of each element of this list
|
|
|
4891 |
// and returns a new list containing the clones
|
|
|
4892 |
},
|
|
|
4893 |
*/
|
|
|
4894 |
|
|
|
4895 |
addContent: function(/*String*/ content, /*String||Integer?*/ position){
|
|
|
4896 |
// summary:
|
|
|
4897 |
// add a node or some HTML as a string to every item in the list.
|
|
|
4898 |
// Returns the original list.
|
|
|
4899 |
// content:
|
|
|
4900 |
// the HTML in string format to add at position to every item
|
|
|
4901 |
// position:
|
|
|
4902 |
// One of:
|
|
|
4903 |
// "last"||"end" (default)
|
|
|
4904 |
// "first||"start"
|
|
|
4905 |
// "before"
|
|
|
4906 |
// "after"
|
|
|
4907 |
// or an integer offset in the childNodes property
|
|
|
4908 |
var ta = d.doc.createElement("span");
|
|
|
4909 |
if(d.isString(content)){
|
|
|
4910 |
ta.innerHTML = content;
|
|
|
4911 |
}else{
|
|
|
4912 |
ta.appendChild(content);
|
|
|
4913 |
}
|
|
|
4914 |
var ct = ((position == "first")||(position == "after")) ? "lastChild" : "firstChild";
|
|
|
4915 |
this.forEach(function(item){
|
|
|
4916 |
var tn = ta.cloneNode(true);
|
|
|
4917 |
while(tn[ct]){
|
|
|
4918 |
d.place(tn[ct], item, position);
|
|
|
4919 |
}
|
|
|
4920 |
});
|
|
|
4921 |
return this; // dojo.NodeList
|
|
|
4922 |
}
|
|
|
4923 |
});
|
|
|
4924 |
|
|
|
4925 |
// syntactic sugar for DOM events
|
|
|
4926 |
d.forEach([
|
|
|
4927 |
"blur", "click", "keydown", "keypress", "keyup", "mousedown", "mouseenter",
|
|
|
4928 |
"mouseleave", "mousemove", "mouseout", "mouseover", "mouseup"
|
|
|
4929 |
], function(evt){
|
|
|
4930 |
var _oe = "on"+evt;
|
|
|
4931 |
dojo.NodeList.prototype[_oe] = function(a, b){
|
|
|
4932 |
return this.connect(_oe, a, b);
|
|
|
4933 |
}
|
|
|
4934 |
// FIXME: should these events trigger publishes?
|
|
|
4935 |
/*
|
|
|
4936 |
return (a ? this.connect(_oe, a, b) :
|
|
|
4937 |
this.forEach(function(n){
|
|
|
4938 |
// FIXME:
|
|
|
4939 |
// listeners get buried by
|
|
|
4940 |
// addEventListener and can't be dug back
|
|
|
4941 |
// out to be triggered externally.
|
|
|
4942 |
// see:
|
|
|
4943 |
// http://developer.mozilla.org/en/docs/DOM:element
|
|
|
4944 |
|
|
|
4945 |
console.debug(n, evt, _oe);
|
|
|
4946 |
|
|
|
4947 |
// FIXME: need synthetic event support!
|
|
|
4948 |
var _e = { target: n, faux: true, type: evt };
|
|
|
4949 |
// dojo._event_listener._synthesizeEvent({}, { target: n, faux: true, type: evt });
|
|
|
4950 |
try{ n[evt](_e); }catch(e){ console.debug(e); }
|
|
|
4951 |
try{ n[_oe](_e); }catch(e){ console.debug(e); }
|
|
|
4952 |
})
|
|
|
4953 |
);
|
|
|
4954 |
}
|
|
|
4955 |
*/
|
|
|
4956 |
}
|
|
|
4957 |
);
|
|
|
4958 |
|
|
|
4959 |
})();
|
|
|
4960 |
|
|
|
4961 |
}
|
|
|
4962 |
|
|
|
4963 |
if(!dojo._hasResource["dojo._base.query"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
4964 |
dojo._hasResource["dojo._base.query"] = true;
|
|
|
4965 |
dojo.provide("dojo._base.query");
|
|
|
4966 |
|
|
|
4967 |
|
|
|
4968 |
/*
|
|
|
4969 |
dojo.query() architectural overview:
|
|
|
4970 |
|
|
|
4971 |
dojo.query is a relatively full-featured CSS3 query library. It is
|
|
|
4972 |
designed to take any valid CSS3 selector and return the nodes matching
|
|
|
4973 |
the selector. To do this quickly, it processes queries in several
|
|
|
4974 |
steps, applying caching where profitable.
|
|
|
4975 |
|
|
|
4976 |
The steps (roughly in reverse order of the way they appear in the code):
|
|
|
4977 |
1.) check to see if we already have a "query dispatcher"
|
|
|
4978 |
- if so, use that with the given parameterization. Skip to step 4.
|
|
|
4979 |
2.) attempt to determine which branch to dispatch the query to:
|
|
|
4980 |
- JS (optimized DOM iteration)
|
|
|
4981 |
- xpath (for browsers that support it and where it's fast)
|
|
|
4982 |
- native (not available in any browser yet)
|
|
|
4983 |
3.) tokenize and convert to executable "query dispatcher"
|
|
|
4984 |
- this is where the lion's share of the complexity in the
|
|
|
4985 |
system lies. In the DOM version, the query dispatcher is
|
|
|
4986 |
assembled as a chain of "yes/no" test functions pertaining to
|
|
|
4987 |
a section of a simple query statement (".blah:nth-child(odd)"
|
|
|
4988 |
but not "div div", which is 2 simple statements). Individual
|
|
|
4989 |
statement dispatchers are cached (to prevent re-definition)
|
|
|
4990 |
as are entire dispatch chains (to make re-execution of the
|
|
|
4991 |
same query fast)
|
|
|
4992 |
- in the xpath path, tokenization yeilds a concatenation of
|
|
|
4993 |
parameterized xpath selectors. As with the DOM version, both
|
|
|
4994 |
simple selector blocks and overall evaluators are cached to
|
|
|
4995 |
prevent re-defintion
|
|
|
4996 |
4.) the resulting query dispatcher is called in the passed scope (by default the top-level document)
|
|
|
4997 |
- for DOM queries, this results in a recursive, top-down
|
|
|
4998 |
evaluation of nodes based on each simple query section
|
|
|
4999 |
- xpath queries can, thankfully, be executed in one shot
|
|
|
5000 |
5.) matched nodes are pruned to ensure they are unique
|
|
|
5001 |
*/
|
|
|
5002 |
|
|
|
5003 |
;(function(){
|
|
|
5004 |
// define everything in a closure for compressability reasons. "d" is an
|
|
|
5005 |
// alias to "dojo" since it's so frequently used. This seems a
|
|
|
5006 |
// transformation that the build system could perform on a per-file basis.
|
|
|
5007 |
|
|
|
5008 |
////////////////////////////////////////////////////////////////////////
|
|
|
5009 |
// Utility code
|
|
|
5010 |
////////////////////////////////////////////////////////////////////////
|
|
|
5011 |
|
|
|
5012 |
var d = dojo;
|
|
|
5013 |
var childNodesName = dojo.isIE ? "children" : "childNodes";
|
|
|
5014 |
|
|
|
5015 |
var getQueryParts = function(query){
|
|
|
5016 |
// summary: state machine for query tokenization
|
|
|
5017 |
if(query.charAt(query.length-1) == ">"){
|
|
|
5018 |
query += " *"
|
|
|
5019 |
}
|
|
|
5020 |
query += " "; // ensure that we terminate the state machine
|
|
|
5021 |
|
|
|
5022 |
var ts = function(s, e){
|
|
|
5023 |
return d.trim(query.slice(s, e));
|
|
|
5024 |
}
|
|
|
5025 |
|
|
|
5026 |
// the overall data graph of the full query, as represented by queryPart objects
|
|
|
5027 |
var qparts = [];
|
|
|
5028 |
// state keeping vars
|
|
|
5029 |
var inBrackets = -1;
|
|
|
5030 |
var inParens = -1;
|
|
|
5031 |
var inMatchFor = -1;
|
|
|
5032 |
var inPseudo = -1;
|
|
|
5033 |
var inClass = -1;
|
|
|
5034 |
var inId = -1;
|
|
|
5035 |
var inTag = -1;
|
|
|
5036 |
var lc = ""; // the last character
|
|
|
5037 |
var cc = ""; // the current character
|
|
|
5038 |
var pStart;
|
|
|
5039 |
// iteration vars
|
|
|
5040 |
var x = 0; // index in the query
|
|
|
5041 |
var ql = query.length;
|
|
|
5042 |
var currentPart = null; // data structure representing the entire clause
|
|
|
5043 |
var _cp = null; // the current pseudo or attr matcher
|
|
|
5044 |
|
|
|
5045 |
var endTag = function(){
|
|
|
5046 |
if(inTag >= 0){
|
|
|
5047 |
var tv = (inTag == x) ? null : ts(inTag, x).toLowerCase();
|
|
|
5048 |
currentPart[ (">~+".indexOf(tv) < 0)? "tag" : "oper" ] = tv;
|
|
|
5049 |
inTag = -1;
|
|
|
5050 |
}
|
|
|
5051 |
}
|
|
|
5052 |
|
|
|
5053 |
var endId = function(){
|
|
|
5054 |
if(inId >= 0){
|
|
|
5055 |
currentPart.id = ts(inId, x).replace(/\\/g, "");
|
|
|
5056 |
inId = -1;
|
|
|
5057 |
}
|
|
|
5058 |
}
|
|
|
5059 |
|
|
|
5060 |
var endClass = function(){
|
|
|
5061 |
if(inClass >= 0){
|
|
|
5062 |
currentPart.classes.push(ts(inClass+1, x).replace(/\\/g, ""));
|
|
|
5063 |
inClass = -1;
|
|
|
5064 |
}
|
|
|
5065 |
}
|
|
|
5066 |
|
|
|
5067 |
var endAll = function(){
|
|
|
5068 |
endId(); endTag(); endClass();
|
|
|
5069 |
}
|
|
|
5070 |
|
|
|
5071 |
for(; x<ql, lc=cc, cc=query.charAt(x); x++){
|
|
|
5072 |
if(lc == "\\"){ continue; }
|
|
|
5073 |
if(!currentPart){
|
|
|
5074 |
// NOTE: I hate all this alloc, but it's shorter than writing tons of if's
|
|
|
5075 |
pStart = x;
|
|
|
5076 |
currentPart = {
|
|
|
5077 |
query: null,
|
|
|
5078 |
pseudos: [],
|
|
|
5079 |
attrs: [],
|
|
|
5080 |
classes: [],
|
|
|
5081 |
tag: null,
|
|
|
5082 |
oper: null,
|
|
|
5083 |
id: null
|
|
|
5084 |
};
|
|
|
5085 |
inTag = x;
|
|
|
5086 |
}
|
|
|
5087 |
|
|
|
5088 |
if(inBrackets >= 0){
|
|
|
5089 |
// look for a the close first
|
|
|
5090 |
if(cc == "]"){
|
|
|
5091 |
if(!_cp.attr){
|
|
|
5092 |
_cp.attr = ts(inBrackets+1, x);
|
|
|
5093 |
}else{
|
|
|
5094 |
_cp.matchFor = ts((inMatchFor||inBrackets+1), x);
|
|
|
5095 |
}
|
|
|
5096 |
var cmf = _cp.matchFor;
|
|
|
5097 |
if(cmf){
|
|
|
5098 |
if( (cmf.charAt(0) == '"') || (cmf.charAt(0) == "'") ){
|
|
|
5099 |
_cp.matchFor = cmf.substring(1, cmf.length-1);
|
|
|
5100 |
}
|
|
|
5101 |
}
|
|
|
5102 |
currentPart.attrs.push(_cp);
|
|
|
5103 |
_cp = null; // necessaray?
|
|
|
5104 |
inBrackets = inMatchFor = -1;
|
|
|
5105 |
}else if(cc == "="){
|
|
|
5106 |
var addToCc = ("|~^$*".indexOf(lc) >=0 ) ? lc : "";
|
|
|
5107 |
_cp.type = addToCc+cc;
|
|
|
5108 |
_cp.attr = ts(inBrackets+1, x-addToCc.length);
|
|
|
5109 |
inMatchFor = x+1;
|
|
|
5110 |
}
|
|
|
5111 |
// now look for other clause parts
|
|
|
5112 |
}else if(inParens >= 0){
|
|
|
5113 |
if(cc == ")"){
|
|
|
5114 |
if(inPseudo >= 0){
|
|
|
5115 |
_cp.value = ts(inParens+1, x);
|
|
|
5116 |
}
|
|
|
5117 |
inPseudo = inParens = -1;
|
|
|
5118 |
}
|
|
|
5119 |
}else if(cc == "#"){
|
|
|
5120 |
endAll();
|
|
|
5121 |
inId = x+1;
|
|
|
5122 |
}else if(cc == "."){
|
|
|
5123 |
endAll();
|
|
|
5124 |
inClass = x;
|
|
|
5125 |
}else if(cc == ":"){
|
|
|
5126 |
endAll();
|
|
|
5127 |
inPseudo = x;
|
|
|
5128 |
}else if(cc == "["){
|
|
|
5129 |
endAll();
|
|
|
5130 |
inBrackets = x;
|
|
|
5131 |
_cp = {
|
|
|
5132 |
/*=====
|
|
|
5133 |
attr: null, type: null, matchFor: null
|
|
|
5134 |
=====*/
|
|
|
5135 |
};
|
|
|
5136 |
}else if(cc == "("){
|
|
|
5137 |
if(inPseudo >= 0){
|
|
|
5138 |
_cp = {
|
|
|
5139 |
name: ts(inPseudo+1, x),
|
|
|
5140 |
value: null
|
|
|
5141 |
}
|
|
|
5142 |
currentPart.pseudos.push(_cp);
|
|
|
5143 |
}
|
|
|
5144 |
inParens = x;
|
|
|
5145 |
}else if(cc == " " && lc != cc){
|
|
|
5146 |
// note that we expect the string to be " " terminated
|
|
|
5147 |
endAll();
|
|
|
5148 |
if(inPseudo >= 0){
|
|
|
5149 |
currentPart.pseudos.push({ name: ts(inPseudo+1, x) });
|
|
|
5150 |
}
|
|
|
5151 |
currentPart.hasLoops = (
|
|
|
5152 |
currentPart.pseudos.length ||
|
|
|
5153 |
currentPart.attrs.length ||
|
|
|
5154 |
currentPart.classes.length );
|
|
|
5155 |
currentPart.query = ts(pStart, x);
|
|
|
5156 |
currentPart.tag = (currentPart["oper"]) ? null : (currentPart.tag || "*");
|
|
|
5157 |
qparts.push(currentPart);
|
|
|
5158 |
currentPart = null;
|
|
|
5159 |
}
|
|
|
5160 |
}
|
|
|
5161 |
return qparts;
|
|
|
5162 |
};
|
|
|
5163 |
|
|
|
5164 |
|
|
|
5165 |
////////////////////////////////////////////////////////////////////////
|
|
|
5166 |
// XPath query code
|
|
|
5167 |
////////////////////////////////////////////////////////////////////////
|
|
|
5168 |
|
|
|
5169 |
// this array is a lookup used to generate an attribute matching function.
|
|
|
5170 |
// There is a similar lookup/generator list for the DOM branch with similar
|
|
|
5171 |
// calling semantics.
|
|
|
5172 |
var xPathAttrs = {
|
|
|
5173 |
"*=": function(attr, value){
|
|
|
5174 |
return "[contains(@"+attr+", '"+ value +"')]";
|
|
|
5175 |
},
|
|
|
5176 |
"^=": function(attr, value){
|
|
|
5177 |
return "[starts-with(@"+attr+", '"+ value +"')]";
|
|
|
5178 |
},
|
|
|
5179 |
"$=": function(attr, value){
|
|
|
5180 |
return "[substring(@"+attr+", string-length(@"+attr+")-"+(value.length-1)+")='"+value+"']";
|
|
|
5181 |
},
|
|
|
5182 |
"~=": function(attr, value){
|
|
|
5183 |
return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
|
|
|
5184 |
},
|
|
|
5185 |
"|=": function(attr, value){
|
|
|
5186 |
return "[contains(concat(' ',@"+attr+",' '), ' "+ value +"-')]";
|
|
|
5187 |
},
|
|
|
5188 |
"=": function(attr, value){
|
|
|
5189 |
return "[@"+attr+"='"+ value +"']";
|
|
|
5190 |
}
|
|
|
5191 |
};
|
|
|
5192 |
|
|
|
5193 |
// takes a list of attribute searches, the overall query, a function to
|
|
|
5194 |
// generate a default matcher, and a closure-bound method for providing a
|
|
|
5195 |
// matching function that generates whatever type of yes/no distinguisher
|
|
|
5196 |
// the query method needs. The method is a bit tortured and hard to read
|
|
|
5197 |
// because it needs to be used in both the XPath and DOM branches.
|
|
|
5198 |
var handleAttrs = function( attrList,
|
|
|
5199 |
query,
|
|
|
5200 |
getDefault,
|
|
|
5201 |
handleMatch){
|
|
|
5202 |
d.forEach(query.attrs, function(attr){
|
|
|
5203 |
var matcher;
|
|
|
5204 |
// type, attr, matchFor
|
|
|
5205 |
if(attr.type && attrList[attr.type]){
|
|
|
5206 |
matcher = attrList[attr.type](attr.attr, attr.matchFor);
|
|
|
5207 |
}else if(attr.attr.length){
|
|
|
5208 |
matcher = getDefault(attr.attr);
|
|
|
5209 |
}
|
|
|
5210 |
if(matcher){ handleMatch(matcher); }
|
|
|
5211 |
});
|
|
|
5212 |
}
|
|
|
5213 |
|
|
|
5214 |
var buildPath = function(query){
|
|
|
5215 |
var xpath = ".";
|
|
|
5216 |
var qparts = getQueryParts(d.trim(query));
|
|
|
5217 |
while(qparts.length){
|
|
|
5218 |
var tqp = qparts.shift();
|
|
|
5219 |
var prefix;
|
|
|
5220 |
// FIXME: need to add support for ~ and +
|
|
|
5221 |
if(tqp.oper == ">"){
|
|
|
5222 |
prefix = "/";
|
|
|
5223 |
// prefix = "/child::node()";
|
|
|
5224 |
tqp = qparts.shift();
|
|
|
5225 |
}else{
|
|
|
5226 |
prefix = "//";
|
|
|
5227 |
// prefix = "/descendant::node()"
|
|
|
5228 |
}
|
|
|
5229 |
|
|
|
5230 |
// get the tag name (if any)
|
|
|
5231 |
|
|
|
5232 |
xpath += prefix + tqp.tag;
|
|
|
5233 |
|
|
|
5234 |
// check to see if it's got an id. Needs to come first in xpath.
|
|
|
5235 |
if(tqp.id){
|
|
|
5236 |
xpath += "[@id='"+tqp.id+"'][1]";
|
|
|
5237 |
}
|
|
|
5238 |
|
|
|
5239 |
d.forEach(tqp.classes, function(cn){
|
|
|
5240 |
var cnl = cn.length;
|
|
|
5241 |
var padding = " ";
|
|
|
5242 |
if(cn.charAt(cnl-1) == "*"){
|
|
|
5243 |
padding = ""; cn = cn.substr(0, cnl-1);
|
|
|
5244 |
}
|
|
|
5245 |
xpath +=
|
|
|
5246 |
"[contains(concat(' ',@class,' '), ' "+
|
|
|
5247 |
cn + padding + "')]";
|
|
|
5248 |
});
|
|
|
5249 |
|
|
|
5250 |
handleAttrs(xPathAttrs, tqp,
|
|
|
5251 |
function(condition){
|
|
|
5252 |
return "[@"+condition+"]";
|
|
|
5253 |
},
|
|
|
5254 |
function(matcher){
|
|
|
5255 |
xpath += matcher;
|
|
|
5256 |
}
|
|
|
5257 |
);
|
|
|
5258 |
|
|
|
5259 |
// FIXME: need to implement pseudo-class checks!!
|
|
|
5260 |
};
|
|
|
5261 |
return xpath;
|
|
|
5262 |
};
|
|
|
5263 |
|
|
|
5264 |
var _xpathFuncCache = {};
|
|
|
5265 |
var getXPathFunc = function(path){
|
|
|
5266 |
if(_xpathFuncCache[path]){
|
|
|
5267 |
return _xpathFuncCache[path];
|
|
|
5268 |
}
|
|
|
5269 |
|
|
|
5270 |
var doc = d.doc;
|
|
|
5271 |
// var parent = d.body(); // FIXME
|
|
|
5272 |
// FIXME: don't need to memoize. The closure scope handles it for us.
|
|
|
5273 |
var xpath = buildPath(path);
|
|
|
5274 |
|
|
|
5275 |
var tf = function(parent){
|
|
|
5276 |
// XPath query strings are memoized.
|
|
|
5277 |
var ret = [];
|
|
|
5278 |
var xpathResult;
|
|
|
5279 |
try{
|
|
|
5280 |
xpathResult = doc.evaluate(xpath, parent, null,
|
|
|
5281 |
// XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
|
|
|
5282 |
XPathResult.ANY_TYPE, null);
|
|
|
5283 |
}catch(e){
|
|
|
5284 |
console.debug("failure in exprssion:", xpath, "under:", parent);
|
|
|
5285 |
console.debug(e);
|
|
|
5286 |
}
|
|
|
5287 |
var result = xpathResult.iterateNext();
|
|
|
5288 |
while(result){
|
|
|
5289 |
ret.push(result);
|
|
|
5290 |
result = xpathResult.iterateNext();
|
|
|
5291 |
}
|
|
|
5292 |
return ret;
|
|
|
5293 |
}
|
|
|
5294 |
return _xpathFuncCache[path] = tf;
|
|
|
5295 |
};
|
|
|
5296 |
|
|
|
5297 |
/*
|
|
|
5298 |
d.xPathMatch = function(query){
|
|
|
5299 |
// XPath based DOM query system. Handles a small subset of CSS
|
|
|
5300 |
// selectors, subset is identical to the non-XPath version of this
|
|
|
5301 |
// function.
|
|
|
5302 |
|
|
|
5303 |
// FIXME: need to add support for alternate roots
|
|
|
5304 |
return getXPathFunc(query)();
|
|
|
5305 |
}
|
|
|
5306 |
*/
|
|
|
5307 |
|
|
|
5308 |
////////////////////////////////////////////////////////////////////////
|
|
|
5309 |
// DOM query code
|
|
|
5310 |
////////////////////////////////////////////////////////////////////////
|
|
|
5311 |
|
|
|
5312 |
var _filtersCache = {};
|
|
|
5313 |
var _simpleFiltersCache = {};
|
|
|
5314 |
|
|
|
5315 |
// the basic building block of the yes/no chaining system. agree(f1, f2)
|
|
|
5316 |
// generates a new function which returns the boolean results of both of
|
|
|
5317 |
// the passed functions to a single logical-anded result.
|
|
|
5318 |
var agree = function(first, second){
|
|
|
5319 |
if(!first){ return second; }
|
|
|
5320 |
if(!second){ return first; }
|
|
|
5321 |
|
|
|
5322 |
return function(){
|
|
|
5323 |
return first.apply(window, arguments) && second.apply(window, arguments);
|
|
|
5324 |
}
|
|
|
5325 |
}
|
|
|
5326 |
|
|
|
5327 |
var _filterDown = function(element, queryParts, matchArr, idx){
|
|
|
5328 |
var nidx = idx+1;
|
|
|
5329 |
var isFinal = (queryParts.length == nidx);
|
|
|
5330 |
var tqp = queryParts[idx];
|
|
|
5331 |
|
|
|
5332 |
// see if we can constrain our next level to direct children
|
|
|
5333 |
if(tqp.oper == ">"){
|
|
|
5334 |
var ecn = element[childNodesName];
|
|
|
5335 |
if(!ecn || !ecn.length){
|
|
|
5336 |
return;
|
|
|
5337 |
}
|
|
|
5338 |
nidx++;
|
|
|
5339 |
isFinal = (queryParts.length == nidx);
|
|
|
5340 |
// kinda janky, too much array alloc
|
|
|
5341 |
var tf = getFilterFunc(queryParts[idx+1]);
|
|
|
5342 |
// for(var x=ecn.length-1, te; x>=0, te=ecn[x]; x--){
|
|
|
5343 |
for(var x=0, ecnl=ecn.length, te; x<ecnl, te=ecn[x]; x++){
|
|
|
5344 |
if(tf(te)){
|
|
|
5345 |
if(isFinal){
|
|
|
5346 |
matchArr.push(te);
|
|
|
5347 |
}else{
|
|
|
5348 |
_filterDown(te, queryParts, matchArr, nidx);
|
|
|
5349 |
}
|
|
|
5350 |
}
|
|
|
5351 |
/*
|
|
|
5352 |
if(x==0){
|
|
|
5353 |
break;
|
|
|
5354 |
}
|
|
|
5355 |
*/
|
|
|
5356 |
}
|
|
|
5357 |
}
|
|
|
5358 |
|
|
|
5359 |
// otherwise, keep going down, unless we'er at the end
|
|
|
5360 |
var candidates = getElementsFunc(tqp)(element);
|
|
|
5361 |
if(isFinal){
|
|
|
5362 |
while(candidates.length){
|
|
|
5363 |
matchArr.push(candidates.shift());
|
|
|
5364 |
}
|
|
|
5365 |
/*
|
|
|
5366 |
candidates.unshift(0, matchArr.length-1);
|
|
|
5367 |
matchArr.splice.apply(matchArr, candidates);
|
|
|
5368 |
*/
|
|
|
5369 |
}else{
|
|
|
5370 |
// if we're not yet at the bottom, keep going!
|
|
|
5371 |
while(candidates.length){
|
|
|
5372 |
_filterDown(candidates.shift(), queryParts, matchArr, nidx);
|
|
|
5373 |
}
|
|
|
5374 |
}
|
|
|
5375 |
}
|
|
|
5376 |
|
|
|
5377 |
var filterDown = function(elements, queryParts){
|
|
|
5378 |
var ret = [];
|
|
|
5379 |
|
|
|
5380 |
// for every root, get the elements that match the descendant selector
|
|
|
5381 |
// for(var x=elements.length-1, te; x>=0, te=elements[x]; x--){
|
|
|
5382 |
var x = elements.length - 1, te;
|
|
|
5383 |
while(te = elements[x--]){
|
|
|
5384 |
_filterDown(te, queryParts, ret, 0);
|
|
|
5385 |
}
|
|
|
5386 |
return ret;
|
|
|
5387 |
}
|
|
|
5388 |
|
|
|
5389 |
var getFilterFunc = function(q){
|
|
|
5390 |
// note: query can't have spaces!
|
|
|
5391 |
if(_filtersCache[q.query]){
|
|
|
5392 |
return _filtersCache[q.query];
|
|
|
5393 |
}
|
|
|
5394 |
var ff = null;
|
|
|
5395 |
|
|
|
5396 |
// does it have a tagName component?
|
|
|
5397 |
if(q.tag){
|
|
|
5398 |
if(q.tag == "*"){
|
|
|
5399 |
ff = agree(ff,
|
|
|
5400 |
function(elem){
|
|
|
5401 |
return (elem.nodeType == 1);
|
|
|
5402 |
}
|
|
|
5403 |
);
|
|
|
5404 |
}else{
|
|
|
5405 |
// tag name match
|
|
|
5406 |
ff = agree(ff,
|
|
|
5407 |
function(elem){
|
|
|
5408 |
return (
|
|
|
5409 |
(elem.nodeType == 1) &&
|
|
|
5410 |
(q.tag == elem.tagName.toLowerCase())
|
|
|
5411 |
);
|
|
|
5412 |
// return isTn;
|
|
|
5413 |
}
|
|
|
5414 |
);
|
|
|
5415 |
}
|
|
|
5416 |
}
|
|
|
5417 |
|
|
|
5418 |
// does the node have an ID?
|
|
|
5419 |
if(q.id){
|
|
|
5420 |
ff = agree(ff,
|
|
|
5421 |
function(elem){
|
|
|
5422 |
return (
|
|
|
5423 |
(elem.nodeType == 1) &&
|
|
|
5424 |
(elem.id == q.id)
|
|
|
5425 |
);
|
|
|
5426 |
}
|
|
|
5427 |
);
|
|
|
5428 |
}
|
|
|
5429 |
|
|
|
5430 |
if(q.hasLoops){
|
|
|
5431 |
// if we have other query param parts, make sure we add them to the
|
|
|
5432 |
// filter chain
|
|
|
5433 |
ff = agree(ff, getSimpleFilterFunc(q));
|
|
|
5434 |
}
|
|
|
5435 |
|
|
|
5436 |
return _filtersCache[q.query] = ff;
|
|
|
5437 |
}
|
|
|
5438 |
|
|
|
5439 |
var getNodeIndex = function(node){
|
|
|
5440 |
// NOTE:
|
|
|
5441 |
// we could have a more accurate caching mechanism by invalidating
|
|
|
5442 |
// caches after the query has finished, but I think that'd lead to
|
|
|
5443 |
// significantly more cache churn than the cache would provide
|
|
|
5444 |
// value for in the common case. Generally, we're more
|
|
|
5445 |
// conservative (and therefore, more accurate) than jQuery and
|
|
|
5446 |
// DomQuery WRT node node indexes, but there may be corner cases
|
|
|
5447 |
// in which we fall down. How much we care about them is TBD.
|
|
|
5448 |
|
|
|
5449 |
var pn = node.parentNode;
|
|
|
5450 |
var pnc = pn.childNodes;
|
|
|
5451 |
|
|
|
5452 |
// check to see if we can trust the cache. If not, re-key the whole
|
|
|
5453 |
// thing and return our node match from that.
|
|
|
5454 |
|
|
|
5455 |
var nidx = -1;
|
|
|
5456 |
var child = pn.firstChild;
|
|
|
5457 |
if(!child){
|
|
|
5458 |
return nidx;
|
|
|
5459 |
}
|
|
|
5460 |
|
|
|
5461 |
var ci = node["__cachedIndex"];
|
|
|
5462 |
var cl = pn["__cachedLength"];
|
|
|
5463 |
|
|
|
5464 |
// only handle cache building if we've gone out of sync
|
|
|
5465 |
if(((typeof cl == "number")&&(cl != pnc.length))||(typeof ci != "number")){
|
|
|
5466 |
// rip though the whole set, building cache indexes as we go
|
|
|
5467 |
pn["__cachedLength"] = pnc.length;
|
|
|
5468 |
var idx = 1;
|
|
|
5469 |
do{
|
|
|
5470 |
// we only assign indexes for nodes with nodeType == 1, as per:
|
|
|
5471 |
// http://www.w3.org/TR/css3-selectors/#nth-child-pseudo
|
|
|
5472 |
// only elements are counted in the search order, and they
|
|
|
5473 |
// begin at 1 for the first child's index
|
|
|
5474 |
|
|
|
5475 |
if(child === node){
|
|
|
5476 |
nidx = idx;
|
|
|
5477 |
}
|
|
|
5478 |
if(child.nodeType == 1){
|
|
|
5479 |
child["__cachedIndex"] = idx;
|
|
|
5480 |
idx++;
|
|
|
5481 |
}
|
|
|
5482 |
child = child.nextSibling;
|
|
|
5483 |
}while(child);
|
|
|
5484 |
}else{
|
|
|
5485 |
// NOTE:
|
|
|
5486 |
// could be incorrect in some cases (node swaps involving the
|
|
|
5487 |
// passed node, etc.), but we ignore those due to the relative
|
|
|
5488 |
// unlikelihood of that occuring
|
|
|
5489 |
nidx = ci;
|
|
|
5490 |
}
|
|
|
5491 |
return nidx;
|
|
|
5492 |
}
|
|
|
5493 |
|
|
|
5494 |
var firedCount = 0;
|
|
|
5495 |
|
|
|
5496 |
var blank = "";
|
|
|
5497 |
var _getAttr = function(elem, attr){
|
|
|
5498 |
if(attr == "class"){
|
|
|
5499 |
return elem.className || blank;
|
|
|
5500 |
}
|
|
|
5501 |
if(attr == "for"){
|
|
|
5502 |
return elem.htmlFor || blank;
|
|
|
5503 |
}
|
|
|
5504 |
return elem.getAttribute(attr, 2) || blank;
|
|
|
5505 |
}
|
|
|
5506 |
|
|
|
5507 |
var attrs = {
|
|
|
5508 |
"*=": function(attr, value){
|
|
|
5509 |
return function(elem){
|
|
|
5510 |
// E[foo*="bar"]
|
|
|
5511 |
// an E element whose "foo" attribute value contains
|
|
|
5512 |
// the substring "bar"
|
|
|
5513 |
return (_getAttr(elem, attr).indexOf(value)>=0);
|
|
|
5514 |
}
|
|
|
5515 |
},
|
|
|
5516 |
"^=": function(attr, value){
|
|
|
5517 |
// E[foo^="bar"]
|
|
|
5518 |
// an E element whose "foo" attribute value begins exactly
|
|
|
5519 |
// with the string "bar"
|
|
|
5520 |
return function(elem){
|
|
|
5521 |
return (_getAttr(elem, attr).indexOf(value)==0);
|
|
|
5522 |
}
|
|
|
5523 |
},
|
|
|
5524 |
"$=": function(attr, value){
|
|
|
5525 |
// E[foo$="bar"]
|
|
|
5526 |
// an E element whose "foo" attribute value ends exactly
|
|
|
5527 |
// with the string "bar"
|
|
|
5528 |
var tval = " "+value;
|
|
|
5529 |
return function(elem){
|
|
|
5530 |
var ea = " "+_getAttr(elem, attr);
|
|
|
5531 |
return (ea.lastIndexOf(value)==(ea.length-value.length));
|
|
|
5532 |
}
|
|
|
5533 |
},
|
|
|
5534 |
"~=": function(attr, value){
|
|
|
5535 |
// E[foo~="bar"]
|
|
|
5536 |
// an E element whose "foo" attribute value is a list of
|
|
|
5537 |
// space-separated values, one of which is exactly equal
|
|
|
5538 |
// to "bar"
|
|
|
5539 |
|
|
|
5540 |
// return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
|
|
|
5541 |
var tval = " "+value+" ";
|
|
|
5542 |
return function(elem){
|
|
|
5543 |
var ea = " "+_getAttr(elem, attr)+" ";
|
|
|
5544 |
return (ea.indexOf(tval)>=0);
|
|
|
5545 |
}
|
|
|
5546 |
},
|
|
|
5547 |
"|=": function(attr, value){
|
|
|
5548 |
// E[hreflang|="en"]
|
|
|
5549 |
// an E element whose "hreflang" attribute has a
|
|
|
5550 |
// hyphen-separated list of values beginning (from the
|
|
|
5551 |
// left) with "en"
|
|
|
5552 |
var valueDash = " "+value+"-";
|
|
|
5553 |
return function(elem){
|
|
|
5554 |
var ea = " "+(elem.getAttribute(attr, 2) || "");
|
|
|
5555 |
return (
|
|
|
5556 |
(ea == value) ||
|
|
|
5557 |
(ea.indexOf(valueDash)==0)
|
|
|
5558 |
);
|
|
|
5559 |
}
|
|
|
5560 |
},
|
|
|
5561 |
"=": function(attr, value){
|
|
|
5562 |
return function(elem){
|
|
|
5563 |
return (_getAttr(elem, attr) == value);
|
|
|
5564 |
}
|
|
|
5565 |
}
|
|
|
5566 |
};
|
|
|
5567 |
|
|
|
5568 |
var pseudos = {
|
|
|
5569 |
"first-child": function(name, condition){
|
|
|
5570 |
return function(elem){
|
|
|
5571 |
if(elem.nodeType != 1){ return false; }
|
|
|
5572 |
// check to see if any of the previous siblings are elements
|
|
|
5573 |
var fc = elem.previousSibling;
|
|
|
5574 |
while(fc && (fc.nodeType != 1)){
|
|
|
5575 |
fc = fc.previousSibling;
|
|
|
5576 |
}
|
|
|
5577 |
return (!fc);
|
|
|
5578 |
}
|
|
|
5579 |
},
|
|
|
5580 |
"last-child": function(name, condition){
|
|
|
5581 |
return function(elem){
|
|
|
5582 |
if(elem.nodeType != 1){ return false; }
|
|
|
5583 |
// check to see if any of the next siblings are elements
|
|
|
5584 |
var nc = elem.nextSibling;
|
|
|
5585 |
while(nc && (nc.nodeType != 1)){
|
|
|
5586 |
nc = nc.nextSibling;
|
|
|
5587 |
}
|
|
|
5588 |
return (!nc);
|
|
|
5589 |
}
|
|
|
5590 |
},
|
|
|
5591 |
"empty": function(name, condition){
|
|
|
5592 |
return function(elem){
|
|
|
5593 |
// DomQuery and jQuery get this wrong, oddly enough.
|
|
|
5594 |
// The CSS 3 selectors spec is pretty explicit about
|
|
|
5595 |
// it, too.
|
|
|
5596 |
var cn = elem.childNodes;
|
|
|
5597 |
var cnl = elem.childNodes.length;
|
|
|
5598 |
// if(!cnl){ return true; }
|
|
|
5599 |
for(var x=cnl-1; x >= 0; x--){
|
|
|
5600 |
var nt = cn[x].nodeType;
|
|
|
5601 |
if((nt == 1)||(nt == 3)){ return false; }
|
|
|
5602 |
}
|
|
|
5603 |
return true;
|
|
|
5604 |
}
|
|
|
5605 |
},
|
|
|
5606 |
/* non standard!
|
|
|
5607 |
"contains": function(name, condition){
|
|
|
5608 |
return function(elem){
|
|
|
5609 |
// FIXME: I dislike this version of "contains", as
|
|
|
5610 |
// whimsical attribute could set it off. An inner-text
|
|
|
5611 |
// based version might be more accurate, but since
|
|
|
5612 |
// jQuery and DomQuery also potentially get this wrong,
|
|
|
5613 |
// I'm leaving it for now.
|
|
|
5614 |
return (elem.innerHTML.indexOf(condition) >= 0);
|
|
|
5615 |
}
|
|
|
5616 |
},
|
|
|
5617 |
*/
|
|
|
5618 |
"not": function(name, condition){
|
|
|
5619 |
var ntf = getFilterFunc(getQueryParts(condition)[0]);
|
|
|
5620 |
return function(elem){
|
|
|
5621 |
return (!ntf(elem));
|
|
|
5622 |
}
|
|
|
5623 |
},
|
|
|
5624 |
"nth-child": function(name, condition){
|
|
|
5625 |
var pi = parseInt;
|
|
|
5626 |
if(condition == "odd"){
|
|
|
5627 |
return function(elem){
|
|
|
5628 |
return (
|
|
|
5629 |
((getNodeIndex(elem)) % 2) == 1
|
|
|
5630 |
);
|
|
|
5631 |
}
|
|
|
5632 |
}else if((condition == "2n")||
|
|
|
5633 |
(condition == "even")){
|
|
|
5634 |
return function(elem){
|
|
|
5635 |
return ((getNodeIndex(elem) % 2) == 0);
|
|
|
5636 |
}
|
|
|
5637 |
}else if(condition.indexOf("0n+") == 0){
|
|
|
5638 |
var ncount = pi(condition.substr(3));
|
|
|
5639 |
return function(elem){
|
|
|
5640 |
return (elem.parentNode[childNodesName][ncount-1] === elem);
|
|
|
5641 |
}
|
|
|
5642 |
}else if( (condition.indexOf("n+") > 0) &&
|
|
|
5643 |
(condition.length > 3) ){
|
|
|
5644 |
var tparts = condition.split("n+", 2);
|
|
|
5645 |
var pred = pi(tparts[0]);
|
|
|
5646 |
var idx = pi(tparts[1]);
|
|
|
5647 |
return function(elem){
|
|
|
5648 |
return ((getNodeIndex(elem) % pred) == idx);
|
|
|
5649 |
}
|
|
|
5650 |
}else if(condition.indexOf("n") == -1){
|
|
|
5651 |
var ncount = pi(condition);
|
|
|
5652 |
return function(elem){
|
|
|
5653 |
return (getNodeIndex(elem) == ncount);
|
|
|
5654 |
}
|
|
|
5655 |
}
|
|
|
5656 |
}
|
|
|
5657 |
};
|
|
|
5658 |
|
|
|
5659 |
var defaultGetter = (d.isIE) ? function(cond){
|
|
|
5660 |
var clc = cond.toLowerCase();
|
|
|
5661 |
return function(elem){
|
|
|
5662 |
return elem[cond]||elem[clc];
|
|
|
5663 |
}
|
|
|
5664 |
} : function(cond){
|
|
|
5665 |
return function(elem){
|
|
|
5666 |
return (elem && elem.getAttribute && elem.hasAttribute(cond));
|
|
|
5667 |
}
|
|
|
5668 |
};
|
|
|
5669 |
|
|
|
5670 |
var getSimpleFilterFunc = function(query){
|
|
|
5671 |
|
|
|
5672 |
var fcHit = (_simpleFiltersCache[query.query]||_filtersCache[query.query]);
|
|
|
5673 |
if(fcHit){ return fcHit; }
|
|
|
5674 |
|
|
|
5675 |
var ff = null;
|
|
|
5676 |
|
|
|
5677 |
// the only case where we'll need the tag name is if we came from an ID query
|
|
|
5678 |
if(query.id){ // do we have an ID component?
|
|
|
5679 |
if(query.tag != "*"){
|
|
|
5680 |
ff = agree(ff, function(elem){
|
|
|
5681 |
return (elem.tagName.toLowerCase() == query.tag);
|
|
|
5682 |
});
|
|
|
5683 |
}
|
|
|
5684 |
}
|
|
|
5685 |
|
|
|
5686 |
// if there's a class in our query, generate a match function for it
|
|
|
5687 |
d.forEach(query.classes, function(cname, idx, arr){
|
|
|
5688 |
// get the class name
|
|
|
5689 |
var isWildcard = cname.charAt(cname.length-1) == "*";
|
|
|
5690 |
if(isWildcard){
|
|
|
5691 |
cname = cname.substr(0, cname.length-1);
|
|
|
5692 |
}
|
|
|
5693 |
// I dislike the regex thing, even if memozied in a cache, but it's VERY short
|
|
|
5694 |
var re = new RegExp("(?:^|\\s)" + cname + (isWildcard ? ".*" : "") + "(?:\\s|$)");
|
|
|
5695 |
ff = agree(ff, function(elem){
|
|
|
5696 |
return re.test(elem.className);
|
|
|
5697 |
});
|
|
|
5698 |
ff.count = idx;
|
|
|
5699 |
});
|
|
|
5700 |
|
|
|
5701 |
d.forEach(query.pseudos, function(pseudo){
|
|
|
5702 |
if(pseudos[pseudo.name]){
|
|
|
5703 |
ff = agree(ff, pseudos[pseudo.name](pseudo.name, pseudo.value));
|
|
|
5704 |
}
|
|
|
5705 |
});
|
|
|
5706 |
|
|
|
5707 |
handleAttrs(attrs, query, defaultGetter,
|
|
|
5708 |
function(tmatcher){ ff = agree(ff, tmatcher); }
|
|
|
5709 |
);
|
|
|
5710 |
if(!ff){
|
|
|
5711 |
ff = function(){ return true; };
|
|
|
5712 |
}
|
|
|
5713 |
return _simpleFiltersCache[query.query] = ff;
|
|
|
5714 |
}
|
|
|
5715 |
|
|
|
5716 |
var _getElementsFuncCache = { };
|
|
|
5717 |
|
|
|
5718 |
var getElementsFunc = function(query, root){
|
|
|
5719 |
var fHit = _getElementsFuncCache[query.query];
|
|
|
5720 |
if(fHit){ return fHit; }
|
|
|
5721 |
|
|
|
5722 |
// NOTE: this function is in the fast path! not memoized!!!
|
|
|
5723 |
|
|
|
5724 |
// the query doesn't contain any spaces, so there's only so many
|
|
|
5725 |
// things it could be
|
|
|
5726 |
|
|
|
5727 |
if(query.id && !query.hasLoops && !query.tag){
|
|
|
5728 |
// ID-only query. Easy.
|
|
|
5729 |
return _getElementsFuncCache[query.query] = function(root){
|
|
|
5730 |
// FIXME: if root != document, check for parenting!
|
|
|
5731 |
return [ d.byId(query.id) ];
|
|
|
5732 |
}
|
|
|
5733 |
}
|
|
|
5734 |
|
|
|
5735 |
var filterFunc = getSimpleFilterFunc(query);
|
|
|
5736 |
|
|
|
5737 |
var retFunc;
|
|
|
5738 |
if(query.tag && query.id && !query.hasLoops){
|
|
|
5739 |
// we got a filtered ID search (e.g., "h4#thinger")
|
|
|
5740 |
retFunc = function(root){
|
|
|
5741 |
var te = d.byId(query.id);
|
|
|
5742 |
if(filterFunc(te)){
|
|
|
5743 |
return [ te ];
|
|
|
5744 |
}
|
|
|
5745 |
}
|
|
|
5746 |
}else{
|
|
|
5747 |
var tret;
|
|
|
5748 |
|
|
|
5749 |
if(!query.hasLoops){
|
|
|
5750 |
// it's just a plain-ol elements-by-tag-name query from the root
|
|
|
5751 |
retFunc = function(root){
|
|
|
5752 |
var ret = [];
|
|
|
5753 |
var te, x=0, tret = root.getElementsByTagName(query.tag);
|
|
|
5754 |
while(te=tret[x++]){
|
|
|
5755 |
ret.push(te);
|
|
|
5756 |
}
|
|
|
5757 |
return ret;
|
|
|
5758 |
}
|
|
|
5759 |
}else{
|
|
|
5760 |
retFunc = function(root){
|
|
|
5761 |
var ret = [];
|
|
|
5762 |
var te, x=0, tret = root.getElementsByTagName(query.tag);
|
|
|
5763 |
while(te=tret[x++]){
|
|
|
5764 |
if(filterFunc(te)){
|
|
|
5765 |
ret.push(te);
|
|
|
5766 |
}
|
|
|
5767 |
}
|
|
|
5768 |
return ret;
|
|
|
5769 |
}
|
|
|
5770 |
}
|
|
|
5771 |
}
|
|
|
5772 |
return _getElementsFuncCache[query.query] = retFunc;
|
|
|
5773 |
}
|
|
|
5774 |
|
|
|
5775 |
var _partsCache = {};
|
|
|
5776 |
|
|
|
5777 |
////////////////////////////////////////////////////////////////////////
|
|
|
5778 |
// the query runner
|
|
|
5779 |
////////////////////////////////////////////////////////////////////////
|
|
|
5780 |
|
|
|
5781 |
// this is the second level of spliting, from full-length queries (e.g.,
|
|
|
5782 |
// "div.foo .bar") into simple query expressions (e.g., ["div.foo",
|
|
|
5783 |
// ".bar"])
|
|
|
5784 |
var _queryFuncCache = {
|
|
|
5785 |
"*": d.isIE ?
|
|
|
5786 |
function(root){
|
|
|
5787 |
return root.all;
|
|
|
5788 |
} :
|
|
|
5789 |
function(root){
|
|
|
5790 |
return root.getElementsByTagName("*");
|
|
|
5791 |
},
|
|
|
5792 |
">": function(root){
|
|
|
5793 |
var ret = [];
|
|
|
5794 |
var te, x=0, tret = root[childNodesName];
|
|
|
5795 |
while(te=tret[x++]){
|
|
|
5796 |
if(te.nodeType == 1){ ret.push(te); }
|
|
|
5797 |
}
|
|
|
5798 |
return ret;
|
|
|
5799 |
}
|
|
|
5800 |
};
|
|
|
5801 |
|
|
|
5802 |
var getStepQueryFunc = function(query){
|
|
|
5803 |
// if it's trivial, get a fast-path dispatcher
|
|
|
5804 |
var qparts = getQueryParts(d.trim(query));
|
|
|
5805 |
// if(query[query.length-1] == ">"){ query += " *"; }
|
|
|
5806 |
if(qparts.length == 1){
|
|
|
5807 |
var tt = getElementsFunc(qparts[0]);
|
|
|
5808 |
tt.nozip = true;
|
|
|
5809 |
return tt;
|
|
|
5810 |
}
|
|
|
5811 |
|
|
|
5812 |
// otherwise, break it up and return a runner that iterates over the parts recursively
|
|
|
5813 |
var sqf = function(root){
|
|
|
5814 |
var localQueryParts = qparts.slice(0); // clone the src arr
|
|
|
5815 |
var candidates;
|
|
|
5816 |
if(localQueryParts[0].oper == ">"){
|
|
|
5817 |
candidates = [ root ];
|
|
|
5818 |
// root = document;
|
|
|
5819 |
}else{
|
|
|
5820 |
candidates = getElementsFunc(localQueryParts.shift())(root);
|
|
|
5821 |
}
|
|
|
5822 |
return filterDown(candidates, localQueryParts);
|
|
|
5823 |
}
|
|
|
5824 |
return sqf;
|
|
|
5825 |
}
|
|
|
5826 |
|
|
|
5827 |
// a specialized method that implements our primoridal "query optimizer".
|
|
|
5828 |
// This allows us to dispatch queries to the fastest subsystem we can get.
|
|
|
5829 |
var _getQueryFunc = (
|
|
|
5830 |
// NOTE:
|
|
|
5831 |
// XPath on the Webkit nighlies is slower than it's DOM iteration
|
|
|
5832 |
// for most test cases
|
|
|
5833 |
// FIXME:
|
|
|
5834 |
// we should try to capture some runtime speed data for each query
|
|
|
5835 |
// function to determine on the fly if we should stick w/ the
|
|
|
5836 |
// potentially optimized variant or if we should try something
|
|
|
5837 |
// new.
|
|
|
5838 |
(document["evaluate"] && !d.isSafari) ?
|
|
|
5839 |
function(query){
|
|
|
5840 |
// has xpath support that's faster than DOM
|
|
|
5841 |
var qparts = query.split(" ");
|
|
|
5842 |
// can we handle it?
|
|
|
5843 |
if( (document["evaluate"])&&
|
|
|
5844 |
(query.indexOf(":") == -1)&&
|
|
|
5845 |
(
|
|
|
5846 |
(true) // ||
|
|
|
5847 |
// (query.indexOf("[") == -1) ||
|
|
|
5848 |
// (query.indexOf("=") == -1)
|
|
|
5849 |
)
|
|
|
5850 |
){
|
|
|
5851 |
// dojo.debug(query);
|
|
|
5852 |
// should we handle it?
|
|
|
5853 |
|
|
|
5854 |
// kind of a lame heuristic, but it works
|
|
|
5855 |
if(
|
|
|
5856 |
// a "div div div" style query
|
|
|
5857 |
((qparts.length > 2)&&(query.indexOf(">") == -1))||
|
|
|
5858 |
// or something else with moderate complexity. kinda janky
|
|
|
5859 |
(qparts.length > 3)||
|
|
|
5860 |
(query.indexOf("[")>=0)||
|
|
|
5861 |
// or if it's a ".thinger" query
|
|
|
5862 |
((1 == qparts.length)&&(0 <= query.indexOf(".")))
|
|
|
5863 |
|
|
|
5864 |
){
|
|
|
5865 |
// use get and cache a xpath runner for this selector
|
|
|
5866 |
return getXPathFunc(query);
|
|
|
5867 |
}
|
|
|
5868 |
}
|
|
|
5869 |
|
|
|
5870 |
// fallthrough
|
|
|
5871 |
return getStepQueryFunc(query);
|
|
|
5872 |
} : getStepQueryFunc
|
|
|
5873 |
);
|
|
|
5874 |
// uncomment to disable XPath for testing and tuning the DOM path
|
|
|
5875 |
// _getQueryFunc = getStepQueryFunc;
|
|
|
5876 |
|
|
|
5877 |
// FIXME: we've got problems w/ the NodeList query()/filter() functions if we go XPath for everything
|
|
|
5878 |
|
|
|
5879 |
// uncomment to disable DOM queries for testing and tuning XPath
|
|
|
5880 |
// _getQueryFunc = getXPathFunc;
|
|
|
5881 |
|
|
|
5882 |
// this is the primary caching for full-query results. The query dispatcher
|
|
|
5883 |
// functions are generated here and then pickled for hash lookup in the
|
|
|
5884 |
// future
|
|
|
5885 |
var getQueryFunc = function(query){
|
|
|
5886 |
// return a cached version if one is available
|
|
|
5887 |
if(_queryFuncCache[query]){ return _queryFuncCache[query]; }
|
|
|
5888 |
if(0 > query.indexOf(",")){
|
|
|
5889 |
// if it's not a compound query (e.g., ".foo, .bar"), cache and return a dispatcher
|
|
|
5890 |
return _queryFuncCache[query] = _getQueryFunc(query);
|
|
|
5891 |
}else{
|
|
|
5892 |
// if it's a complex query, break it up into it's constituent parts
|
|
|
5893 |
// and return a dispatcher that will merge the parts when run
|
|
|
5894 |
|
|
|
5895 |
// var parts = query.split(", ");
|
|
|
5896 |
var parts = query.split(/\s*,\s*/);
|
|
|
5897 |
var tf = function(root){
|
|
|
5898 |
var pindex = 0; // avoid array alloc for every invocation
|
|
|
5899 |
var ret = [];
|
|
|
5900 |
var tp;
|
|
|
5901 |
while(tp = parts[pindex++]){
|
|
|
5902 |
ret = ret.concat(_getQueryFunc(tp, tp.indexOf(" "))(root));
|
|
|
5903 |
}
|
|
|
5904 |
return ret;
|
|
|
5905 |
}
|
|
|
5906 |
// ...cache and return
|
|
|
5907 |
return _queryFuncCache[query] = tf;
|
|
|
5908 |
}
|
|
|
5909 |
}
|
|
|
5910 |
|
|
|
5911 |
// FIXME:
|
|
|
5912 |
// Dean's new Base2 uses a system whereby queries themselves note if
|
|
|
5913 |
// they'll need duplicate filtering. We need to get on that plan!!
|
|
|
5914 |
|
|
|
5915 |
// attempt to efficiently determine if an item in a list is a dupe,
|
|
|
5916 |
// returning a list of "uniques", hopefully in doucment order
|
|
|
5917 |
var _zipIdx = 0;
|
|
|
5918 |
var _zip = function(arr){
|
|
|
5919 |
if(arr && arr.nozip){ return d.NodeList._wrap(arr); }
|
|
|
5920 |
var ret = new d.NodeList();
|
|
|
5921 |
if(!arr){ return ret; }
|
|
|
5922 |
if(arr[0]){
|
|
|
5923 |
ret.push(arr[0]);
|
|
|
5924 |
}
|
|
|
5925 |
if(arr.length < 2){ return ret; }
|
|
|
5926 |
_zipIdx++;
|
|
|
5927 |
arr[0]["_zipIdx"] = _zipIdx;
|
|
|
5928 |
for(var x=1, te; te = arr[x]; x++){
|
|
|
5929 |
if(arr[x]["_zipIdx"] != _zipIdx){
|
|
|
5930 |
ret.push(te);
|
|
|
5931 |
}
|
|
|
5932 |
te["_zipIdx"] = _zipIdx;
|
|
|
5933 |
}
|
|
|
5934 |
// FIXME: should we consider stripping these properties?
|
|
|
5935 |
return ret;
|
|
|
5936 |
}
|
|
|
5937 |
|
|
|
5938 |
// the main exectuor
|
|
|
5939 |
d.query = function(query, root){
|
|
|
5940 |
// summary:
|
|
|
5941 |
// returns nodes which match the given CSS3 selector, searching the
|
|
|
5942 |
// entire document by default but optionally taking a node to scope
|
|
|
5943 |
// the search by. Returns an instance of dojo.NodeList.
|
|
|
5944 |
// description:
|
|
|
5945 |
// dojo.query() is the swiss army knife of DOM node manipulation in
|
|
|
5946 |
// Dojo. Much like Prototype's "$$" (bling-bling) function or JQuery's
|
|
|
5947 |
// "$" function, dojo.query provides robust, high-performance
|
|
|
5948 |
// CSS-based node selector support with the option of scoping searches
|
|
|
5949 |
// to a particular sub-tree of a document.
|
|
|
5950 |
//
|
|
|
5951 |
// Supported Selectors:
|
|
|
5952 |
// --------------------
|
|
|
5953 |
//
|
|
|
5954 |
// dojo.query() supports a rich set of CSS3 selectors, including:
|
|
|
5955 |
//
|
|
|
5956 |
// * class selectors (e.g., ".foo")
|
|
|
5957 |
// * node type selectors like "span"
|
|
|
5958 |
// * " " descendant selectors
|
|
|
5959 |
// * ">" child element selectors
|
|
|
5960 |
// * "#foo" style ID selectors
|
|
|
5961 |
// * "*" universal selector
|
|
|
5962 |
// * attribute queries:
|
|
|
5963 |
// * "[foo]" attribute presence selector
|
|
|
5964 |
// * "[foo='bar']" attribute value exact match
|
|
|
5965 |
// * "[foo~='bar']" attribute value list item match
|
|
|
5966 |
// * "[foo^='bar']" attribute start match
|
|
|
5967 |
// * "[foo$='bar']" attribute end match
|
|
|
5968 |
// * "[foo*='bar']" attribute substring match
|
|
|
5969 |
// * ":first-child", ":last-child" positional selectors
|
|
|
5970 |
// * ":nth-child(n)", ":nth-child(2n+1)" style positional calculations
|
|
|
5971 |
// * ":nth-child(even)", ":nth-child(odd)" positional selectors
|
|
|
5972 |
// * ":not(...)" negation pseudo selectors
|
|
|
5973 |
//
|
|
|
5974 |
// Any legal combination of those selector types as per the CSS 3 sepc
|
|
|
5975 |
// will work with dojo.query(), including compound selectors (","
|
|
|
5976 |
// delimited). Very complex and useful searches can be constructed
|
|
|
5977 |
// with this palette of selectors and when combined with functions for
|
|
|
5978 |
// maniplation presented by dojo.NodeList, many types of DOM
|
|
|
5979 |
// manipulation operations become very straightforward.
|
|
|
5980 |
//
|
|
|
5981 |
// Unsupported Selectors:
|
|
|
5982 |
// --------------------
|
|
|
5983 |
//
|
|
|
5984 |
// While dojo.query handles many CSS3 selectors, some fall outside of
|
|
|
5985 |
// what's resaonable for a programmatic node querying engine to
|
|
|
5986 |
// handle. Currently unsupported selectors include:
|
|
|
5987 |
//
|
|
|
5988 |
// * namespace-differentiated selectors of any form
|
|
|
5989 |
// * "~", the immediately preceeded-by sibling selector
|
|
|
5990 |
// * "+", the preceeded-by sibling selector
|
|
|
5991 |
// * all "::" pseduo-element selectors
|
|
|
5992 |
// * certain pseduo-selectors which don't get a lot of day-to-day use:
|
|
|
5993 |
// * :root, :lang(), :target, :focus
|
|
|
5994 |
// * all visual and state selectors:
|
|
|
5995 |
// * :root, :active, :hover, :visisted, :link, :enabled, :disabled, :checked
|
|
|
5996 |
// * :*-of-type pseudo selectors
|
|
|
5997 |
//
|
|
|
5998 |
// dojo.query and XML Documents:
|
|
|
5999 |
// -----------------------------
|
|
|
6000 |
// FIXME
|
|
|
6001 |
//
|
|
|
6002 |
// query: String
|
|
|
6003 |
// The CSS3 expression to match against. For details on the syntax of
|
|
|
6004 |
// CSS3 selectors, see:
|
|
|
6005 |
// http://www.w3.org/TR/css3-selectors/#selectors
|
|
|
6006 |
// root: String|DOMNode?
|
|
|
6007 |
// A node (or string ID of a node) to scope the search from. Optional.
|
|
|
6008 |
// returns:
|
|
|
6009 |
// An instance of dojo.NodeList. Many methods are available on
|
|
|
6010 |
// NodeLists for searching, iterating, manipulating, and handling
|
|
|
6011 |
// events on the matched nodes in the returned list.
|
|
|
6012 |
|
|
|
6013 |
// return is always an array
|
|
|
6014 |
// NOTE: elementsById is not currently supported
|
|
|
6015 |
// NOTE: ignores xpath-ish queries for now
|
|
|
6016 |
if(query.constructor == d.NodeList){
|
|
|
6017 |
return query;
|
|
|
6018 |
}
|
|
|
6019 |
if(!d.isString(query)){
|
|
|
6020 |
return new d.NodeList(query); // dojo.NodeList
|
|
|
6021 |
}
|
|
|
6022 |
if(d.isString(root)){
|
|
|
6023 |
root = d.byId(root);
|
|
|
6024 |
}
|
|
|
6025 |
|
|
|
6026 |
// FIXME: should support more methods on the return than the stock array.
|
|
|
6027 |
return _zip(getQueryFunc(query)(root||d.doc));
|
|
|
6028 |
}
|
|
|
6029 |
|
|
|
6030 |
/*
|
|
|
6031 |
// exposing these was a mistake
|
|
|
6032 |
d.query.attrs = attrs;
|
|
|
6033 |
d.query.pseudos = pseudos;
|
|
|
6034 |
*/
|
|
|
6035 |
|
|
|
6036 |
// one-off function for filtering a NodeList based on a simple selector
|
|
|
6037 |
d._filterQueryResult = function(nodeList, simpleFilter){
|
|
|
6038 |
var tnl = new d.NodeList();
|
|
|
6039 |
var ff = (simpleFilter) ? getFilterFunc(getQueryParts(simpleFilter)[0]) : function(){ return true; };
|
|
|
6040 |
for(var x=0, te; te = nodeList[x]; x++){
|
|
|
6041 |
if(ff(te)){ tnl.push(te); }
|
|
|
6042 |
}
|
|
|
6043 |
return tnl;
|
|
|
6044 |
}
|
|
|
6045 |
})();
|
|
|
6046 |
|
|
|
6047 |
}
|
|
|
6048 |
|
|
|
6049 |
if(!dojo._hasResource["dojo._base.xhr"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
6050 |
dojo._hasResource["dojo._base.xhr"] = true;
|
|
|
6051 |
dojo.provide("dojo._base.xhr");
|
|
|
6052 |
|
|
|
6053 |
|
|
|
6054 |
|
|
|
6055 |
|
|
|
6056 |
|
|
|
6057 |
(function(){
|
|
|
6058 |
var _d = dojo;
|
|
|
6059 |
function setValue(/*Object*/obj, /*String*/name, /*String*/value){
|
|
|
6060 |
//summary:
|
|
|
6061 |
// For the nameed property in object, set the value. If a value
|
|
|
6062 |
// already exists and it is a string, convert the value to be an
|
|
|
6063 |
// array of values.
|
|
|
6064 |
var val = obj[name];
|
|
|
6065 |
if(_d.isString(val)){
|
|
|
6066 |
obj[name] = [val, value];
|
|
|
6067 |
}else if(_d.isArray(val)){
|
|
|
6068 |
val.push(value);
|
|
|
6069 |
}else{
|
|
|
6070 |
obj[name] = value;
|
|
|
6071 |
}
|
|
|
6072 |
}
|
|
|
6073 |
|
|
|
6074 |
dojo.formToObject = function(/*DOMNode||String*/ formNode){
|
|
|
6075 |
// summary:
|
|
|
6076 |
// dojo.formToObject returns the values encoded in an HTML form as
|
|
|
6077 |
// string properties in an object which it then returns. Disabled form
|
|
|
6078 |
// elements, buttons, and other non-value form elements are skipped.
|
|
|
6079 |
// Multi-select elements are returned as an array of string values.
|
|
|
6080 |
// description:
|
|
|
6081 |
// This form:
|
|
|
6082 |
//
|
|
|
6083 |
// <form id="test_form">
|
|
|
6084 |
// <input type="text" name="blah" value="blah">
|
|
|
6085 |
// <input type="text" name="no_value" value="blah" disabled>
|
|
|
6086 |
// <input type="button" name="no_value2" value="blah">
|
|
|
6087 |
// <select type="select" multiple name="multi" size="5">
|
|
|
6088 |
// <option value="blah">blah</option>
|
|
|
6089 |
// <option value="thud" selected>thud</option>
|
|
|
6090 |
// <option value="thonk" selected>thonk</option>
|
|
|
6091 |
// </select>
|
|
|
6092 |
// </form>
|
|
|
6093 |
//
|
|
|
6094 |
// yields this object structure as the result of a call to
|
|
|
6095 |
// formToObject():
|
|
|
6096 |
//
|
|
|
6097 |
// {
|
|
|
6098 |
// blah: "blah",
|
|
|
6099 |
// multi: [
|
|
|
6100 |
// "thud",
|
|
|
6101 |
// "thonk"
|
|
|
6102 |
// ]
|
|
|
6103 |
// };
|
|
|
6104 |
|
|
|
6105 |
var ret = {};
|
|
|
6106 |
var iq = "input:not([type=file]):not([type=submit]):not([type=image]):not([type=reset]):not([type=button]), select, textarea";
|
|
|
6107 |
_d.query(iq, formNode).filter(function(node){
|
|
|
6108 |
return (!node.disabled);
|
|
|
6109 |
}).forEach(function(item){
|
|
|
6110 |
var _in = item.name;
|
|
|
6111 |
var type = (item.type||"").toLowerCase();
|
|
|
6112 |
if(type == "radio" || type == "checkbox"){
|
|
|
6113 |
if(item.checked){ setValue(ret, _in, item.value); }
|
|
|
6114 |
}else if(item.multiple){
|
|
|
6115 |
ret[_in] = [];
|
|
|
6116 |
_d.query("option", item).forEach(function(opt){
|
|
|
6117 |
if(opt.selected){
|
|
|
6118 |
setValue(ret, _in, opt.value);
|
|
|
6119 |
}
|
|
|
6120 |
});
|
|
|
6121 |
}else{
|
|
|
6122 |
setValue(ret, _in, item.value);
|
|
|
6123 |
if(type == "image"){
|
|
|
6124 |
ret[_in+".x"] = ret[_in+".y"] = ret[_in].x = ret[_in].y = 0;
|
|
|
6125 |
}
|
|
|
6126 |
}
|
|
|
6127 |
});
|
|
|
6128 |
return ret; // Object
|
|
|
6129 |
}
|
|
|
6130 |
|
|
|
6131 |
dojo.objectToQuery = function(/*Object*/ map){
|
|
|
6132 |
// summary:
|
|
|
6133 |
// takes a key/value mapping object and returns a string representing
|
|
|
6134 |
// a URL-encoded version of that object.
|
|
|
6135 |
// example:
|
|
|
6136 |
// this object:
|
|
|
6137 |
//
|
|
|
6138 |
// | {
|
|
|
6139 |
// | blah: "blah",
|
|
|
6140 |
// | multi: [
|
|
|
6141 |
// | "thud",
|
|
|
6142 |
// | "thonk"
|
|
|
6143 |
// | ]
|
|
|
6144 |
// | };
|
|
|
6145 |
//
|
|
|
6146 |
// yeilds the following query string:
|
|
|
6147 |
//
|
|
|
6148 |
// | "blah=blah&multi=thud&multi=thonk"
|
|
|
6149 |
|
|
|
6150 |
|
|
|
6151 |
// FIXME: need to implement encodeAscii!!
|
|
|
6152 |
var ec = encodeURIComponent;
|
|
|
6153 |
var ret = "";
|
|
|
6154 |
var backstop = {};
|
|
|
6155 |
for(var x in map){
|
|
|
6156 |
if(map[x] != backstop[x]){
|
|
|
6157 |
if(_d.isArray(map[x])){
|
|
|
6158 |
for(var y=0; y<map[x].length; y++){
|
|
|
6159 |
ret += ec(x) + "=" + ec(map[x][y]) + "&";
|
|
|
6160 |
}
|
|
|
6161 |
}else{
|
|
|
6162 |
ret += ec(x) + "=" + ec(map[x]) + "&";
|
|
|
6163 |
}
|
|
|
6164 |
}
|
|
|
6165 |
}
|
|
|
6166 |
if(ret.length && ret.charAt(ret.length-1) == "&"){
|
|
|
6167 |
ret = ret.substr(0, ret.length-1);
|
|
|
6168 |
}
|
|
|
6169 |
return ret; // String
|
|
|
6170 |
}
|
|
|
6171 |
|
|
|
6172 |
dojo.formToQuery = function(/*DOMNode||String*/ formNode){
|
|
|
6173 |
// summary:
|
|
|
6174 |
// return URL-encoded string representing the form passed as either a
|
|
|
6175 |
// node or string ID identifying the form to serialize
|
|
|
6176 |
return _d.objectToQuery(_d.formToObject(formNode)); // String
|
|
|
6177 |
}
|
|
|
6178 |
|
|
|
6179 |
dojo.formToJson = function(/*DOMNode||String*/ formNode, /*Boolean?*/prettyPrint){
|
|
|
6180 |
// summary:
|
|
|
6181 |
// return a serialized JSON string from a form node or string
|
|
|
6182 |
// ID identifying the form to serialize
|
|
|
6183 |
return _d.toJson(_d.formToObject(formNode), prettyPrint); // String
|
|
|
6184 |
}
|
|
|
6185 |
|
|
|
6186 |
dojo.queryToObject = function(/*String*/ str){
|
|
|
6187 |
// summary:
|
|
|
6188 |
// returns an object representing a de-serialized query section of a
|
|
|
6189 |
// URL. Query keys with multiple values are returned in an array.
|
|
|
6190 |
// description:
|
|
|
6191 |
// This string:
|
|
|
6192 |
//
|
|
|
6193 |
// "foo=bar&foo=baz&thinger=%20spaces%20=blah&zonk=blarg&"
|
|
|
6194 |
//
|
|
|
6195 |
// returns this object structure:
|
|
|
6196 |
//
|
|
|
6197 |
// {
|
|
|
6198 |
// foo: [ "bar", "baz" ],
|
|
|
6199 |
// thinger: " spaces =blah",
|
|
|
6200 |
// zonk: "blarg"
|
|
|
6201 |
// }
|
|
|
6202 |
//
|
|
|
6203 |
// Note that spaces and other urlencoded entities are correctly
|
|
|
6204 |
// handled.
|
|
|
6205 |
|
|
|
6206 |
// FIXME: should we grab the URL string if we're not passed one?
|
|
|
6207 |
var ret = {};
|
|
|
6208 |
var qp = str.split("&");
|
|
|
6209 |
var dc = decodeURIComponent;
|
|
|
6210 |
_d.forEach(qp, function(item){
|
|
|
6211 |
if(item.length){
|
|
|
6212 |
var parts = item.split("=");
|
|
|
6213 |
var name = dc(parts.shift());
|
|
|
6214 |
var val = dc(parts.join("="));
|
|
|
6215 |
if(_d.isString(ret[name])){
|
|
|
6216 |
ret[name] = [ret[name]];
|
|
|
6217 |
}
|
|
|
6218 |
if(_d.isArray(ret[name])){
|
|
|
6219 |
ret[name].push(val);
|
|
|
6220 |
}else{
|
|
|
6221 |
ret[name] = val;
|
|
|
6222 |
}
|
|
|
6223 |
}
|
|
|
6224 |
});
|
|
|
6225 |
return ret; // Object
|
|
|
6226 |
}
|
|
|
6227 |
|
|
|
6228 |
/*
|
|
|
6229 |
from refactor.txt:
|
|
|
6230 |
|
|
|
6231 |
all bind() replacement APIs take the following argument structure:
|
|
|
6232 |
|
|
|
6233 |
{
|
|
|
6234 |
url: "blah.html",
|
|
|
6235 |
|
|
|
6236 |
// all below are optional, but must be supported in some form by
|
|
|
6237 |
// every IO API
|
|
|
6238 |
timeout: 1000, // milliseconds
|
|
|
6239 |
handleAs: "text", // replaces the always-wrong "mimetype"
|
|
|
6240 |
content: {
|
|
|
6241 |
key: "value"
|
|
|
6242 |
},
|
|
|
6243 |
|
|
|
6244 |
// browser-specific, MAY be unsupported
|
|
|
6245 |
sync: true, // defaults to false
|
|
|
6246 |
form: dojo.byId("someForm")
|
|
|
6247 |
}
|
|
|
6248 |
*/
|
|
|
6249 |
|
|
|
6250 |
// need to block async callbacks from snatching this thread as the result
|
|
|
6251 |
// of an async callback might call another sync XHR, this hangs khtml forever
|
|
|
6252 |
// must checked by watchInFlight()
|
|
|
6253 |
|
|
|
6254 |
dojo._blockAsync = false;
|
|
|
6255 |
|
|
|
6256 |
dojo._contentHandlers = {
|
|
|
6257 |
"text": function(xhr){ return xhr.responseText; },
|
|
|
6258 |
"json": function(xhr){
|
|
|
6259 |
if(!djConfig.usePlainJson){
|
|
|
6260 |
console.debug("Consider using mimetype:text/json-comment-filtered"
|
|
|
6261 |
+ " to avoid potential security issues with JSON endpoints"
|
|
|
6262 |
+ " (use djConfig.usePlainJson=true to turn off this message)");
|
|
|
6263 |
}
|
|
|
6264 |
return _d.fromJson(xhr.responseText);
|
|
|
6265 |
},
|
|
|
6266 |
"json-comment-filtered": function(xhr){
|
|
|
6267 |
// NOTE: we provide the json-comment-filtered option as one solution to
|
|
|
6268 |
// the "JavaScript Hijacking" issue noted by Fortify and others. It is
|
|
|
6269 |
// not appropriate for all circumstances.
|
|
|
6270 |
|
|
|
6271 |
var value = xhr.responseText;
|
|
|
6272 |
var cStartIdx = value.indexOf("\/*");
|
|
|
6273 |
var cEndIdx = value.lastIndexOf("*\/");
|
|
|
6274 |
if(cStartIdx == -1 || cEndIdx == -1){
|
|
|
6275 |
throw new Error("JSON was not comment filtered");
|
|
|
6276 |
}
|
|
|
6277 |
return _d.fromJson(value.substring(cStartIdx+2, cEndIdx));
|
|
|
6278 |
},
|
|
|
6279 |
"javascript": function(xhr){
|
|
|
6280 |
// FIXME: try Moz and IE specific eval variants?
|
|
|
6281 |
return _d.eval(xhr.responseText);
|
|
|
6282 |
},
|
|
|
6283 |
"xml": function(xhr){
|
|
|
6284 |
if(_d.isIE && !xhr.responseXML){
|
|
|
6285 |
_d.forEach(["MSXML2", "Microsoft", "MSXML", "MSXML3"], function(i){
|
|
|
6286 |
try{
|
|
|
6287 |
var doc = new ActiveXObject(prefixes[i]+".XMLDOM");
|
|
|
6288 |
doc.async = false;
|
|
|
6289 |
doc.loadXML(xhr.responseText);
|
|
|
6290 |
return doc; // DOMDocument
|
|
|
6291 |
}catch(e){ /* squelch */ };
|
|
|
6292 |
});
|
|
|
6293 |
}else{
|
|
|
6294 |
return xhr.responseXML;
|
|
|
6295 |
}
|
|
|
6296 |
}
|
|
|
6297 |
};
|
|
|
6298 |
|
|
|
6299 |
dojo._contentHandlers["json-comment-optional"] = function(xhr){
|
|
|
6300 |
var handlers = _d._contentHandlers;
|
|
|
6301 |
try{
|
|
|
6302 |
return handlers["json-comment-filtered"](xhr);
|
|
|
6303 |
}catch(e){
|
|
|
6304 |
return handlers["json"](xhr);
|
|
|
6305 |
}
|
|
|
6306 |
};
|
|
|
6307 |
|
|
|
6308 |
/*=====
|
|
|
6309 |
dojo.__ioArgs = function(kwArgs){
|
|
|
6310 |
// url: String
|
|
|
6311 |
// URL to server endpoint.
|
|
|
6312 |
// content: Object?
|
|
|
6313 |
// Contains properties with string values. These
|
|
|
6314 |
// properties will be serialized as name1=value2 and
|
|
|
6315 |
// passed in the request.
|
|
|
6316 |
// timeout: Integer?
|
|
|
6317 |
// Milliseconds to wait for the response. If this time
|
|
|
6318 |
// passes, the then error callbacks are called.
|
|
|
6319 |
// form: DOMNode?
|
|
|
6320 |
// DOM node for a form. Used to extract the form values
|
|
|
6321 |
// and send to the server.
|
|
|
6322 |
// preventCache: Boolean?
|
|
|
6323 |
// Default is false. If true, then a
|
|
|
6324 |
// "dojo.preventCache" parameter is sent in the request
|
|
|
6325 |
// with a value that changes with each request
|
|
|
6326 |
// (timestamp). Useful only with GET-type requests.
|
|
|
6327 |
// handleAs: String?
|
|
|
6328 |
// Acceptable values depend on the type of IO
|
|
|
6329 |
// transport (see specific IO calls for more information).
|
|
|
6330 |
// load: Function?
|
|
|
6331 |
// function(response, ioArgs){}. response is an Object, ioArgs
|
|
|
6332 |
// is of type dojo.__ioCallbackArgs. The load function will be
|
|
|
6333 |
// called on a successful response.
|
|
|
6334 |
// error: Function?
|
|
|
6335 |
// function(response, ioArgs){}. response is an Object, ioArgs
|
|
|
6336 |
// is of type dojo.__ioCallbackArgs. The error function will
|
|
|
6337 |
// be called in an error case.
|
|
|
6338 |
// handle: Function
|
|
|
6339 |
// function(response, ioArgs){}. response is an Object, ioArgs
|
|
|
6340 |
// is of type dojo.__ioCallbackArgs. The handle function will
|
|
|
6341 |
// be called in either the successful or error case. For
|
|
|
6342 |
// the load, error and handle functions, the ioArgs object
|
|
|
6343 |
// will contain the following properties:
|
|
|
6344 |
}
|
|
|
6345 |
=====*/
|
|
|
6346 |
|
|
|
6347 |
/*=====
|
|
|
6348 |
dojo.__ioCallbackArgs = function(kwArgs){
|
|
|
6349 |
// args: Object
|
|
|
6350 |
// the original object argument to the IO call.
|
|
|
6351 |
// xhr: XMLHttpRequest
|
|
|
6352 |
// For XMLHttpRequest calls only, the
|
|
|
6353 |
// XMLHttpRequest object that was used for the
|
|
|
6354 |
// request.
|
|
|
6355 |
// url: String
|
|
|
6356 |
// The final URL used for the call. Many times it
|
|
|
6357 |
// will be different than the original args.url
|
|
|
6358 |
// value.
|
|
|
6359 |
// query: String
|
|
|
6360 |
// For non-GET requests, the
|
|
|
6361 |
// name1=value1&name2=value2 parameters sent up in
|
|
|
6362 |
// the request.
|
|
|
6363 |
// handleAs: String
|
|
|
6364 |
// The final indicator on how the response will be
|
|
|
6365 |
// handled.
|
|
|
6366 |
// id: String
|
|
|
6367 |
// For dojo.io.script calls only, the internal
|
|
|
6368 |
// script ID used for the request.
|
|
|
6369 |
// canDelete: Boolean
|
|
|
6370 |
// For dojo.io.script calls only, indicates
|
|
|
6371 |
// whether the script tag that represents the
|
|
|
6372 |
// request can be deleted after callbacks have
|
|
|
6373 |
// been called. Used internally to know when
|
|
|
6374 |
// cleanup can happen on JSONP-type requests.
|
|
|
6375 |
// json: Object
|
|
|
6376 |
// For dojo.io.script calls only: holds the JSON
|
|
|
6377 |
// response for JSONP-type requests. Used
|
|
|
6378 |
// internally to hold on to the JSON responses.
|
|
|
6379 |
// You should not need to access it directly --
|
|
|
6380 |
// the same object should be passed to the success
|
|
|
6381 |
// callbacks directly.
|
|
|
6382 |
}
|
|
|
6383 |
=====*/
|
|
|
6384 |
|
|
|
6385 |
|
|
|
6386 |
|
|
|
6387 |
dojo._ioSetArgs = function(/*dojo.__ioArgs*/args,
|
|
|
6388 |
/*Function*/canceller,
|
|
|
6389 |
/*Function*/okHandler,
|
|
|
6390 |
/*Function*/errHandler){
|
|
|
6391 |
// summary:
|
|
|
6392 |
// sets up the Deferred and ioArgs property on the Deferred so it
|
|
|
6393 |
// can be used in an io call.
|
|
|
6394 |
// args:
|
|
|
6395 |
// The args object passed into the public io call. Recognized properties on
|
|
|
6396 |
// the args object are:
|
|
|
6397 |
// canceller:
|
|
|
6398 |
// The canceller function used for the Deferred object. The function
|
|
|
6399 |
// will receive one argument, the Deferred object that is related to the
|
|
|
6400 |
// canceller.
|
|
|
6401 |
// okHandler:
|
|
|
6402 |
// The first OK callback to be registered with Deferred. It has the opportunity
|
|
|
6403 |
// to transform the OK response. It will receive one argument -- the Deferred
|
|
|
6404 |
// object returned from this function.
|
|
|
6405 |
// errHandler:
|
|
|
6406 |
// The first error callback to be registered with Deferred. It has the opportunity
|
|
|
6407 |
// to do cleanup on an error. It will receive two arguments: error (the
|
|
|
6408 |
// Error object) and dfd, the Deferred object returned from this function.
|
|
|
6409 |
|
|
|
6410 |
var ioArgs = {args: args, url: args.url};
|
|
|
6411 |
|
|
|
6412 |
//Get values from form if requestd.
|
|
|
6413 |
var formObject = null;
|
|
|
6414 |
if(args.form){
|
|
|
6415 |
var form = _d.byId(args.form);
|
|
|
6416 |
//IE requires going through getAttributeNode instead of just getAttribute in some form cases,
|
|
|
6417 |
//so use it for all. See #2844
|
|
|
6418 |
var actnNode = form.getAttributeNode("action");
|
|
|
6419 |
ioArgs.url = ioArgs.url || (actnNode ? actnNode.value : null);
|
|
|
6420 |
formObject = _d.formToObject(form);
|
|
|
6421 |
}
|
|
|
6422 |
|
|
|
6423 |
// set up the query params
|
|
|
6424 |
var miArgs = [{}];
|
|
|
6425 |
|
|
|
6426 |
if(formObject){
|
|
|
6427 |
// potentially over-ride url-provided params w/ form values
|
|
|
6428 |
miArgs.push(formObject);
|
|
|
6429 |
}
|
|
|
6430 |
if(args.content){
|
|
|
6431 |
// stuff in content over-rides what's set by form
|
|
|
6432 |
miArgs.push(args.content);
|
|
|
6433 |
}
|
|
|
6434 |
if(args.preventCache){
|
|
|
6435 |
miArgs.push({"dojo.preventCache": new Date().valueOf()});
|
|
|
6436 |
}
|
|
|
6437 |
ioArgs.query = _d.objectToQuery(_d.mixin.apply(null, miArgs));
|
|
|
6438 |
|
|
|
6439 |
// .. and the real work of getting the deferred in order, etc.
|
|
|
6440 |
ioArgs.handleAs = args.handleAs || "text";
|
|
|
6441 |
var d = new _d.Deferred(canceller);
|
|
|
6442 |
d.addCallbacks(okHandler, function(error){
|
|
|
6443 |
return errHandler(error, d);
|
|
|
6444 |
});
|
|
|
6445 |
|
|
|
6446 |
//Support specifying load, error and handle callback functions from the args.
|
|
|
6447 |
//For those callbacks, the "this" object will be the args object.
|
|
|
6448 |
//The callbacks will get the deferred result value as the
|
|
|
6449 |
//first argument and the ioArgs object as the second argument.
|
|
|
6450 |
var ld = args.load;
|
|
|
6451 |
if(ld && _d.isFunction(ld)){
|
|
|
6452 |
d.addCallback(function(value){
|
|
|
6453 |
return ld.call(args, value, ioArgs);
|
|
|
6454 |
});
|
|
|
6455 |
}
|
|
|
6456 |
var err = args.error;
|
|
|
6457 |
if(err && _d.isFunction(err)){
|
|
|
6458 |
d.addErrback(function(value){
|
|
|
6459 |
return err.call(args, value, ioArgs);
|
|
|
6460 |
});
|
|
|
6461 |
}
|
|
|
6462 |
var handle = args.handle;
|
|
|
6463 |
if(handle && _d.isFunction(handle)){
|
|
|
6464 |
d.addBoth(function(value){
|
|
|
6465 |
return handle.call(args, value, ioArgs);
|
|
|
6466 |
});
|
|
|
6467 |
}
|
|
|
6468 |
|
|
|
6469 |
d.ioArgs = ioArgs;
|
|
|
6470 |
|
|
|
6471 |
// FIXME: need to wire up the xhr object's abort method to something
|
|
|
6472 |
// analagous in the Deferred
|
|
|
6473 |
return d;
|
|
|
6474 |
}
|
|
|
6475 |
|
|
|
6476 |
var _deferredCancel = function(/*Deferred*/dfd){
|
|
|
6477 |
//summary: canceller function for dojo._ioSetArgs call.
|
|
|
6478 |
|
|
|
6479 |
dfd.canceled = true;
|
|
|
6480 |
var xhr = dfd.ioArgs.xhr;
|
|
|
6481 |
var _at = (typeof xhr.abort);
|
|
|
6482 |
if((_at == "function")||(_at == "unknown")){
|
|
|
6483 |
xhr.abort();
|
|
|
6484 |
}
|
|
|
6485 |
var err = new Error("xhr cancelled");
|
|
|
6486 |
err.dojoType = "cancel";
|
|
|
6487 |
return err;
|
|
|
6488 |
}
|
|
|
6489 |
var _deferredOk = function(/*Deferred*/dfd){
|
|
|
6490 |
//summary: okHandler function for dojo._ioSetArgs call.
|
|
|
6491 |
|
|
|
6492 |
return _d._contentHandlers[dfd.ioArgs.handleAs](dfd.ioArgs.xhr);
|
|
|
6493 |
}
|
|
|
6494 |
var _deferError = function(/*Error*/error, /*Deferred*/dfd){
|
|
|
6495 |
//summary: errHandler function for dojo._ioSetArgs call.
|
|
|
6496 |
|
|
|
6497 |
// console.debug("xhr error in:", dfd.ioArgs.xhr);
|
|
|
6498 |
console.debug(error);
|
|
|
6499 |
return error;
|
|
|
6500 |
}
|
|
|
6501 |
|
|
|
6502 |
var _makeXhrDeferred = function(/*dojo.__xhrArgs*/args){
|
|
|
6503 |
//summary: makes the Deferred object for this xhr request.
|
|
|
6504 |
var dfd = _d._ioSetArgs(args, _deferredCancel, _deferredOk, _deferError);
|
|
|
6505 |
//Pass the args to _xhrObj, to allow xhr iframe proxy interceptions.
|
|
|
6506 |
dfd.ioArgs.xhr = _d._xhrObj(dfd.ioArgs.args);
|
|
|
6507 |
return dfd;
|
|
|
6508 |
}
|
|
|
6509 |
|
|
|
6510 |
// avoid setting a timer per request. It degrades performance on IE
|
|
|
6511 |
// something fierece if we don't use unified loops.
|
|
|
6512 |
var _inFlightIntvl = null;
|
|
|
6513 |
var _inFlight = [];
|
|
|
6514 |
var _watchInFlight = function(){
|
|
|
6515 |
//summary:
|
|
|
6516 |
// internal method that checks each inflight XMLHttpRequest to see
|
|
|
6517 |
// if it has completed or if the timeout situation applies.
|
|
|
6518 |
|
|
|
6519 |
var now = (new Date()).getTime();
|
|
|
6520 |
// make sure sync calls stay thread safe, if this callback is called
|
|
|
6521 |
// during a sync call and this results in another sync call before the
|
|
|
6522 |
// first sync call ends the browser hangs
|
|
|
6523 |
if(!_d._blockAsync){
|
|
|
6524 |
// we need manual loop because we often modify _inFlight (and therefore 'i') while iterating
|
|
|
6525 |
// note: the second clause is an assigment on purpose, lint may complain
|
|
|
6526 |
for(var i=0, tif; (i<_inFlight.length)&&(tif=_inFlight[i]); i++){
|
|
|
6527 |
var dfd = tif.dfd;
|
|
|
6528 |
try{
|
|
|
6529 |
if(!dfd || dfd.canceled || !tif.validCheck(dfd)){
|
|
|
6530 |
_inFlight.splice(i--, 1);
|
|
|
6531 |
}else if(tif.ioCheck(dfd)){
|
|
|
6532 |
_inFlight.splice(i--, 1);
|
|
|
6533 |
tif.resHandle(dfd);
|
|
|
6534 |
}else if(dfd.startTime){
|
|
|
6535 |
//did we timeout?
|
|
|
6536 |
if(dfd.startTime + (dfd.ioArgs.args.timeout||0) < now){
|
|
|
6537 |
_inFlight.splice(i--, 1);
|
|
|
6538 |
var err = new Error("timeout exceeded");
|
|
|
6539 |
err.dojoType = "timeout";
|
|
|
6540 |
dfd.errback(err);
|
|
|
6541 |
//Cancel the request so the io module can do appropriate cleanup.
|
|
|
6542 |
dfd.cancel();
|
|
|
6543 |
}
|
|
|
6544 |
}
|
|
|
6545 |
}catch(e){
|
|
|
6546 |
// FIXME: make sure we errback!
|
|
|
6547 |
console.debug(e);
|
|
|
6548 |
dfd.errback(new Error("_watchInFlightError!"));
|
|
|
6549 |
}
|
|
|
6550 |
}
|
|
|
6551 |
}
|
|
|
6552 |
|
|
|
6553 |
if(!_inFlight.length){
|
|
|
6554 |
clearInterval(_inFlightIntvl);
|
|
|
6555 |
_inFlightIntvl = null;
|
|
|
6556 |
return;
|
|
|
6557 |
}
|
|
|
6558 |
|
|
|
6559 |
}
|
|
|
6560 |
|
|
|
6561 |
dojo._ioCancelAll = function(){
|
|
|
6562 |
//summary: Cancels all pending IO requests, regardless of IO type
|
|
|
6563 |
//(xhr, script, iframe).
|
|
|
6564 |
try{
|
|
|
6565 |
_d.forEach(_inFlight, function(i){
|
|
|
6566 |
i.dfd.cancel();
|
|
|
6567 |
});
|
|
|
6568 |
}catch(e){/*squelch*/}
|
|
|
6569 |
}
|
|
|
6570 |
|
|
|
6571 |
//Automatically call cancel all io calls on unload
|
|
|
6572 |
//in IE for trac issue #2357.
|
|
|
6573 |
if(_d.isIE){
|
|
|
6574 |
_d.addOnUnload(_d._ioCancelAll);
|
|
|
6575 |
}
|
|
|
6576 |
|
|
|
6577 |
_d._ioWatch = function(/*Deferred*/dfd,
|
|
|
6578 |
/*Function*/validCheck,
|
|
|
6579 |
/*Function*/ioCheck,
|
|
|
6580 |
/*Function*/resHandle){
|
|
|
6581 |
//summary: watches the io request represented by dfd to see if it completes.
|
|
|
6582 |
//dfd:
|
|
|
6583 |
// The Deferred object to watch.
|
|
|
6584 |
//validCheck:
|
|
|
6585 |
// Function used to check if the IO request is still valid. Gets the dfd
|
|
|
6586 |
// object as its only argument.
|
|
|
6587 |
//ioCheck:
|
|
|
6588 |
// Function used to check if basic IO call worked. Gets the dfd
|
|
|
6589 |
// object as its only argument.
|
|
|
6590 |
//resHandle:
|
|
|
6591 |
// Function used to process response. Gets the dfd
|
|
|
6592 |
// object as its only argument.
|
|
|
6593 |
if(dfd.ioArgs.args.timeout){
|
|
|
6594 |
dfd.startTime = (new Date()).getTime();
|
|
|
6595 |
}
|
|
|
6596 |
_inFlight.push({dfd: dfd, validCheck: validCheck, ioCheck: ioCheck, resHandle: resHandle});
|
|
|
6597 |
if(!_inFlightIntvl){
|
|
|
6598 |
_inFlightIntvl = setInterval(_watchInFlight, 50);
|
|
|
6599 |
}
|
|
|
6600 |
_watchInFlight(); // handle sync requests
|
|
|
6601 |
}
|
|
|
6602 |
|
|
|
6603 |
var _defaultContentType = "application/x-www-form-urlencoded";
|
|
|
6604 |
|
|
|
6605 |
var _validCheck = function(/*Deferred*/dfd){
|
|
|
6606 |
return dfd.ioArgs.xhr.readyState; //boolean
|
|
|
6607 |
}
|
|
|
6608 |
var _ioCheck = function(/*Deferred*/dfd){
|
|
|
6609 |
return 4 == dfd.ioArgs.xhr.readyState; //boolean
|
|
|
6610 |
}
|
|
|
6611 |
var _resHandle = function(/*Deferred*/dfd){
|
|
|
6612 |
if(_d._isDocumentOk(dfd.ioArgs.xhr)){
|
|
|
6613 |
dfd.callback(dfd);
|
|
|
6614 |
}else{
|
|
|
6615 |
dfd.errback(new Error("bad http response code:" + dfd.ioArgs.xhr.status));
|
|
|
6616 |
}
|
|
|
6617 |
}
|
|
|
6618 |
|
|
|
6619 |
var _doIt = function(/*String*/type, /*Deferred*/dfd){
|
|
|
6620 |
// IE 6 is a steaming pile. It won't let you call apply() on the native function (xhr.open).
|
|
|
6621 |
// workaround for IE6's apply() "issues"
|
|
|
6622 |
var ioArgs = dfd.ioArgs;
|
|
|
6623 |
var args = ioArgs.args;
|
|
|
6624 |
ioArgs.xhr.open(type, ioArgs.url, args.sync !== true, args.user || undefined, args.password || undefined);
|
|
|
6625 |
if(args.headers){
|
|
|
6626 |
for(var hdr in args.headers){
|
|
|
6627 |
if(hdr.toLowerCase() === "content-type" && !args.contentType){
|
|
|
6628 |
args.contentType = args.headers[hdr];
|
|
|
6629 |
}else{
|
|
|
6630 |
ioArgs.xhr.setRequestHeader(hdr, args.headers[hdr]);
|
|
|
6631 |
}
|
|
|
6632 |
}
|
|
|
6633 |
}
|
|
|
6634 |
// FIXME: is this appropriate for all content types?
|
|
|
6635 |
ioArgs.xhr.setRequestHeader("Content-Type", (args.contentType||_defaultContentType));
|
|
|
6636 |
// FIXME: set other headers here!
|
|
|
6637 |
try{
|
|
|
6638 |
ioArgs.xhr.send(ioArgs.query);
|
|
|
6639 |
}catch(e){
|
|
|
6640 |
dfd.cancel();
|
|
|
6641 |
}
|
|
|
6642 |
_d._ioWatch(dfd, _validCheck, _ioCheck, _resHandle);
|
|
|
6643 |
return dfd; //Deferred
|
|
|
6644 |
}
|
|
|
6645 |
|
|
|
6646 |
dojo._ioAddQueryToUrl = function(/*dojo.__ioCallbackArgs*/ioArgs){
|
|
|
6647 |
//summary: Adds query params discovered by the io deferred construction to the URL.
|
|
|
6648 |
//Only use this for operations which are fundamentally GET-type operations.
|
|
|
6649 |
if(ioArgs.query.length){
|
|
|
6650 |
ioArgs.url += (ioArgs.url.indexOf("?") == -1 ? "?" : "&") + ioArgs.query;
|
|
|
6651 |
ioArgs.query = null;
|
|
|
6652 |
}
|
|
|
6653 |
}
|
|
|
6654 |
|
|
|
6655 |
/*=====
|
|
|
6656 |
dojo.__xhrArgs = function(kwArgs){
|
|
|
6657 |
// summary:
|
|
|
6658 |
// In addition to the properties listed for the dojo.__ioArgs type,
|
|
|
6659 |
// the following properties are allowed for dojo.xhr* methods.
|
|
|
6660 |
// handleAs:
|
|
|
6661 |
// String. Acceptable values are:
|
|
|
6662 |
// "text" (default)
|
|
|
6663 |
// "json"
|
|
|
6664 |
// "json-comment-optional"
|
|
|
6665 |
// "json-comment-filtered"
|
|
|
6666 |
// "javascript"
|
|
|
6667 |
// "xml"
|
|
|
6668 |
// sync:
|
|
|
6669 |
// Boolean. false is default. Indicates whether the request should
|
|
|
6670 |
// be a synchronous (blocking) request.
|
|
|
6671 |
// headers:
|
|
|
6672 |
// Object. Additional HTTP headers to send in the request.
|
|
|
6673 |
}
|
|
|
6674 |
=====*/
|
|
|
6675 |
|
|
|
6676 |
dojo.xhrGet = function(/*dojo.__xhrArgs*/ args){
|
|
|
6677 |
// summary:
|
|
|
6678 |
// Sends an HTTP GET request to the server.
|
|
|
6679 |
var dfd = _makeXhrDeferred(args);
|
|
|
6680 |
_d._ioAddQueryToUrl(dfd.ioArgs);
|
|
|
6681 |
return _doIt("GET", dfd); // dojo.Deferred
|
|
|
6682 |
}
|
|
|
6683 |
|
|
|
6684 |
dojo.xhrPost = function(/*dojo.__xhrArgs*/ args){
|
|
|
6685 |
//summary:
|
|
|
6686 |
// Sends an HTTP POST request to the server.
|
|
|
6687 |
return _doIt("POST", _makeXhrDeferred(args)); // dojo.Deferred
|
|
|
6688 |
}
|
|
|
6689 |
|
|
|
6690 |
dojo.rawXhrPost = function(/*dojo.__xhrArgs*/ args){
|
|
|
6691 |
// summary:
|
|
|
6692 |
// Sends an HTTP POST request to the server. In addtion to the properties
|
|
|
6693 |
// listed for the dojo.__xhrArgs type, the following property is allowed:
|
|
|
6694 |
// postData:
|
|
|
6695 |
// String. The raw data to send in the body of the POST request.
|
|
|
6696 |
var dfd = _makeXhrDeferred(args);
|
|
|
6697 |
dfd.ioArgs.query = args.postData;
|
|
|
6698 |
return _doIt("POST", dfd); // dojo.Deferred
|
|
|
6699 |
}
|
|
|
6700 |
|
|
|
6701 |
dojo.xhrPut = function(/*dojo.__xhrArgs*/ args){
|
|
|
6702 |
// summary:
|
|
|
6703 |
// Sends an HTTP PUT request to the server.
|
|
|
6704 |
return _doIt("PUT", _makeXhrDeferred(args)); // dojo.Deferred
|
|
|
6705 |
}
|
|
|
6706 |
|
|
|
6707 |
dojo.rawXhrPut = function(/*dojo.__xhrArgs*/ args){
|
|
|
6708 |
// summary:
|
|
|
6709 |
// Sends an HTTP PUT request to the server. In addtion to the properties
|
|
|
6710 |
// listed for the dojo.__xhrArgs type, the following property is allowed:
|
|
|
6711 |
// putData:
|
|
|
6712 |
// String. The raw data to send in the body of the PUT request.
|
|
|
6713 |
var dfd = _makeXhrDeferred(args);
|
|
|
6714 |
var ioArgs = dfd.ioArgs;
|
|
|
6715 |
if(args["putData"]){
|
|
|
6716 |
ioArgs.query = args.putData;
|
|
|
6717 |
args.putData = null;
|
|
|
6718 |
}
|
|
|
6719 |
return _doIt("PUT", dfd); // dojo.Deferred
|
|
|
6720 |
}
|
|
|
6721 |
|
|
|
6722 |
dojo.xhrDelete = function(/*dojo.__xhrArgs*/ args){
|
|
|
6723 |
// summary:
|
|
|
6724 |
// Sends an HTTP DELETE request to the server.
|
|
|
6725 |
var dfd = _makeXhrDeferred(args);
|
|
|
6726 |
_d._ioAddQueryToUrl(dfd.ioArgs);
|
|
|
6727 |
return _doIt("DELETE", dfd); // dojo.Deferred
|
|
|
6728 |
}
|
|
|
6729 |
|
|
|
6730 |
/*
|
|
|
6731 |
dojo.wrapForm = function(formNode){
|
|
|
6732 |
//summary:
|
|
|
6733 |
// A replacement for FormBind, but not implemented yet.
|
|
|
6734 |
|
|
|
6735 |
// FIXME: need to think harder about what extensions to this we might
|
|
|
6736 |
// want. What should we allow folks to do w/ this? What events to
|
|
|
6737 |
// set/send?
|
|
|
6738 |
throw new Error("dojo.wrapForm not yet implemented");
|
|
|
6739 |
}
|
|
|
6740 |
*/
|
|
|
6741 |
})();
|
|
|
6742 |
|
|
|
6743 |
}
|
|
|
6744 |
|
|
|
6745 |
if(!dojo._hasResource["dojo._base.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
6746 |
dojo._hasResource["dojo._base.fx"] = true;
|
|
|
6747 |
dojo.provide("dojo._base.fx");
|
|
|
6748 |
|
|
|
6749 |
|
|
|
6750 |
|
|
|
6751 |
|
|
|
6752 |
|
|
|
6753 |
|
|
|
6754 |
/*
|
|
|
6755 |
Animation losely package based on Dan Pupius' work, contributed under CLA:
|
|
|
6756 |
http://pupius.co.uk/js/Toolkit.Drawing.js
|
|
|
6757 |
*/
|
|
|
6758 |
|
|
|
6759 |
dojo._Line = function(/*int*/ start, /*int*/ end){
|
|
|
6760 |
// summary:
|
|
|
6761 |
// dojo._Line is the object used to generate values from a start value
|
|
|
6762 |
// to an end value
|
|
|
6763 |
// start: int
|
|
|
6764 |
// Beginning value for range
|
|
|
6765 |
// end: int
|
|
|
6766 |
// Ending value for range
|
|
|
6767 |
this.start = start;
|
|
|
6768 |
this.end = end;
|
|
|
6769 |
this.getValue = function(/*float*/ n){
|
|
|
6770 |
// summary: returns the point on the line
|
|
|
6771 |
// n: a floating point number greater than 0 and less than 1
|
|
|
6772 |
return ((this.end - this.start) * n) + this.start; // Decimal
|
|
|
6773 |
}
|
|
|
6774 |
}
|
|
|
6775 |
|
|
|
6776 |
dojo.declare("dojo._Animation", null, {
|
|
|
6777 |
// summary
|
|
|
6778 |
// A generic animation object that fires callbacks into it's handlers
|
|
|
6779 |
// object at various states
|
|
|
6780 |
//
|
|
|
6781 |
constructor: function(/*Object*/ args){
|
|
|
6782 |
dojo.mixin(this, args);
|
|
|
6783 |
if(dojo.isArray(this.curve)){
|
|
|
6784 |
/* curve: Array
|
|
|
6785 |
pId: a */
|
|
|
6786 |
this.curve = new dojo._Line(this.curve[0], this.curve[1]);
|
|
|
6787 |
}
|
|
|
6788 |
},
|
|
|
6789 |
|
|
|
6790 |
// duration: Integer
|
|
|
6791 |
// The time in milliseonds the animation will take to run
|
|
|
6792 |
duration: 1000,
|
|
|
6793 |
|
|
|
6794 |
/*=====
|
|
|
6795 |
// curve: dojo._Line||Array
|
|
|
6796 |
// A two element array of start and end values, or a dojo._Line instance to be
|
|
|
6797 |
// used in the Animation.
|
|
|
6798 |
curve: null,
|
|
|
6799 |
|
|
|
6800 |
// easing: Function
|
|
|
6801 |
// A Function to adjust the acceleration (or deceleration) of the progress
|
|
|
6802 |
// across a dojo._Line
|
|
|
6803 |
easing: null,
|
|
|
6804 |
=====*/
|
|
|
6805 |
|
|
|
6806 |
// repeat: Integer
|
|
|
6807 |
// The number of times to loop the animation
|
|
|
6808 |
repeat: 0,
|
|
|
6809 |
|
|
|
6810 |
// rate: Integer
|
|
|
6811 |
// the time in milliseconds to wait before advancing to next frame
|
|
|
6812 |
// (used as a fps timer: rate/1000 = fps)
|
|
|
6813 |
rate: 10 /* 100 fps */,
|
|
|
6814 |
|
|
|
6815 |
/*=====
|
|
|
6816 |
// delay: Integer
|
|
|
6817 |
// The time in milliseconds to wait before starting animation after it has been .play()'ed
|
|
|
6818 |
delay: null,
|
|
|
6819 |
|
|
|
6820 |
// events
|
|
|
6821 |
//
|
|
|
6822 |
// beforeBegin: Event
|
|
|
6823 |
// Synthetic event fired before a dojo._Animation begins playing (synhcronous)
|
|
|
6824 |
beforeBegin: null,
|
|
|
6825 |
|
|
|
6826 |
// onBegin: Event
|
|
|
6827 |
// Synthetic event fired as a dojo._Animation begins playing (useful?)
|
|
|
6828 |
onBegin: null,
|
|
|
6829 |
|
|
|
6830 |
// onAnimate: Event
|
|
|
6831 |
// Synthetic event fired at each interval of a dojo._Animation
|
|
|
6832 |
onAnimate: null,
|
|
|
6833 |
|
|
|
6834 |
// onEnd: Event
|
|
|
6835 |
// Synthetic event fired after the final frame of a dojo._Animation
|
|
|
6836 |
onEnd: null,
|
|
|
6837 |
|
|
|
6838 |
// ???
|
|
|
6839 |
onPlay: null,
|
|
|
6840 |
|
|
|
6841 |
// onPause: Event
|
|
|
6842 |
// Synthetic event fired when a dojo._Animation is paused
|
|
|
6843 |
onPause: null,
|
|
|
6844 |
|
|
|
6845 |
// onStop: Event
|
|
|
6846 |
// Synthetic event fires when a dojo._Animation is stopped
|
|
|
6847 |
onStop: null,
|
|
|
6848 |
|
|
|
6849 |
=====*/
|
|
|
6850 |
|
|
|
6851 |
_percent: 0,
|
|
|
6852 |
_startRepeatCount: 0,
|
|
|
6853 |
|
|
|
6854 |
fire: function(/*Event*/ evt, /*Array?*/ args){
|
|
|
6855 |
// summary:
|
|
|
6856 |
// Convenience function. Fire event "evt" and pass it the
|
|
|
6857 |
// arguments specified in "args".
|
|
|
6858 |
// evt:
|
|
|
6859 |
// The event to fire.
|
|
|
6860 |
// args:
|
|
|
6861 |
// The arguments to pass to the event.
|
|
|
6862 |
if(this[evt]){
|
|
|
6863 |
this[evt].apply(this, args||[]);
|
|
|
6864 |
}
|
|
|
6865 |
return this; // dojo._Animation
|
|
|
6866 |
},
|
|
|
6867 |
|
|
|
6868 |
play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
|
|
|
6869 |
// summary:
|
|
|
6870 |
// Start the animation.
|
|
|
6871 |
// delay:
|
|
|
6872 |
// How many milliseconds to delay before starting.
|
|
|
6873 |
// gotoStart:
|
|
|
6874 |
// If true, starts the animation from the beginning; otherwise,
|
|
|
6875 |
// starts it from its current position.
|
|
|
6876 |
var _t = this;
|
|
|
6877 |
if(gotoStart){
|
|
|
6878 |
_t._stopTimer();
|
|
|
6879 |
_t._active = _t._paused = false;
|
|
|
6880 |
_t._percent = 0;
|
|
|
6881 |
}else if(_t._active && !_t._paused){
|
|
|
6882 |
return _t; // dojo._Animation
|
|
|
6883 |
}
|
|
|
6884 |
|
|
|
6885 |
_t.fire("beforeBegin");
|
|
|
6886 |
|
|
|
6887 |
var d = delay||_t.delay;
|
|
|
6888 |
var _p = dojo.hitch(_t, "_play", gotoStart);
|
|
|
6889 |
if(d > 0){
|
|
|
6890 |
setTimeout(_p, d);
|
|
|
6891 |
return _t; // dojo._Animation
|
|
|
6892 |
}
|
|
|
6893 |
_p();
|
|
|
6894 |
return _t;
|
|
|
6895 |
},
|
|
|
6896 |
|
|
|
6897 |
_play: function(gotoStart){
|
|
|
6898 |
var _t = this;
|
|
|
6899 |
_t._startTime = new Date().valueOf();
|
|
|
6900 |
if(_t._paused){
|
|
|
6901 |
_t._startTime -= _t.duration * _t._percent;
|
|
|
6902 |
}
|
|
|
6903 |
_t._endTime = _t._startTime + _t.duration;
|
|
|
6904 |
|
|
|
6905 |
_t._active = true;
|
|
|
6906 |
_t._paused = false;
|
|
|
6907 |
|
|
|
6908 |
var value = _t.curve.getValue(_t._percent);
|
|
|
6909 |
if(!_t._percent){
|
|
|
6910 |
if(!_t._startRepeatCount){
|
|
|
6911 |
_t._startRepeatCount = _t.repeat;
|
|
|
6912 |
}
|
|
|
6913 |
_t.fire("onBegin", [value]);
|
|
|
6914 |
}
|
|
|
6915 |
|
|
|
6916 |
_t.fire("onPlay", [value]);
|
|
|
6917 |
|
|
|
6918 |
_t._cycle();
|
|
|
6919 |
return _t; // dojo._Animation
|
|
|
6920 |
},
|
|
|
6921 |
|
|
|
6922 |
pause: function(){
|
|
|
6923 |
// summary: Pauses a running animation.
|
|
|
6924 |
this._stopTimer();
|
|
|
6925 |
if(!this._active){ return this; /*dojo._Animation*/}
|
|
|
6926 |
this._paused = true;
|
|
|
6927 |
this.fire("onPause", [this.curve.getValue(this._percent)]);
|
|
|
6928 |
return this; // dojo._Animation
|
|
|
6929 |
},
|
|
|
6930 |
|
|
|
6931 |
gotoPercent: function(/*Decimal*/ percent, /*Boolean?*/ andPlay){
|
|
|
6932 |
// summary:
|
|
|
6933 |
// Sets the progress of the animation.
|
|
|
6934 |
// percent:
|
|
|
6935 |
// A percentage in decimal notation (between and including 0.0 and 1.0).
|
|
|
6936 |
// andPlay:
|
|
|
6937 |
// If true, play the animation after setting the progress.
|
|
|
6938 |
this._stopTimer();
|
|
|
6939 |
this._active = this._paused = true;
|
|
|
6940 |
this._percent = percent;
|
|
|
6941 |
if(andPlay){ this.play(); }
|
|
|
6942 |
return this; // dojo._Animation
|
|
|
6943 |
},
|
|
|
6944 |
|
|
|
6945 |
stop: function(/*boolean?*/ gotoEnd){
|
|
|
6946 |
// summary: Stops a running animation.
|
|
|
6947 |
// gotoEnd: If true, the animation will end.
|
|
|
6948 |
if(!this._timer){ return; }
|
|
|
6949 |
this._stopTimer();
|
|
|
6950 |
if(gotoEnd){
|
|
|
6951 |
this._percent = 1;
|
|
|
6952 |
}
|
|
|
6953 |
this.fire("onStop", [this.curve.getValue(this._percent)]);
|
|
|
6954 |
this._active = this._paused = false;
|
|
|
6955 |
return this; // dojo._Animation
|
|
|
6956 |
},
|
|
|
6957 |
|
|
|
6958 |
status: function(){
|
|
|
6959 |
// summary: Returns a string token representation of the status of
|
|
|
6960 |
// the animation, one of: "paused", "playing", "stopped"
|
|
|
6961 |
if(this._active){
|
|
|
6962 |
return this._paused ? "paused" : "playing"; // String
|
|
|
6963 |
}
|
|
|
6964 |
return "stopped"; // String
|
|
|
6965 |
},
|
|
|
6966 |
|
|
|
6967 |
_cycle: function(){
|
|
|
6968 |
var _t = this;
|
|
|
6969 |
if(_t._active){
|
|
|
6970 |
var curr = new Date().valueOf();
|
|
|
6971 |
var step = (curr - _t._startTime) / (_t._endTime - _t._startTime);
|
|
|
6972 |
|
|
|
6973 |
if(step >= 1){
|
|
|
6974 |
step = 1;
|
|
|
6975 |
}
|
|
|
6976 |
_t._percent = step;
|
|
|
6977 |
|
|
|
6978 |
// Perform easing
|
|
|
6979 |
if(_t.easing){
|
|
|
6980 |
step = _t.easing(step);
|
|
|
6981 |
}
|
|
|
6982 |
|
|
|
6983 |
_t.fire("onAnimate", [_t.curve.getValue(step)]);
|
|
|
6984 |
|
|
|
6985 |
if(step < 1){
|
|
|
6986 |
_t._startTimer();
|
|
|
6987 |
}else{
|
|
|
6988 |
_t._active = false;
|
|
|
6989 |
|
|
|
6990 |
if(_t.repeat > 0){
|
|
|
6991 |
_t.repeat--;
|
|
|
6992 |
_t.play(null, true);
|
|
|
6993 |
}else if(_t.repeat == -1){
|
|
|
6994 |
_t.play(null, true);
|
|
|
6995 |
}else{
|
|
|
6996 |
if(_t._startRepeatCount){
|
|
|
6997 |
_t.repeat = _t._startRepeatCount;
|
|
|
6998 |
_t._startRepeatCount = 0;
|
|
|
6999 |
}
|
|
|
7000 |
}
|
|
|
7001 |
_t._percent = 0;
|
|
|
7002 |
_t.fire("onEnd");
|
|
|
7003 |
}
|
|
|
7004 |
}
|
|
|
7005 |
return _t; // dojo._Animation
|
|
|
7006 |
}
|
|
|
7007 |
});
|
|
|
7008 |
|
|
|
7009 |
(function(){
|
|
|
7010 |
var d = dojo;
|
|
|
7011 |
var ctr = 0;
|
|
|
7012 |
var _globalTimerList = [];
|
|
|
7013 |
var runner = {
|
|
|
7014 |
run: function(){}
|
|
|
7015 |
};
|
|
|
7016 |
var timer = null;
|
|
|
7017 |
dojo._Animation.prototype._startTimer = function(){
|
|
|
7018 |
// this._timer = setTimeout(dojo.hitch(this, "_cycle"), this.rate);
|
|
|
7019 |
if(!this._timer){
|
|
|
7020 |
this._timer = dojo.connect(runner, "run", this, "_cycle");
|
|
|
7021 |
ctr++;
|
|
|
7022 |
}
|
|
|
7023 |
if(!timer){
|
|
|
7024 |
timer = setInterval(dojo.hitch(runner, "run"), this.rate);
|
|
|
7025 |
}
|
|
|
7026 |
};
|
|
|
7027 |
|
|
|
7028 |
dojo._Animation.prototype._stopTimer = function(){
|
|
|
7029 |
dojo.disconnect(this._timer);
|
|
|
7030 |
this._timer = null;
|
|
|
7031 |
ctr--;
|
|
|
7032 |
if(!ctr){
|
|
|
7033 |
clearInterval(timer);
|
|
|
7034 |
timer = null;
|
|
|
7035 |
}
|
|
|
7036 |
};
|
|
|
7037 |
|
|
|
7038 |
var _makeFadeable = (d.isIE) ? function(node){
|
|
|
7039 |
// only set the zoom if the "tickle" value would be the same as the
|
|
|
7040 |
// default
|
|
|
7041 |
var ns = node.style;
|
|
|
7042 |
if(!ns.zoom.length && d.style(node, "zoom") == "normal"){
|
|
|
7043 |
// make sure the node "hasLayout"
|
|
|
7044 |
// NOTE: this has been tested with larger and smaller user-set text
|
|
|
7045 |
// sizes and works fine
|
|
|
7046 |
ns.zoom = "1";
|
|
|
7047 |
// node.style.zoom = "normal";
|
|
|
7048 |
}
|
|
|
7049 |
// don't set the width to auto if it didn't already cascade that way.
|
|
|
7050 |
// We don't want to f anyones designs
|
|
|
7051 |
if(!ns.width.length && d.style(node, "width") == "auto"){
|
|
|
7052 |
ns.width = "auto";
|
|
|
7053 |
}
|
|
|
7054 |
} : function(){};
|
|
|
7055 |
|
|
|
7056 |
dojo._fade = function(/*Object*/ args){
|
|
|
7057 |
// summary:
|
|
|
7058 |
// Returns an animation that will fade the node defined by
|
|
|
7059 |
// args.node from the start to end values passed (args.start
|
|
|
7060 |
// args.end) (end is mandatory, start is optional)
|
|
|
7061 |
|
|
|
7062 |
args.node = d.byId(args.node);
|
|
|
7063 |
var fArgs = d.mixin({ properties: {} }, args);
|
|
|
7064 |
var props = (fArgs.properties.opacity = {});
|
|
|
7065 |
props.start = !("start" in fArgs) ?
|
|
|
7066 |
function(){ return Number(d.style(fArgs.node, "opacity")); } : fArgs.start;
|
|
|
7067 |
props.end = fArgs.end;
|
|
|
7068 |
|
|
|
7069 |
var anim = d.animateProperty(fArgs);
|
|
|
7070 |
d.connect(anim, "beforeBegin", d.partial(_makeFadeable, fArgs.node));
|
|
|
7071 |
|
|
|
7072 |
return anim; // dojo._Animation
|
|
|
7073 |
}
|
|
|
7074 |
|
|
|
7075 |
/*=====
|
|
|
7076 |
dojo.__fadeArgs = function(kwArgs){
|
|
|
7077 |
// duration: Integer?
|
|
|
7078 |
// Duration of the animation in milliseconds.
|
|
|
7079 |
// easing: Function?
|
|
|
7080 |
// An easing function.
|
|
|
7081 |
}
|
|
|
7082 |
=====*/
|
|
|
7083 |
|
|
|
7084 |
dojo.fadeIn = function(/*dojo.__fadeArgs*/ args){
|
|
|
7085 |
// summary:
|
|
|
7086 |
// Returns an animation that will fade node defined in 'args' from
|
|
|
7087 |
// its current opacity to fully opaque.
|
|
|
7088 |
return d._fade(d.mixin({ end: 1 }, args)); // dojo._Animation
|
|
|
7089 |
}
|
|
|
7090 |
|
|
|
7091 |
dojo.fadeOut = function(/*dojo.__fadeArgs*/ args){
|
|
|
7092 |
// summary:
|
|
|
7093 |
// Returns an animation that will fade node defined in 'args'
|
|
|
7094 |
// from its current opacity to fully transparent.
|
|
|
7095 |
return d._fade(d.mixin({ end: 0 }, args)); // dojo._Animation
|
|
|
7096 |
}
|
|
|
7097 |
|
|
|
7098 |
dojo._defaultEasing = function(/*Decimal?*/ n){
|
|
|
7099 |
// summary: The default easing function for dojo._Animation(s)
|
|
|
7100 |
return 0.5 + ((Math.sin((n + 1.5) * Math.PI))/2);
|
|
|
7101 |
}
|
|
|
7102 |
|
|
|
7103 |
var PropLine = function(properties){
|
|
|
7104 |
this._properties = properties;
|
|
|
7105 |
for(var p in properties){
|
|
|
7106 |
var prop = properties[p];
|
|
|
7107 |
if(prop.start instanceof d.Color){
|
|
|
7108 |
// create a reusable temp color object to keep intermediate results
|
|
|
7109 |
prop.tempColor = new d.Color();
|
|
|
7110 |
}
|
|
|
7111 |
}
|
|
|
7112 |
this.getValue = function(r){
|
|
|
7113 |
var ret = {};
|
|
|
7114 |
for(var p in this._properties){
|
|
|
7115 |
var prop = this._properties[p];
|
|
|
7116 |
var start = prop.start;
|
|
|
7117 |
if(start instanceof d.Color){
|
|
|
7118 |
ret[p] = d.blendColors(start, prop.end, r, prop.tempColor).toCss();
|
|
|
7119 |
}else if(!d.isArray(start)){
|
|
|
7120 |
ret[p] = ((prop.end - start) * r) + start + (p != "opacity" ? prop.units||"px" : "");
|
|
|
7121 |
}
|
|
|
7122 |
}
|
|
|
7123 |
return ret;
|
|
|
7124 |
}
|
|
|
7125 |
}
|
|
|
7126 |
|
|
|
7127 |
dojo.animateProperty = function(/*Object*/ args){
|
|
|
7128 |
// summary:
|
|
|
7129 |
// Returns an animation that will transition the properties of
|
|
|
7130 |
// node defined in 'args' depending how they are defined in
|
|
|
7131 |
// 'args.properties'
|
|
|
7132 |
//
|
|
|
7133 |
// description:
|
|
|
7134 |
// The foundation of most dojo.fx animations, dojo.AnimateProperty
|
|
|
7135 |
// will take an object of "properties" corresponding to style
|
|
|
7136 |
// properties, and animate them in parallel over a set duration.
|
|
|
7137 |
//
|
|
|
7138 |
// args.node can be a String or a DomNode reference
|
|
|
7139 |
//
|
|
|
7140 |
// example:
|
|
|
7141 |
// | dojo.animateProperty({ node: node, duration:2000,
|
|
|
7142 |
// | properties: {
|
|
|
7143 |
// | width: { start: '200', end: '400', unit:"px" },
|
|
|
7144 |
// | height: { start:'200', end: '400', unit:"px" },
|
|
|
7145 |
// | paddingTop: { start:'5', end:'50', unit:"px" }
|
|
|
7146 |
// | }
|
|
|
7147 |
// | }).play();
|
|
|
7148 |
//
|
|
|
7149 |
|
|
|
7150 |
args.node = d.byId(args.node);
|
|
|
7151 |
if(!args.easing){ args.easing = d._defaultEasing; }
|
|
|
7152 |
|
|
|
7153 |
var anim = new d._Animation(args);
|
|
|
7154 |
d.connect(anim, "beforeBegin", anim, function(){
|
|
|
7155 |
var pm = {};
|
|
|
7156 |
for(var p in this.properties){
|
|
|
7157 |
// Make shallow copy of properties into pm because we overwrite some values below.
|
|
|
7158 |
// In particular if start/end are functions we don't want to overwrite them or
|
|
|
7159 |
// the functions won't be called if the animation is reused.
|
|
|
7160 |
var prop = (pm[p] = d.mixin({}, this.properties[p]));
|
|
|
7161 |
|
|
|
7162 |
if(d.isFunction(prop.start)){
|
|
|
7163 |
prop.start = prop.start();
|
|
|
7164 |
}
|
|
|
7165 |
if(d.isFunction(prop.end)){
|
|
|
7166 |
prop.end = prop.end();
|
|
|
7167 |
}
|
|
|
7168 |
|
|
|
7169 |
var isColor = (p.toLowerCase().indexOf("color") >= 0);
|
|
|
7170 |
function getStyle(node, p){
|
|
|
7171 |
// dojo.style(node, "height") can return "auto" or "" on IE; this is more reliable:
|
|
|
7172 |
var v = ({height: node.offsetHeight, width: node.offsetWidth})[p];
|
|
|
7173 |
if(v !== undefined){ return v; }
|
|
|
7174 |
v = d.style(node, p);
|
|
|
7175 |
return (p=="opacity") ? Number(v) : parseFloat(v);
|
|
|
7176 |
}
|
|
|
7177 |
if(!("end" in prop)){
|
|
|
7178 |
prop.end = getStyle(this.node, p);
|
|
|
7179 |
}else if(!("start" in prop)){
|
|
|
7180 |
prop.start = getStyle(this.node, p);
|
|
|
7181 |
}
|
|
|
7182 |
|
|
|
7183 |
if(isColor){
|
|
|
7184 |
// console.debug("it's a color!");
|
|
|
7185 |
prop.start = new d.Color(prop.start);
|
|
|
7186 |
prop.end = new d.Color(prop.end);
|
|
|
7187 |
}else{
|
|
|
7188 |
prop.start = (p == "opacity") ? Number(prop.start) : parseFloat(prop.start);
|
|
|
7189 |
}
|
|
|
7190 |
// console.debug("start:", prop.start);
|
|
|
7191 |
// console.debug("end:", prop.end);
|
|
|
7192 |
}
|
|
|
7193 |
this.curve = new PropLine(pm);
|
|
|
7194 |
});
|
|
|
7195 |
d.connect(anim, "onAnimate", anim, function(propValues){
|
|
|
7196 |
// try{
|
|
|
7197 |
for(var s in propValues){
|
|
|
7198 |
// console.debug(s, propValues[s], this.node.style[s]);
|
|
|
7199 |
d.style(this.node, s, propValues[s]);
|
|
|
7200 |
// this.node.style[s] = propValues[s];
|
|
|
7201 |
}
|
|
|
7202 |
// }catch(e){ console.debug(dojo.toJson(e)); }
|
|
|
7203 |
});
|
|
|
7204 |
return anim; // dojo._Animation
|
|
|
7205 |
}
|
|
|
7206 |
})();
|
|
|
7207 |
|
|
|
7208 |
}
|
|
|
7209 |
|