]>
Commit | Line | Data |
---|---|---|
2f01fe57 AD |
1 | /* |
2 | Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. | |
3 | Available via Academic Free License >= 2.1 OR the modified BSD license. | |
4 | see: http://dojotoolkit.org/license for details | |
5 | */ | |
6 | ||
7 | ||
a089699c AD |
8 | if(!dojo._hasResource["dojo._base.lang"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
9 | dojo._hasResource["dojo._base.lang"] = true; | |
2f01fe57 | 10 | dojo.provide("dojo._base.lang"); |
a089699c | 11 | |
2f01fe57 | 12 | (function(){ |
a089699c AD |
13 | var d = dojo, opts = Object.prototype.toString; |
14 | ||
15 | // Crockford (ish) functions | |
16 | ||
17 | dojo.isString = function(/*anything*/ it){ | |
18 | // summary: | |
19 | // Return true if it is a String | |
20 | return (typeof it == "string" || it instanceof String); // Boolean | |
21 | } | |
22 | ||
23 | dojo.isArray = function(/*anything*/ it){ | |
24 | // summary: | |
25 | // Return true if it is an Array. | |
26 | // Does not work on Arrays created in other windows. | |
27 | return it && (it instanceof Array || typeof it == "array"); // Boolean | |
28 | } | |
29 | ||
30 | dojo.isFunction = function(/*anything*/ it){ | |
31 | // summary: | |
32 | // Return true if it is a Function | |
33 | return opts.call(it) === "[object Function]"; | |
34 | }; | |
35 | ||
36 | dojo.isObject = function(/*anything*/ it){ | |
37 | // summary: | |
38 | // Returns true if it is a JavaScript object (or an Array, a Function | |
39 | // or null) | |
40 | return it !== undefined && | |
41 | (it === null || typeof it == "object" || d.isArray(it) || d.isFunction(it)); // Boolean | |
42 | } | |
43 | ||
44 | dojo.isArrayLike = function(/*anything*/ it){ | |
45 | // summary: | |
46 | // similar to dojo.isArray() but more permissive | |
47 | // description: | |
48 | // Doesn't strongly test for "arrayness". Instead, settles for "isn't | |
49 | // a string or number and has a length property". Arguments objects | |
50 | // and DOM collections will return true when passed to | |
51 | // dojo.isArrayLike(), but will return false when passed to | |
52 | // dojo.isArray(). | |
53 | // returns: | |
54 | // If it walks like a duck and quacks like a duck, return `true` | |
55 | return it && it !== undefined && // Boolean | |
56 | // keep out built-in constructors (Number, String, ...) which have length | |
57 | // properties | |
58 | !d.isString(it) && !d.isFunction(it) && | |
59 | !(it.tagName && it.tagName.toLowerCase() == 'form') && | |
60 | (d.isArray(it) || isFinite(it.length)); | |
61 | } | |
62 | ||
63 | dojo.isAlien = function(/*anything*/ it){ | |
64 | // summary: | |
65 | // Returns true if it is a built-in function or some other kind of | |
66 | // oddball that *should* report as a function but doesn't | |
67 | return it && !d.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean | |
68 | } | |
69 | ||
70 | dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){ | |
71 | // summary: | |
72 | // Adds all properties and methods of props to constructor's | |
73 | // prototype, making them available to all instances created with | |
74 | // constructor. | |
75 | for(var i=1, l=arguments.length; i<l; i++){ | |
76 | d._mixin(constructor.prototype, arguments[i]); | |
77 | } | |
78 | return constructor; // Object | |
79 | } | |
80 | ||
81 | dojo._hitchArgs = function(scope, method /*,...*/){ | |
82 | var pre = d._toArray(arguments, 2); | |
83 | var named = d.isString(method); | |
84 | return function(){ | |
85 | // arrayify arguments | |
86 | var args = d._toArray(arguments); | |
87 | // locate our method | |
88 | var f = named ? (scope||d.global)[method] : method; | |
89 | // invoke with collected args | |
90 | return f && f.apply(scope || this, pre.concat(args)); // mixed | |
91 | } // Function | |
92 | } | |
93 | ||
94 | dojo.hitch = function(/*Object*/scope, /*Function|String*/method /*,...*/){ | |
95 | // summary: | |
96 | // Returns a function that will only ever execute in the a given scope. | |
97 | // This allows for easy use of object member functions | |
98 | // in callbacks and other places in which the "this" keyword may | |
99 | // otherwise not reference the expected scope. | |
100 | // Any number of default positional arguments may be passed as parameters | |
101 | // beyond "method". | |
102 | // Each of these values will be used to "placehold" (similar to curry) | |
103 | // for the hitched function. | |
104 | // scope: | |
105 | // The scope to use when method executes. If method is a string, | |
106 | // scope is also the object containing method. | |
107 | // method: | |
108 | // A function to be hitched to scope, or the name of the method in | |
109 | // scope to be hitched. | |
110 | // example: | |
111 | // | dojo.hitch(foo, "bar")(); | |
112 | // runs foo.bar() in the scope of foo | |
113 | // example: | |
114 | // | dojo.hitch(foo, myFunction); | |
115 | // returns a function that runs myFunction in the scope of foo | |
116 | // example: | |
117 | // Expansion on the default positional arguments passed along from | |
118 | // hitch. Passed args are mixed first, additional args after. | |
119 | // | var foo = { bar: function(a, b, c){ console.log(a, b, c); } }; | |
120 | // | var fn = dojo.hitch(foo, "bar", 1, 2); | |
121 | // | fn(3); // logs "1, 2, 3" | |
122 | // example: | |
123 | // | var foo = { bar: 2 }; | |
124 | // | dojo.hitch(foo, function(){ this.bar = 10; })(); | |
125 | // execute an anonymous function in scope of foo | |
126 | ||
127 | if(arguments.length > 2){ | |
128 | return d._hitchArgs.apply(d, arguments); // Function | |
129 | } | |
130 | if(!method){ | |
131 | method = scope; | |
132 | scope = null; | |
133 | } | |
134 | if(d.isString(method)){ | |
135 | scope = scope || d.global; | |
136 | if(!scope[method]){ throw(['dojo.hitch: scope["', method, '"] is null (scope="', scope, '")'].join('')); } | |
137 | return function(){ return scope[method].apply(scope, arguments || []); }; // Function | |
138 | } | |
139 | return !scope ? method : function(){ return method.apply(scope, arguments || []); }; // Function | |
140 | } | |
141 | ||
142 | /*===== | |
143 | dojo.delegate = function(obj, props){ | |
144 | // summary: | |
145 | // Returns a new object which "looks" to obj for properties which it | |
146 | // does not have a value for. Optionally takes a bag of properties to | |
147 | // seed the returned object with initially. | |
148 | // description: | |
149 | // This is a small implementaton of the Boodman/Crockford delegation | |
150 | // pattern in JavaScript. An intermediate object constructor mediates | |
151 | // the prototype chain for the returned object, using it to delegate | |
152 | // down to obj for property lookup when object-local lookup fails. | |
153 | // This can be thought of similarly to ES4's "wrap", save that it does | |
154 | // not act on types but rather on pure objects. | |
155 | // obj: | |
156 | // The object to delegate to for properties not found directly on the | |
157 | // return object or in props. | |
158 | // props: | |
159 | // an object containing properties to assign to the returned object | |
160 | // returns: | |
161 | // an Object of anonymous type | |
162 | // example: | |
163 | // | var foo = { bar: "baz" }; | |
164 | // | var thinger = dojo.delegate(foo, { thud: "xyzzy"}); | |
165 | // | thinger.bar == "baz"; // delegated to foo | |
166 | // | foo.thud == undefined; // by definition | |
167 | // | thinger.thud == "xyzzy"; // mixed in from props | |
168 | // | foo.bar = "thonk"; | |
169 | // | thinger.bar == "thonk"; // still delegated to foo's bar | |
170 | } | |
171 | =====*/ | |
172 | ||
173 | dojo.delegate = dojo._delegate = (function(){ | |
174 | // boodman/crockford delegation w/ cornford optimization | |
175 | function TMP(){} | |
176 | return function(obj, props){ | |
177 | TMP.prototype = obj; | |
178 | var tmp = new TMP(); | |
179 | TMP.prototype = null; | |
180 | if(props){ | |
181 | d._mixin(tmp, props); | |
182 | } | |
183 | return tmp; // Object | |
184 | } | |
185 | })(); | |
186 | ||
187 | /*===== | |
188 | dojo._toArray = function(obj, offset, startWith){ | |
189 | // summary: | |
190 | // Converts an array-like object (i.e. arguments, DOMCollection) to an | |
191 | // array. Returns a new Array with the elements of obj. | |
192 | // obj: Object | |
193 | // the object to "arrayify". We expect the object to have, at a | |
194 | // minimum, a length property which corresponds to integer-indexed | |
195 | // properties. | |
196 | // offset: Number? | |
197 | // the location in obj to start iterating from. Defaults to 0. | |
198 | // Optional. | |
199 | // startWith: Array? | |
200 | // An array to pack with the properties of obj. If provided, | |
201 | // properties in obj are appended at the end of startWith and | |
202 | // startWith is the returned array. | |
203 | } | |
204 | =====*/ | |
205 | ||
206 | var efficient = function(obj, offset, startWith){ | |
207 | return (startWith||[]).concat(Array.prototype.slice.call(obj, offset||0)); | |
208 | }; | |
209 | ||
210 | var slow = function(obj, offset, startWith){ | |
211 | var arr = startWith||[]; | |
212 | for(var x = offset || 0; x < obj.length; x++){ | |
213 | arr.push(obj[x]); | |
214 | } | |
215 | return arr; | |
216 | }; | |
217 | ||
218 | dojo._toArray = | |
219 | d.isIE ? function(obj){ | |
220 | return ((obj.item) ? slow : efficient).apply(this, arguments); | |
221 | } : | |
222 | efficient; | |
223 | ||
224 | dojo.partial = function(/*Function|String*/method /*, ...*/){ | |
225 | // summary: | |
226 | // similar to hitch() except that the scope object is left to be | |
227 | // whatever the execution context eventually becomes. | |
228 | // description: | |
229 | // Calling dojo.partial is the functional equivalent of calling: | |
230 | // | dojo.hitch(null, funcName, ...); | |
231 | var arr = [ null ]; | |
232 | return d.hitch.apply(d, arr.concat(d._toArray(arguments))); // Function | |
233 | } | |
234 | ||
235 | var extraNames = d._extraNames, extraLen = extraNames.length, empty = {}; | |
236 | ||
237 | dojo.clone = function(/*anything*/ o){ | |
238 | // summary: | |
239 | // Clones objects (including DOM nodes) and all children. | |
240 | // Warning: do not clone cyclic structures. | |
241 | if(!o || typeof o != "object" || d.isFunction(o)){ | |
242 | // null, undefined, any non-object, or function | |
243 | return o; // anything | |
244 | } | |
245 | if(o.nodeType && "cloneNode" in o){ | |
246 | // DOM Node | |
247 | return o.cloneNode(true); // Node | |
248 | } | |
249 | if(o instanceof Date){ | |
250 | // Date | |
251 | return new Date(o.getTime()); // Date | |
252 | } | |
253 | var r, i, l, s, name; | |
254 | if(d.isArray(o)){ | |
255 | // array | |
256 | r = []; | |
257 | for(i = 0, l = o.length; i < l; ++i){ | |
258 | if(i in o){ | |
259 | r.push(d.clone(o[i])); | |
260 | } | |
261 | } | |
262 | // we don't clone functions for performance reasons | |
263 | // }else if(d.isFunction(o)){ | |
264 | // // function | |
265 | // r = function(){ return o.apply(this, arguments); }; | |
266 | }else{ | |
267 | // generic objects | |
268 | r = o.constructor ? new o.constructor() : {}; | |
269 | } | |
270 | for(name in o){ | |
271 | // the "tobj" condition avoid copying properties in "source" | |
272 | // inherited from Object.prototype. For example, if target has a custom | |
273 | // toString() method, don't overwrite it with the toString() method | |
274 | // that source inherited from Object.prototype | |
275 | s = o[name]; | |
276 | if(!(name in r) || (r[name] !== s && (!(name in empty) || empty[name] !== s))){ | |
277 | r[name] = d.clone(s); | |
278 | } | |
279 | } | |
280 | // IE doesn't recognize some custom functions in for..in | |
281 | if(extraLen){ | |
282 | for(i = 0; i < extraLen; ++i){ | |
283 | name = extraNames[i]; | |
284 | s = o[name]; | |
285 | if(!(name in r) || (r[name] !== s && (!(name in empty) || empty[name] !== s))){ | |
286 | r[name] = s; // functions only, we don't clone them | |
287 | } | |
288 | } | |
289 | } | |
290 | return r; // Object | |
291 | } | |
292 | ||
293 | /*===== | |
294 | dojo.trim = function(str){ | |
295 | // summary: | |
296 | // Trims whitespace from both sides of the string | |
297 | // str: String | |
298 | // String to be trimmed | |
299 | // returns: String | |
300 | // Returns the trimmed string | |
301 | // description: | |
302 | // This version of trim() was selected for inclusion into the base due | |
303 | // to its compact size and relatively good performance | |
304 | // (see [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript) | |
305 | // Uses String.prototype.trim instead, if available. | |
306 | // The fastest but longest version of this function is located at | |
307 | // dojo.string.trim() | |
308 | return ""; // String | |
309 | } | |
310 | =====*/ | |
311 | ||
312 | dojo.trim = String.prototype.trim ? | |
313 | function(str){ return str.trim(); } : | |
314 | function(str){ return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; | |
315 | ||
316 | /*===== | |
317 | dojo.replace = function(tmpl, map, pattern){ | |
318 | // summary: | |
319 | // Performs parameterized substitutions on a string. Throws an | |
320 | // exception if any parameter is unmatched. | |
321 | // tmpl: String | |
322 | // String to be used as a template. | |
323 | // map: Object|Function | |
324 | // If an object, it is used as a dictionary to look up substitutions. | |
325 | // If a function, it is called for every substitution with following | |
326 | // parameters: a whole match, a name, an offset, and the whole template | |
327 | // string (see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/String/replace | |
328 | // for more details). | |
329 | // pattern: RegEx? | |
330 | // Optional regular expression objects that overrides the default pattern. | |
331 | // Must be global and match one item. The default is: /\{([^\}]+)\}/g, | |
332 | // which matches patterns like that: "{xxx}", where "xxx" is any sequence | |
333 | // of characters, which doesn't include "}". | |
334 | // returns: String | |
335 | // Returns the substituted string. | |
336 | // example: | |
337 | // | // uses a dictionary for substitutions: | |
338 | // | dojo.replace("Hello, {name.first} {name.last} AKA {nick}!", | |
339 | // | { | |
340 | // | nick: "Bob", | |
341 | // | name: { | |
342 | // | first: "Robert", | |
343 | // | middle: "X", | |
344 | // | last: "Cringely" | |
345 | // | } | |
346 | // | }); | |
347 | // | // returns: Hello, Robert Cringely AKA Bob! | |
348 | // example: | |
349 | // | // uses an array for substitutions: | |
350 | // | dojo.replace("Hello, {0} {2}!", | |
351 | // | ["Robert", "X", "Cringely"]); | |
352 | // | // returns: Hello, Robert Cringely! | |
353 | // example: | |
354 | // | // uses a function for substitutions: | |
355 | // | function sum(a){ | |
356 | // | var t = 0; | |
357 | // | dojo.forEach(a, function(x){ t += x; }); | |
358 | // | return t; | |
359 | // | } | |
360 | // | dojo.replace( | |
361 | // | "{count} payments averaging {avg} USD per payment.", | |
362 | // | dojo.hitch( | |
363 | // | { payments: [11, 16, 12] }, | |
364 | // | function(_, key){ | |
365 | // | switch(key){ | |
366 | // | case "count": return this.payments.length; | |
367 | // | case "min": return Math.min.apply(Math, this.payments); | |
368 | // | case "max": return Math.max.apply(Math, this.payments); | |
369 | // | case "sum": return sum(this.payments); | |
370 | // | case "avg": return sum(this.payments) / this.payments.length; | |
371 | // | } | |
372 | // | } | |
373 | // | ) | |
374 | // | ); | |
375 | // | // prints: 3 payments averaging 13 USD per payment. | |
376 | // example: | |
377 | // | // uses an alternative PHP-like pattern for substitutions: | |
378 | // | dojo.replace("Hello, ${0} ${2}!", | |
379 | // | ["Robert", "X", "Cringely"], /\$\{([^\}]+)\}/g); | |
380 | // | // returns: Hello, Robert Cringely! | |
381 | return ""; // String | |
382 | } | |
383 | =====*/ | |
384 | ||
385 | var _pattern = /\{([^\}]+)\}/g; | |
386 | dojo.replace = function(tmpl, map, pattern){ | |
387 | return tmpl.replace(pattern || _pattern, d.isFunction(map) ? | |
388 | map : function(_, k){ return d.getObject(k, false, map); }); | |
389 | }; | |
2f01fe57 | 390 | })(); |
a089699c | 391 | |
2f01fe57 | 392 | } |