OLD | NEW |
| (Empty) |
1 // Copyright 2006 Google Inc. | |
2 // All Rights Reserved. | |
3 // | |
4 // Redistribution and use in source and binary forms, with or without | |
5 // modification, are permitted provided that the following conditions | |
6 // are met: | |
7 // | |
8 // * Redistributions of source code must retain the above copyright | |
9 // notice, this list of conditions and the following disclaimer. | |
10 // * Redistributions in binary form must reproduce the above copyright | |
11 // notice, this list of conditions and the following disclaimer in | |
12 // the documentation and/or other materials provided with the | |
13 // distribution. | |
14 // | |
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
18 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
19 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
20 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
21 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
22 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
24 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
25 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
26 // POSSIBILITY OF SUCH DAMAGE. | |
27 | |
28 // NOTE: This file has been changed from the one on doctype. The following | |
29 // changes were made: | |
30 // - Removed goog.globalEval because it calls eval() which is not allowed from | |
31 // inside v8 extensions. If we ever need to use globalEval, we will need to | |
32 // find a way to work around this problem. | |
33 // - Remove Function.prototype.apply() emulation for the same reason. This one | |
34 // is useless anyway because V8 supports apply() natively. | |
35 | |
36 /** | |
37 * @fileoverview Bootstrap for the Google JS Library | |
38 */ | |
39 | |
40 /** | |
41 * @define {boolean} Overridden to true by the compiler when | |
42 * --mark_as_compiled is specified. | |
43 */ | |
44 var COMPILED = true; | |
45 | |
46 | |
47 /** | |
48 * Base namespace for the Google JS library. Checks to see goog is | |
49 * already defined in the current scope before assigning to prevent | |
50 * clobbering if base.js is loaded more than once. | |
51 */ | |
52 var goog = {}; // Check to see if already defined in current scope | |
53 | |
54 | |
55 /** | |
56 * Reference to the global context. In most cases this will be 'window'. | |
57 */ | |
58 goog.global = this; | |
59 | |
60 | |
61 /** | |
62 * Indicates whether or not we can call 'eval' directly to eval code in the | |
63 * global scope. Set to a Boolean by the first call to goog.globalEval (which | |
64 * empirically tests whether eval works for globals). @see goog.globalEval | |
65 * @type {boolean?} | |
66 * @private | |
67 */ | |
68 goog.evalWorksForGlobals_ = null; | |
69 | |
70 | |
71 /** | |
72 * Creates object stubs for a namespace. When present in a file, goog.provide | |
73 * also indicates that the file defines the indicated object. | |
74 * @param {string} name name of the object that this file defines. | |
75 */ | |
76 goog.provide = function(name) { | |
77 if (!COMPILED) { | |
78 // Ensure that the same namespace isn't provided twice. This is intended | |
79 // to teach new developers that 'goog.provide' is effectively a variable | |
80 // declaration. And when JSCompiler transforms goog.provide into a real | |
81 // variable declaration, the compiled JS should work the same as the raw | |
82 // JS--even when the raw JS uses goog.provide incorrectly. | |
83 if (goog.getObjectByName(name) && !goog.implicitNamespaces_[name]) { | |
84 throw 'Namespace "' + name + '" already declared.'; | |
85 } | |
86 | |
87 var namespace = name; | |
88 while ((namespace = namespace.substr(0, namespace.lastIndexOf('.')))) { | |
89 goog.implicitNamespaces_[namespace] = true; | |
90 } | |
91 } | |
92 | |
93 goog.exportPath_(name); | |
94 }; | |
95 | |
96 | |
97 if (!COMPILED) { | |
98 /** | |
99 * Namespaces implicitly defined by goog.provide. For example, | |
100 * goog.provide('goog.events.Event') implicitly declares | |
101 * that 'goog' and 'goog.events' must be namespaces. | |
102 * | |
103 * @type {Object} | |
104 * @private | |
105 */ | |
106 goog.implicitNamespaces_ = {}; | |
107 } | |
108 | |
109 | |
110 /** | |
111 * Builds an object structure for the provided namespace path, | |
112 * ensuring that names that already exist are not overwritten. For | |
113 * example: | |
114 * "a.b.c" -> a = {};a.b={};a.b.c={}; | |
115 * Used by goog.provide and goog.exportSymbol. | |
116 * @param {string} name name of the object that this file defines. | |
117 * @param {Object} opt_object the object to expose at the end of the path. | |
118 * @private | |
119 */ | |
120 goog.exportPath_ = function(name, opt_object) { | |
121 var parts = name.split('.'); | |
122 var cur = goog.global; | |
123 var part; | |
124 | |
125 // Internet Explorer exhibits strange behavior when throwing errors from | |
126 // methods externed in this manner. See the testExportSymbolExceptions in | |
127 // base_test.html for an example. | |
128 if (!(parts[0] in cur) && cur.execScript) { | |
129 cur.execScript('var ' + parts[0]); | |
130 } | |
131 | |
132 // Parentheses added to eliminate strict JS warning in Firefox. | |
133 while ((part = parts.shift())) { | |
134 if (!parts.length && goog.isDef(opt_object)) { | |
135 // last part and we have an object; use it | |
136 cur[part] = opt_object; | |
137 } else if (cur[part]) { | |
138 cur = cur[part]; | |
139 } else { | |
140 cur = cur[part] = {}; | |
141 } | |
142 } | |
143 }; | |
144 | |
145 | |
146 /** | |
147 * Returns an object based on its fully qualified name | |
148 * @param {string} name The fully qualified name. | |
149 * @return {Object?} The object or, if not found, null. | |
150 */ | |
151 goog.getObjectByName = function(name) { | |
152 var parts = name.split('.'); | |
153 var cur = goog.global; | |
154 for (var part; part = parts.shift(); ) { | |
155 if (cur[part]) { | |
156 cur = cur[part]; | |
157 } else { | |
158 return null; | |
159 } | |
160 } | |
161 return cur; | |
162 }; | |
163 | |
164 | |
165 /** | |
166 * Globalizes a whole namespace, such as goog or goog.lang. | |
167 * | |
168 * @param {Object} obj The namespace to globalize. | |
169 * @param {Object} opt_global The object to add the properties to. | |
170 * @deprecated Properties may be explicitly exported to the global scope, but | |
171 * this should no longer be done in bulk. | |
172 */ | |
173 goog.globalize = function(obj, opt_global) { | |
174 var global = opt_global || goog.global; | |
175 for (var x in obj) { | |
176 global[x] = obj[x]; | |
177 } | |
178 }; | |
179 | |
180 | |
181 /** | |
182 * Adds a dependency from a file to the files it requires. | |
183 * @param {string} relPath The path to the js file. | |
184 * @param {Array} provides An array of strings with the names of the objects | |
185 * this file provides. | |
186 * @param {Array} requires An array of strings with the names of the objects | |
187 * this file requires. | |
188 */ | |
189 goog.addDependency = function(relPath, provides, requires) { | |
190 if (!COMPILED) { | |
191 var provide, require; | |
192 var path = relPath.replace(/\\/g, '/'); | |
193 var deps = goog.dependencies_; | |
194 for (var i = 0; provide = provides[i]; i++) { | |
195 deps.nameToPath[provide] = path; | |
196 if (!(path in deps.pathToNames)) { | |
197 deps.pathToNames[path] = {}; | |
198 } | |
199 deps.pathToNames[path][provide] = true; | |
200 } | |
201 for (var j = 0; require = requires[j]; j++) { | |
202 if (!(path in deps.requires)) { | |
203 deps.requires[path] = {}; | |
204 } | |
205 deps.requires[path][require] = true; | |
206 } | |
207 } | |
208 }; | |
209 | |
210 | |
211 /** | |
212 * Implements a system for the dynamic resolution of dependencies | |
213 * that works in parallel with the BUILD system. | |
214 * @param {string} rule Rule to include, in the form goog.package.part. | |
215 */ | |
216 goog.require = function(rule) { | |
217 | |
218 // if the object already exists we do not need do do anything | |
219 if (!COMPILED) { | |
220 if (goog.getObjectByName(rule)) { | |
221 return; | |
222 } | |
223 var path = goog.getPathFromDeps_(rule); | |
224 if (path) { | |
225 goog.included_[path] = true; | |
226 goog.writeScripts_(); | |
227 } else { | |
228 // NOTE(nicksantos): We could throw an error, but this would break | |
229 // legacy users that depended on this failing silently. Instead, the | |
230 // compiler should warn us when there are invalid goog.require calls. | |
231 } | |
232 } | |
233 }; | |
234 | |
235 | |
236 /** | |
237 * Path for included scripts | |
238 * @type {string} | |
239 */ | |
240 goog.basePath = ''; | |
241 | |
242 | |
243 /** | |
244 * Null function used for default values of callbacks, etc. | |
245 * @type {Function} | |
246 */ | |
247 goog.nullFunction = function() {}; | |
248 | |
249 | |
250 /** | |
251 * When defining a class Foo with an abstract method bar(), you can do: | |
252 * | |
253 * Foo.prototype.bar = goog.abstractMethod | |
254 * | |
255 * Now if a subclass of Foo fails to override bar(), an error | |
256 * will be thrown when bar() is invoked. | |
257 * | |
258 * Note: This does not take the name of the function to override as | |
259 * an argument because that would make it more difficult to obfuscate | |
260 * our JavaScript code. | |
261 * | |
262 * @throws {Error} when invoked to indicate the method should be | |
263 * overridden. | |
264 */ | |
265 goog.abstractMethod = function() { | |
266 throw Error('unimplemented abstract method'); | |
267 }; | |
268 | |
269 | |
270 if (!COMPILED) { | |
271 /** | |
272 * Object used to keep track of urls that have already been added. This | |
273 * record allows the prevention of circular dependencies. | |
274 * @type {Object} | |
275 * @private | |
276 */ | |
277 goog.included_ = {}; | |
278 | |
279 | |
280 /** | |
281 * This object is used to keep track of dependencies and other data that is | |
282 * used for loading scripts | |
283 * @private | |
284 * @type {Object} | |
285 */ | |
286 goog.dependencies_ = { | |
287 pathToNames: {}, // 1 to many | |
288 nameToPath: {}, // 1 to 1 | |
289 requires: {}, // 1 to many | |
290 visited: {}, // used when resolving dependencies to prevent us from | |
291 // visiting the file twice | |
292 written: {} // used to keep track of script files we have written | |
293 }; | |
294 | |
295 | |
296 /** | |
297 * Tries to detect the base path of the base.js script that bootstraps | |
298 * Google JS Library | |
299 * @private | |
300 */ | |
301 goog.findBasePath_ = function() { | |
302 var doc = goog.global.document; | |
303 if (typeof doc == 'undefined') { | |
304 return; | |
305 } | |
306 if (goog.global.GOOG_BASE_PATH) { | |
307 goog.basePath = goog.global.GOOG_BASE_PATH; | |
308 return; | |
309 } else { | |
310 goog.global.GOOG_BASE_PATH = null; | |
311 } | |
312 var scripts = doc.getElementsByTagName('script'); | |
313 for (var script, i = 0; script = scripts[i]; i++) { | |
314 var src = script.src; | |
315 var l = src.length; | |
316 if (src.substr(l - 7) == 'base.js') { | |
317 goog.basePath = src.substr(0, l - 7); | |
318 return; | |
319 } | |
320 } | |
321 }; | |
322 | |
323 | |
324 /** | |
325 * Writes a script tag if, and only if, that script hasn't already been added | |
326 * to the document. (Must be called at execution time) | |
327 * @param {string} src Script source. | |
328 * @private | |
329 */ | |
330 goog.writeScriptTag_ = function(src) { | |
331 var doc = goog.global.document; | |
332 if (typeof doc != 'undefined' && | |
333 !goog.dependencies_.written[src]) { | |
334 goog.dependencies_.written[src] = true; | |
335 doc.write('<script type="text/javascript" src="' + | |
336 src + '"></' + 'script>'); | |
337 } | |
338 }; | |
339 | |
340 | |
341 /** | |
342 * Resolves dependencies based on the dependencies added using addDependency | |
343 * and calls writeScriptTag_ in the correct order. | |
344 * @private | |
345 */ | |
346 goog.writeScripts_ = function() { | |
347 // the scripts we need to write this time | |
348 var scripts = []; | |
349 var seenScript = {}; | |
350 var deps = goog.dependencies_; | |
351 | |
352 function visitNode(path) { | |
353 if (path in deps.written) { | |
354 return; | |
355 } | |
356 | |
357 // we have already visited this one. We can get here if we have cyclic | |
358 // dependencies | |
359 if (path in deps.visited) { | |
360 if (!(path in seenScript)) { | |
361 seenScript[path] = true; | |
362 scripts.push(path); | |
363 } | |
364 return; | |
365 } | |
366 | |
367 deps.visited[path] = true; | |
368 | |
369 if (path in deps.requires) { | |
370 for (var requireName in deps.requires[path]) { | |
371 visitNode(deps.nameToPath[requireName]); | |
372 } | |
373 } | |
374 | |
375 if (!(path in seenScript)) { | |
376 seenScript[path] = true; | |
377 scripts.push(path); | |
378 } | |
379 } | |
380 | |
381 for (var path in goog.included_) { | |
382 if (!deps.written[path]) { | |
383 visitNode(path); | |
384 } | |
385 } | |
386 | |
387 for (var i = 0; i < scripts.length; i++) { | |
388 if (scripts[i]) { | |
389 goog.writeScriptTag_(goog.basePath + scripts[i]); | |
390 } else { | |
391 throw Error('Undefined script input'); | |
392 } | |
393 } | |
394 }; | |
395 | |
396 | |
397 /** | |
398 * Looks at the dependency rules and tries to determine the script file that | |
399 * fulfills a particular rule. | |
400 * @param {string} rule In the form goog.namespace.Class or project.script. | |
401 * @return {string?} Url corresponding to the rule, or null. | |
402 * @private | |
403 */ | |
404 goog.getPathFromDeps_ = function(rule) { | |
405 if (rule in goog.dependencies_.nameToPath) { | |
406 return goog.dependencies_.nameToPath[rule]; | |
407 } else { | |
408 return null; | |
409 } | |
410 }; | |
411 | |
412 goog.findBasePath_(); | |
413 goog.writeScriptTag_(goog.basePath + 'deps.js'); | |
414 } | |
415 | |
416 | |
417 | |
418 //============================================================================== | |
419 // Language Enhancements | |
420 //============================================================================== | |
421 | |
422 | |
423 /** | |
424 * This is a "fixed" version of the typeof operator. It differs from the typeof | |
425 * operator in such a way that null returns 'null' and arrays return 'array'. | |
426 * @param {*} value The value to get the type of. | |
427 * @return {string} The name of the type. | |
428 */ | |
429 goog.typeOf = function(value) { | |
430 var s = typeof value; | |
431 if (s == 'object') { | |
432 if (value) { | |
433 // We cannot use constructor == Array or instanceof Array because | |
434 // different frames have different Array objects. In IE6, if the iframe | |
435 // where the array was created is destroyed, the array loses its | |
436 // prototype. Then dereferencing val.splice here throws an exception, so | |
437 // we can't use goog.isFunction. Calling typeof directly returns 'unknown' | |
438 // so that will work. In this case, this function will return false and | |
439 // most array functions will still work because the array is still | |
440 // array-like (supports length and []) even though it has lost its | |
441 // prototype. Custom object cannot have non enumerable length and | |
442 // NodeLists don't have a slice method. | |
443 if (typeof value.length == 'number' && | |
444 typeof value.splice != 'undefined' && | |
445 !goog.propertyIsEnumerable_(value, 'length')) { | |
446 return 'array'; | |
447 } | |
448 | |
449 // IE in cross-window calls does not correctly marshal the function type | |
450 // (it appears just as an object) so we cannot use just typeof val == | |
451 // 'function'. However, if the object has a call property, it is a | |
452 // function. | |
453 if (typeof value.call != 'undefined') { | |
454 return 'function'; | |
455 } | |
456 } else { | |
457 return 'null'; | |
458 } | |
459 | |
460 // In Safari typeof nodeList returns function. We would like to return | |
461 // object for those and we can detect an invalid function by making sure that | |
462 // the function object has a call method | |
463 } else if (s == 'function' && typeof value.call == 'undefined') { | |
464 return 'object'; | |
465 } | |
466 return s; | |
467 }; | |
468 | |
469 if (Object.prototype.propertyIsEnumerable) { | |
470 /** | |
471 * Safe way to test whether a property is enumarable. It allows testing | |
472 * for enumarable on objects where 'propertyIsEnumerable' is overridden or | |
473 * does not exist (like DOM nodes in IE). | |
474 * @param {Object} object The object to test if the property is enumerable. | |
475 * @param {string} propName The property name to check for. | |
476 * @return {boolean} True if the property is enumarable. | |
477 * @private | |
478 */ | |
479 goog.propertyIsEnumerable_ = function(object, propName) { | |
480 return Object.prototype.propertyIsEnumerable.call(object, propName); | |
481 }; | |
482 } else { | |
483 /** | |
484 * Safe way to test whether a property is enumarable. It allows testing | |
485 * for enumarable on objects where 'propertyIsEnumerable' is overridden or | |
486 * does not exist (like DOM nodes in IE). | |
487 * @param {Object} object The object to test if the property is enumerable. | |
488 * @param {string} propName The property name to check for. | |
489 * @return {boolean} True if the property is enumarable. | |
490 * @private | |
491 */ | |
492 goog.propertyIsEnumerable_ = function(object, propName) { | |
493 // KJS in Safari 2 is not ECMAScript compatible and lacks crucial methods | |
494 // such as propertyIsEnumerable. We therefore use a workaround. | |
495 // Does anyone know a more efficient work around? | |
496 if (propName in object) { | |
497 for (var key in object) { | |
498 if (key == propName) { | |
499 return true; | |
500 } | |
501 } | |
502 } | |
503 return false; | |
504 }; | |
505 } | |
506 | |
507 /** | |
508 * Returns true if the specified value is not |undefined|. | |
509 * WARNING: Do not use this to test if an object has a property. Use the in | |
510 * operator instead. | |
511 * @param {*} val Variable to test. | |
512 * @return {boolean} Whether variable is defined. | |
513 */ | |
514 goog.isDef = function(val) { | |
515 return typeof val != 'undefined'; | |
516 }; | |
517 | |
518 | |
519 /** | |
520 * Returns true if the specified value is |null| | |
521 * @param {*} val Variable to test. | |
522 * @return {boolean} Whether variable is null. | |
523 */ | |
524 goog.isNull = function(val) { | |
525 return val === null; | |
526 }; | |
527 | |
528 | |
529 /** | |
530 * Returns true if the specified value is defined and not null | |
531 * @param {*} val Variable to test. | |
532 * @return {boolean} Whether variable is defined and not null. | |
533 */ | |
534 goog.isDefAndNotNull = function(val) { | |
535 return goog.isDef(val) && !goog.isNull(val); | |
536 }; | |
537 | |
538 | |
539 /** | |
540 * Returns true if the specified value is an array | |
541 * @param {*} val Variable to test. | |
542 * @return {boolean} Whether variable is an array. | |
543 */ | |
544 goog.isArray = function(val) { | |
545 return goog.typeOf(val) == 'array'; | |
546 }; | |
547 | |
548 | |
549 /** | |
550 * Returns true if the object looks like an array. To qualify as array like | |
551 * the value needs to be either a NodeList or an object with a Number length | |
552 * property. | |
553 * @param {*} val Variable to test. | |
554 * @return {boolean} Whether variable is an array. | |
555 */ | |
556 goog.isArrayLike = function(val) { | |
557 var type = goog.typeOf(val); | |
558 return type == 'array' || type == 'object' && typeof val.length == 'number'; | |
559 }; | |
560 | |
561 | |
562 /** | |
563 * Returns true if the object looks like a Date. To qualify as Date-like | |
564 * the value needs to be an object and have a getFullYear() function. | |
565 * @param {*} val Variable to test. | |
566 * @return {boolean} Whether variable is a like a Date. | |
567 */ | |
568 goog.isDateLike = function(val) { | |
569 return goog.isObject(val) && typeof val.getFullYear == 'function'; | |
570 }; | |
571 | |
572 | |
573 /** | |
574 * Returns true if the specified value is a string | |
575 * @param {*} val Variable to test. | |
576 * @return {boolean} Whether variable is a string. | |
577 */ | |
578 goog.isString = function(val) { | |
579 return typeof val == 'string'; | |
580 }; | |
581 | |
582 | |
583 /** | |
584 * Returns true if the specified value is a boolean | |
585 * @param {*} val Variable to test. | |
586 * @return {boolean} Whether variable is boolean. | |
587 */ | |
588 goog.isBoolean = function(val) { | |
589 return typeof val == 'boolean'; | |
590 }; | |
591 | |
592 | |
593 /** | |
594 * Returns true if the specified value is a number | |
595 * @param {*} val Variable to test. | |
596 * @return {boolean} Whether variable is a number. | |
597 */ | |
598 goog.isNumber = function(val) { | |
599 return typeof val == 'number'; | |
600 }; | |
601 | |
602 | |
603 /** | |
604 * Returns true if the specified value is a function | |
605 * @param {*} val Variable to test. | |
606 * @return {boolean} Whether variable is a function. | |
607 */ | |
608 goog.isFunction = function(val) { | |
609 return goog.typeOf(val) == 'function'; | |
610 }; | |
611 | |
612 | |
613 /** | |
614 * Returns true if the specified value is an object. This includes arrays | |
615 * and functions. | |
616 * @param {*} val Variable to test. | |
617 * @return {boolean} Whether variable is an object. | |
618 */ | |
619 goog.isObject = function(val) { | |
620 var type = goog.typeOf(val); | |
621 return type == 'object' || type == 'array' || type == 'function'; | |
622 }; | |
623 | |
624 | |
625 /** | |
626 * Adds a hash code field to an object. The hash code is unique for the | |
627 * given object. | |
628 * @param {Object} obj The object to get the hash code for. | |
629 * @return {number} The hash code for the object. | |
630 */ | |
631 goog.getHashCode = function(obj) { | |
632 // In IE, DOM nodes do not extend Object so they do not have this method. | |
633 // we need to check hasOwnProperty because the proto might have this set. | |
634 | |
635 if (obj.hasOwnProperty && obj.hasOwnProperty(goog.HASH_CODE_PROPERTY_)) { | |
636 return obj[goog.HASH_CODE_PROPERTY_]; | |
637 } | |
638 if (!obj[goog.HASH_CODE_PROPERTY_]) { | |
639 obj[goog.HASH_CODE_PROPERTY_] = ++goog.hashCodeCounter_; | |
640 } | |
641 return obj[goog.HASH_CODE_PROPERTY_]; | |
642 }; | |
643 | |
644 | |
645 /** | |
646 * Removes the hash code field from an object. | |
647 * @param {Object} obj The object to remove the field from. | |
648 */ | |
649 goog.removeHashCode = function(obj) { | |
650 // DOM nodes in IE are not instance of Object and throws exception | |
651 // for delete. Instead we try to use removeAttribute | |
652 if ('removeAttribute' in obj) { | |
653 obj.removeAttribute(goog.HASH_CODE_PROPERTY_); | |
654 } | |
655 /** @preserveTry */ | |
656 try { | |
657 delete obj[goog.HASH_CODE_PROPERTY_]; | |
658 } catch (ex) { | |
659 } | |
660 }; | |
661 | |
662 | |
663 /** | |
664 * {String} Name for hash code property | |
665 * @private | |
666 */ | |
667 goog.HASH_CODE_PROPERTY_ = 'goog_hashCode_'; | |
668 | |
669 | |
670 /** | |
671 * @type {number} Counter for hash codes. | |
672 * @private | |
673 */ | |
674 goog.hashCodeCounter_ = 0; | |
675 | |
676 | |
677 /** | |
678 * Clone an object/array (recursively) | |
679 * @param {Object} proto Object to clone. | |
680 * @return {Object} Clone of x;. | |
681 */ | |
682 goog.cloneObject = function(proto) { | |
683 var type = goog.typeOf(proto); | |
684 if (type == 'object' || type == 'array') { | |
685 if (proto.clone) { | |
686 return proto.clone(); | |
687 } | |
688 var clone = type == 'array' ? [] : {}; | |
689 for (var key in proto) { | |
690 clone[key] = goog.cloneObject(proto[key]); | |
691 } | |
692 return clone; | |
693 } | |
694 | |
695 return proto; | |
696 }; | |
697 | |
698 | |
699 /** | |
700 * Partially applies this function to a particular 'this object' and zero or | |
701 * more arguments. The result is a new function with some arguments of the first | |
702 * function pre-filled and the value of |this| 'pre-specified'.<br><br> | |
703 * | |
704 * Remaining arguments specified at call-time are appended to the pre- | |
705 * specified ones.<br><br> | |
706 * | |
707 * Also see: {@link #partial}.<br><br> | |
708 * | |
709 * Note that bind and partial are optimized such that repeated calls to it do | |
710 * not create more than one function object, so there is no additional cost for | |
711 * something like:<br> | |
712 * | |
713 * <pre>var g = bind(f, obj); | |
714 * var h = partial(g, 1, 2, 3); | |
715 * var k = partial(h, a, b, c);</pre> | |
716 * | |
717 * Usage: | |
718 * <pre>var barMethBound = bind(myFunction, myObj, 'arg1', 'arg2'); | |
719 * barMethBound('arg3', 'arg4');</pre> | |
720 * | |
721 * @param {Function} fn A function to partially apply. | |
722 * @param {Object} self Specifies the object which |this| should point to | |
723 * when the function is run. If the value is null or undefined, it will | |
724 * default to the global object. | |
725 * @param {Object} var_args Additional arguments that are partially | |
726 * applied to the function. | |
727 * | |
728 * @return {Function} A partially-applied form of the function bind() was | |
729 * invoked as a method of. | |
730 */ | |
731 goog.bind = function(fn, self, var_args) { | |
732 var boundArgs = fn.boundArgs_; | |
733 | |
734 if (arguments.length > 2) { | |
735 var args = Array.prototype.slice.call(arguments, 2); | |
736 if (boundArgs) { | |
737 args.unshift.apply(args, boundArgs); | |
738 } | |
739 boundArgs = args; | |
740 } | |
741 | |
742 self = fn.boundSelf_ || self; | |
743 fn = fn.boundFn_ || fn; | |
744 | |
745 var newfn; | |
746 var context = self || goog.global; | |
747 | |
748 if (boundArgs) { | |
749 newfn = function() { | |
750 // Combine the static args and the new args into one big array | |
751 var args = Array.prototype.slice.call(arguments); | |
752 args.unshift.apply(args, boundArgs); | |
753 return fn.apply(context, args); | |
754 } | |
755 } else { | |
756 newfn = function() { | |
757 return fn.apply(context, arguments); | |
758 } | |
759 } | |
760 | |
761 newfn.boundArgs_ = boundArgs; | |
762 newfn.boundSelf_ = self; | |
763 newfn.boundFn_ = fn; | |
764 | |
765 return newfn; | |
766 }; | |
767 | |
768 | |
769 /** | |
770 * Like bind(), except that a 'this object' is not required. Useful when the | |
771 * target function is already bound. | |
772 * | |
773 * Usage: | |
774 * var g = partial(f, arg1, arg2); | |
775 * g(arg3, arg4); | |
776 * | |
777 * @param {Function} fn A function to partially apply. | |
778 * @param {Object} var_args Additional arguments that are partially | |
779 * applied to fn. | |
780 * @return {Function} A partially-applied form of the function bind() was | |
781 * invoked as a method of. | |
782 */ | |
783 goog.partial = function(fn, var_args) { | |
784 var args = Array.prototype.slice.call(arguments, 1); | |
785 args.unshift(fn, null); | |
786 return goog.bind.apply(null, args); | |
787 }; | |
788 | |
789 | |
790 /** | |
791 * Copies all the members of a source object to a target object. | |
792 * This is deprecated. Use goog.object.extend instead. | |
793 * @param {Object} target Target. | |
794 * @param {Object} source Source. | |
795 * @deprecated | |
796 */ | |
797 goog.mixin = function(target, source) { | |
798 for (var x in source) { | |
799 target[x] = source[x]; | |
800 } | |
801 | |
802 // For IE the for-in-loop does not contain any properties that are not | |
803 // enumerable on the prototype object (for example, isPrototypeOf from | |
804 // Object.prototype) but also it will not include 'replace' on objects that | |
805 // extend String and change 'replace' (not that it is common for anyone to | |
806 // extend anything except Object). | |
807 }; | |
808 | |
809 | |
810 /** | |
811 * A simple wrapper for new Date().getTime(). | |
812 * | |
813 * @return {number} An integer value representing the number of milliseconds | |
814 * between midnight, January 1, 1970 and the current time. | |
815 */ | |
816 goog.now = Date.now || (function() { | |
817 return new Date().getTime(); | |
818 }); | |
819 | |
820 | |
821 /** | |
822 * Abstract implementation of goog.getMsg for use with localized messages | |
823 * @param {string} str Translatable string, places holders in the form.{$foo} | |
824 * @param {Object} opt_values Map of place holder name to value. | |
825 */ | |
826 goog.getMsg = function(str, opt_values) { | |
827 var values = opt_values || {}; | |
828 for (var key in values) { | |
829 str = str.replace(new RegExp('\\{\\$' + key + '\\}', 'gi'), values[key]); | |
830 } | |
831 return str; | |
832 }; | |
833 | |
834 | |
835 /** | |
836 * Exposes an unobfuscated global namespace path for the given object. | |
837 * Note that fields of the exported object *will* be obfuscated, | |
838 * unless they are exported in turn via this function or | |
839 * goog.exportProperty | |
840 * | |
841 * <p>Also handy for making public items that are defined in anonymous | |
842 * closures. | |
843 * | |
844 * ex. goog.exportSymbol('Foo', Foo); | |
845 * | |
846 * ex. goog.exportSymbol('public.path.Foo.staticFunction', | |
847 * Foo.staticFunction); | |
848 * public.path.Foo.staticFunction(); | |
849 * | |
850 * ex. goog.exportSymbol('public.path.Foo.prototype.myMethod', | |
851 * Foo.prototype.myMethod); | |
852 * new public.path.Foo().myMethod(); | |
853 * | |
854 * @param {string} publicPath Unobfuscated name to export. | |
855 * @param {Object} object Object the name should point to. | |
856 */ | |
857 goog.exportSymbol = function(publicPath, object) { | |
858 goog.exportPath_(publicPath, object); | |
859 }; | |
860 | |
861 | |
862 /** | |
863 * Exports a property unobfuscated into the object's namespace. | |
864 * ex. goog.exportProperty(Foo, 'staticFunction', Foo.staticFunction); | |
865 * ex. goog.exportProperty(Foo.prototype, 'myMethod', Foo.prototype.myMethod); | |
866 * @param {Object} object Object whose static property is being exported. | |
867 * @param {string} publicName Unobfuscated name to export. | |
868 * @param {Object} symbol Object the name should point to. | |
869 */ | |
870 goog.exportProperty = function(object, publicName, symbol) { | |
871 object[publicName] = symbol; | |
872 }; | |
873 | |
874 | |
875 | |
876 //============================================================================== | |
877 // Extending Function | |
878 //============================================================================== | |
879 | |
880 | |
881 /** | |
882 * An alias to the {@link goog.bind()} global function. | |
883 * | |
884 * Usage: | |
885 * var g = f.bind(obj, arg1, arg2); | |
886 * g(arg3, arg4); | |
887 * | |
888 * @param {Object} self Specifies the object to which |this| should point | |
889 * when the function is run. If the value is null or undefined, it will | |
890 * default to the global object. | |
891 * @param {Object} var_args Additional arguments that are partially | |
892 * applied to fn. | |
893 * @return {Function} A partially-applied form of the Function on which bind() | |
894 * was invoked as a method. | |
895 * @deprecated | |
896 */ | |
897 Function.prototype.bind = function(self, var_args) { | |
898 if (arguments.length > 1) { | |
899 var args = Array.prototype.slice.call(arguments, 1); | |
900 args.unshift(this, self); | |
901 return goog.bind.apply(null, args); | |
902 } else { | |
903 return goog.bind(this, self); | |
904 } | |
905 }; | |
906 | |
907 | |
908 /** | |
909 * An alias to the {@link goog.partial()} global function. | |
910 * | |
911 * Usage: | |
912 * var g = f.partial(arg1, arg2); | |
913 * g(arg3, arg4); | |
914 * | |
915 * @param {Object} var_args Additional arguments that are partially | |
916 * applied to fn. | |
917 * @return {Function} A partially-applied form of the function partial() was | |
918 * invoked as a method of. | |
919 * @deprecated | |
920 */ | |
921 Function.prototype.partial = function(var_args) { | |
922 var args = Array.prototype.slice.call(arguments); | |
923 args.unshift(this, null); | |
924 return goog.bind.apply(null, args); | |
925 }; | |
926 | |
927 | |
928 /** | |
929 * Inherit the prototype methods from one constructor into another. | |
930 * | |
931 * Usage: | |
932 * <pre> | |
933 * function ParentClass(a, b) { } | |
934 * ParentClass.prototype.foo = function(a) { } | |
935 * | |
936 * function ChildClass(a, b, c) { | |
937 * ParentClass.call(this, a, b); | |
938 * } | |
939 * | |
940 * ChildClass.inherits(ParentClass); | |
941 * | |
942 * var child = new ChildClass('a', 'b', 'see'); | |
943 * child.foo(); // works | |
944 * </pre> | |
945 * | |
946 * In addition, a superclass' implementation of a method can be invoked | |
947 * as follows: | |
948 * | |
949 * <pre> | |
950 * ChildClass.prototype.foo = function(a) { | |
951 * ChildClass.superClass_.foo.call(this, a); | |
952 * // other code | |
953 * }; | |
954 * </pre> | |
955 * | |
956 * @param {Function} parentCtor Parent class. | |
957 */ | |
958 Function.prototype.inherits = function(parentCtor) { | |
959 goog.inherits(this, parentCtor); | |
960 }; | |
961 | |
962 | |
963 /** | |
964 * Static variant of Function.prototype.inherits. | |
965 * @param {Function} childCtor Child class. | |
966 * @param {Function} parentCtor Parent class. | |
967 */ | |
968 goog.inherits = function(childCtor, parentCtor) { | |
969 /** @constructor */ | |
970 function tempCtor() {}; | |
971 tempCtor.prototype = parentCtor.prototype; | |
972 childCtor.superClass_ = parentCtor.prototype; | |
973 childCtor.prototype = new tempCtor(); | |
974 childCtor.prototype.constructor = childCtor; | |
975 }; | |
976 | |
977 | |
978 /** | |
979 * Mixes in an object's properties and methods into the callee's prototype. | |
980 * Basically mixin based inheritance, thus providing an alternative method for | |
981 * adding properties and methods to a class' prototype. | |
982 * | |
983 * <pre> | |
984 * function X() {} | |
985 * X.mixin({ | |
986 * one: 1, | |
987 * two: 2, | |
988 * three: 3, | |
989 * doit: function() { return this.one + this.two + this.three; } | |
990 * }); | |
991 * | |
992 * function Y() { } | |
993 * Y.mixin(X.prototype); | |
994 * Y.prototype.four = 15; | |
995 * Y.prototype.doit2 = function() { return this.doit() + this.four; } | |
996 * }); | |
997 * | |
998 * // or | |
999 * | |
1000 * function Y() { } | |
1001 * Y.inherits(X); | |
1002 * Y.mixin({ | |
1003 * one: 10, | |
1004 * four: 15, | |
1005 * doit2: function() { return this.doit() + this.four; } | |
1006 * }); | |
1007 * </pre> | |
1008 * | |
1009 * @param {Object} source from which to copy properties. | |
1010 * @see goog.mixin | |
1011 * @deprecated | |
1012 */ | |
1013 Function.prototype.mixin = function(source) { | |
1014 goog.mixin(this.prototype, source); | |
1015 }; | |
OLD | NEW |