1 // Copyright 2006 The Closure Library Authors. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS-IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 /** 16 * @fileoverview Bootstrap for the Google JS Library (Closure). 17 * 18 * In uncompiled mode base.js will write out Closure's deps file, unless the 19 * global <code>CLOSURE_NO_DEPS</code> is set to true. This allows projects to 20 * include their own deps file(s) from different locations. 21 * 22 * 23 * 24 */ 25 26 /** 27 * @define {boolean} Overridden to true by the compiler when --closure_pass 28 * or --mark_as_compiled is specified. 29 */ 30 var COMPILED = false; 31 32 33 /** 34 * Base namespace for the Closure library. Checks to see goog is 35 * already defined in the current scope before assigning to prevent 36 * clobbering if base.js is loaded more than once. 37 */ 38 var goog = goog || {}; // Check to see if already defined in current scope 39 40 41 /** 42 * Reference to the global context. In most cases this will be 'window'. 43 */ 44 goog.global = this; 45 46 47 /** 48 * @define {boolean} DEBUG is provided as a convenience so that debugging code 49 * that should not be included in a production js_binary can be easily stripped 50 * by specifying --define goog.DEBUG=false to the JSCompiler. For example, most 51 * toString() methods should be declared inside an "if (goog.DEBUG)" conditional 52 * because they are generally used for debugging purposes and it is difficult 53 * for the JSCompiler to statically determine whether they are used. 54 */ 55 goog.DEBUG = true; 56 57 58 /** 59 * @define {string} LOCALE defines the locale being used for compilation. It is 60 * used to select locale specific data to be compiled in js binary. BUILD rule 61 * can specify this value by "--define goog.LOCALE=<locale_name>" as JSCompiler 62 * option. 63 * 64 * Take into account that the locale code format is important. You should use 65 * the canonical Unicode format with hyphen as a delimiter. Language must be 66 * lowercase, Language Script - Capitalized, Region - UPPERCASE. 67 * There are few examples: pt-BR, en, en-US, sr-Latin-BO, zh-Hans-CN. 68 * 69 * See more info about locale codes here: 70 * http://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers 71 * 72 * For language codes you should use values defined by ISO 693-1. See it here 73 * http://www.w3.org/WAI/ER/IG/ert/iso639.htm. There is only one exception from 74 * this rule: the Hebrew language. For legacy reasons the old code (iw) should 75 * be used instead of the new code (he), see http://wiki/Main/IIISynonyms. 76 */ 77 goog.LOCALE = 'en'; // default to en 78 79 80 /** 81 * Indicates whether or not we can call 'eval' directly to eval code in the 82 * global scope. Set to a Boolean by the first call to goog.globalEval (which 83 * empirically tests whether eval works for globals). @see goog.globalEval 84 * @type {?boolean} 85 * @private 86 */ 87 goog.evalWorksForGlobals_ = null; 88 89 90 /** 91 * Creates object stubs for a namespace. When present in a file, goog.provide 92 * also indicates that the file defines the indicated object. Calls to 93 * goog.provide are resolved by the compiler if --closure_pass is set. 94 * @param {string} name name of the object that this file defines. 95 */ 96 goog.provide = function(name) { 97 if (!COMPILED) { 98 // Ensure that the same namespace isn't provided twice. This is intended 99 // to teach new developers that 'goog.provide' is effectively a variable 100 // declaration. And when JSCompiler transforms goog.provide into a real 101 // variable declaration, the compiled JS should work the same as the raw 102 // JS--even when the raw JS uses goog.provide incorrectly. 103 if (goog.getObjectByName(name) && !goog.implicitNamespaces_[name]) { 104 throw Error('Namespace "' + name + '" already declared.'); 105 } 106 107 var namespace = name; 108 while ((namespace = namespace.substring(0, namespace.lastIndexOf('.')))) { 109 goog.implicitNamespaces_[namespace] = true; 110 } 111 } 112 113 goog.exportPath_(name); 114 }; 115 116 117 if (!COMPILED) { 118 /** 119 * Namespaces implicitly defined by goog.provide. For example, 120 * goog.provide('goog.events.Event') implicitly declares 121 * that 'goog' and 'goog.events' must be namespaces. 122 * 123 * @type {Object} 124 * @private 125 */ 126 goog.implicitNamespaces_ = {}; 127 } 128 129 130 /** 131 * Builds an object structure for the provided namespace path, 132 * ensuring that names that already exist are not overwritten. For 133 * example: 134 * "a.b.c" -> a = {};a.b={};a.b.c={}; 135 * Used by goog.provide and goog.exportSymbol. 136 * @param {string} name name of the object that this file defines. 137 * @param {*=} opt_object the object to expose at the end of the path. 138 * @param {Object=} opt_objectToExportTo The object to add the path to; default 139 * is |goog.global|. 140 * @private 141 */ 142 goog.exportPath_ = function(name, opt_object, opt_objectToExportTo) { 143 var parts = name.split('.'); 144 var cur = opt_objectToExportTo || goog.global; 145 146 // Internet Explorer exhibits strange behavior when throwing errors from 147 // methods externed in this manner. See the testExportSymbolExceptions in 148 // base_test.html for an example. 149 if (!(parts[0] in cur) && cur.execScript) { 150 cur.execScript('var ' + parts[0]); 151 } 152 153 // Certain browsers cannot parse code in the form for((a in b); c;); 154 // This pattern is produced by the JSCompiler when it collapses the 155 // statement above into the conditional loop below. To prevent this from 156 // happening, use a for-loop and reserve the init logic as below. 157 158 // Parentheses added to eliminate strict JS warning in Firefox. 159 for (var part; parts.length && (part = parts.shift());) { 160 if (!parts.length && goog.isDef(opt_object)) { 161 // last part and we have an object; use it 162 cur[part] = opt_object; 163 } else if (cur[part]) { 164 cur = cur[part]; 165 } else { 166 cur = cur[part] = {}; 167 } 168 } 169 }; 170 171 172 /** 173 * Returns an object based on its fully qualified external name. If you are 174 * using a compilation pass that renames property names beware that using this 175 * function will not find renamed properties. 176 * 177 * @param {string} name The fully qualified name. 178 * @param {Object=} opt_obj The object within which to look; default is 179 * |goog.global|. 180 * @return {Object} The object or, if not found, null. 181 */ 182 goog.getObjectByName = function(name, opt_obj) { 183 var parts = name.split('.'); 184 var cur = opt_obj || goog.global; 185 for (var part; part = parts.shift(); ) { 186 if (cur[part]) { 187 cur = cur[part]; 188 } else { 189 return null; 190 } 191 } 192 return cur; 193 }; 194 195 196 /** 197 * Globalizes a whole namespace, such as goog or goog.lang. 198 * 199 * @param {Object} obj The namespace to globalize. 200 * @param {Object=} opt_global The object to add the properties to. 201 * @deprecated Properties may be explicitly exported to the global scope, but 202 * this should no longer be done in bulk. 203 */ 204 goog.globalize = function(obj, opt_global) { 205 var global = opt_global || goog.global; 206 for (var x in obj) { 207 global[x] = obj[x]; 208 } 209 }; 210 211 212 /** 213 * Adds a dependency from a file to the files it requires. 214 * @param {string} relPath The path to the js file. 215 * @param {Array} provides An array of strings with the names of the objects 216 * this file provides. 217 * @param {Array} requires An array of strings with the names of the objects 218 * this file requires. 219 */ 220 goog.addDependency = function(relPath, provides, requires) { 221 if (!COMPILED) { 222 var provide, require; 223 var path = relPath.replace(/\\/g, '/'); 224 var deps = goog.dependencies_; 225 for (var i = 0; provide = provides[i]; i++) { 226 deps.nameToPath[provide] = path; 227 if (!(path in deps.pathToNames)) { 228 deps.pathToNames[path] = {}; 229 } 230 deps.pathToNames[path][provide] = true; 231 } 232 for (var j = 0; require = requires[j]; j++) { 233 if (!(path in deps.requires)) { 234 deps.requires[path] = {}; 235 } 236 deps.requires[path][require] = true; 237 } 238 } 239 }; 240 241 242 243 /** 244 * Implements a system for the dynamic resolution of dependencies 245 * that works in parallel with the BUILD system. Note that all calls 246 * to goog.require will be stripped by the JSCompiler when the 247 * --closure_pass option is used. 248 * @param {string} rule Rule to include, in the form goog.package.part. 249 */ 250 goog.require = function(rule) { 251 252 // if the object already exists we do not need do do anything 253 // TODO(user): If we start to support require based on file name this has 254 // to change 255 // TODO(user): If we allow goog.foo.* this has to change 256 // TODO(user): If we implement dynamic load after page load we should probably 257 // not remove this code for the compiled output 258 if (!COMPILED) { 259 if (goog.getObjectByName(rule)) { 260 return; 261 } 262 var path = goog.getPathFromDeps_(rule); 263 if (path) { 264 goog.included_[path] = true; 265 goog.writeScripts_(); 266 } else { 267 var errorMessage = 'goog.require could not find: ' + rule; 268 if (goog.global.console) { 269 goog.global.console['error'](errorMessage); 270 } 271 272 273 throw Error(errorMessage); 274 275 } 276 } 277 }; 278 279 280 /** 281 * Path for included scripts 282 * @type {string} 283 */ 284 goog.basePath = ''; 285 286 287 /** 288 * A hook for overriding the base path. 289 * @type {string|undefined} 290 */ 291 goog.global.CLOSURE_BASE_PATH; 292 293 294 /** 295 * Whether to write out Closure's deps file. By default, 296 * the deps are written. 297 * @type {boolean|undefined} 298 */ 299 goog.global.CLOSURE_NO_DEPS; 300 301 302 /** 303 * Null function used for default values of callbacks, etc. 304 * @type {!Function} 305 */ 306 goog.nullFunction = function() {}; 307 308 309 /** 310 * The identity function. Returns its first argument. 311 * 312 * @param {...*} var_args The arguments of the function. 313 * @return {*} The first argument. 314 * @deprecated Use goog.functions.identity instead. 315 */ 316 goog.identityFunction = function(var_args) { 317 return arguments[0]; 318 }; 319 320 321 /** 322 * When defining a class Foo with an abstract method bar(), you can do: 323 * 324 * Foo.prototype.bar = goog.abstractMethod 325 * 326 * Now if a subclass of Foo fails to override bar(), an error 327 * will be thrown when bar() is invoked. 328 * 329 * Note: This does not take the name of the function to override as 330 * an argument because that would make it more difficult to obfuscate 331 * our JavaScript code. 332 * 333 * @type {!Function} 334 * @throws {Error} when invoked to indicate the method should be 335 * overridden. 336 */ 337 goog.abstractMethod = function() { 338 throw Error('unimplemented abstract method'); 339 }; 340 341 342 /** 343 * Adds a {@code getInstance} static method that always return the same instance 344 * object. 345 * @param {!Function} ctor The constructor for the class to add the static 346 * method to. 347 */ 348 goog.addSingletonGetter = function(ctor) { 349 ctor.getInstance = function() { 350 return ctor.instance_ || (ctor.instance_ = new ctor()); 351 }; 352 }; 353 354 355 if (!COMPILED) { 356 /** 357 * Object used to keep track of urls that have already been added. This 358 * record allows the prevention of circular dependencies. 359 * @type {Object} 360 * @private 361 */ 362 goog.included_ = {}; 363 364 365 /** 366 * This object is used to keep track of dependencies and other data that is 367 * used for loading scripts 368 * @private 369 * @type {Object} 370 */ 371 goog.dependencies_ = { 372 pathToNames: {}, // 1 to many 373 nameToPath: {}, // 1 to 1 374 requires: {}, // 1 to many 375 visited: {}, // used when resolving dependencies to prevent us from 376 // visiting the file twice 377 written: {} // used to keep track of script files we have written 378 }; 379 380 381 /** 382 * Tries to detect whether is in the context of an HTML document. 383 * @return {boolean} True if it looks like HTML document. 384 * @private 385 */ 386 goog.inHtmlDocument_ = function() { 387 var doc = goog.global.document; 388 return typeof doc != 'undefined' && 389 'write' in doc; // XULDocument misses write. 390 }; 391 392 393 /** 394 * Tries to detect the base path of the base.js script that bootstraps Closure 395 * @private 396 */ 397 goog.findBasePath_ = function() { 398 if (!goog.inHtmlDocument_()) { 399 return; 400 } 401 var doc = goog.global.document; 402 if (goog.global.CLOSURE_BASE_PATH) { 403 goog.basePath = goog.global.CLOSURE_BASE_PATH; 404 return; 405 } 406 var scripts = doc.getElementsByTagName('script'); 407 // Search backwards since the current script is in almost all cases the one 408 // that has base.js. 409 for (var i = scripts.length - 1; i >= 0; --i) { 410 var src = scripts[i].src; 411 var l = src.length; 412 if (src.substr(l - 7) == 'base.js') { 413 goog.basePath = src.substr(0, l - 7); 414 return; 415 } 416 } 417 }; 418 419 420 /** 421 * Writes a script tag if, and only if, that script hasn't already been added 422 * to the document. (Must be called at execution time) 423 * @param {string} src Script source. 424 * @private 425 */ 426 goog.writeScriptTag_ = function(src) { 427 if (goog.inHtmlDocument_() && 428 !goog.dependencies_.written[src]) { 429 goog.dependencies_.written[src] = true; 430 var doc = goog.global.document; 431 doc.write('<script type="text/javascript" src="' + 432 src + '"></' + 'script>'); 433 } 434 }; 435 436 437 /** 438 * Resolves dependencies based on the dependencies added using addDependency 439 * and calls writeScriptTag_ in the correct order. 440 * @private 441 */ 442 goog.writeScripts_ = function() { 443 // the scripts we need to write this time 444 var scripts = []; 445 var seenScript = {}; 446 var deps = goog.dependencies_; 447 448 function visitNode(path) { 449 if (path in deps.written) { 450 return; 451 } 452 453 // we have already visited this one. We can get here if we have cyclic 454 // dependencies 455 if (path in deps.visited) { 456 if (!(path in seenScript)) { 457 seenScript[path] = true; 458 scripts.push(path); 459 } 460 return; 461 } 462 463 deps.visited[path] = true; 464 465 if (path in deps.requires) { 466 for (var requireName in deps.requires[path]) { 467 if (requireName in deps.nameToPath) { 468 visitNode(deps.nameToPath[requireName]); 469 } else if (!goog.getObjectByName(requireName)) { 470 // If the required name is defined, we assume that this 471 // dependency was bootstapped by other means. Otherwise, 472 // throw an exception. 473 throw Error('Undefined nameToPath for ' + requireName); 474 } 475 } 476 } 477 478 if (!(path in seenScript)) { 479 seenScript[path] = true; 480 scripts.push(path); 481 } 482 } 483 484 for (var path in goog.included_) { 485 if (!deps.written[path]) { 486 visitNode(path); 487 } 488 } 489 490 for (var i = 0; i < scripts.length; i++) { 491 if (scripts[i]) { 492 493 goog.writeScriptTag_(goog.basePath + scripts[i]); 494 } else { 495 throw Error('Undefined script input'); 496 } 497 } 498 }; 499 500 501 /** 502 * Looks at the dependency rules and tries to determine the script file that 503 * fulfills a particular rule. 504 * @param {string} rule In the form goog.namespace.Class or project.script. 505 * @return {?string} Url corresponding to the rule, or null. 506 * @private 507 */ 508 goog.getPathFromDeps_ = function(rule) { 509 if (rule in goog.dependencies_.nameToPath) { 510 return goog.dependencies_.nameToPath[rule]; 511 } else { 512 return null; 513 } 514 }; 515 516 goog.findBasePath_(); 517 518 // Allow projects to manage the deps files themselves. 519 if (!goog.global.CLOSURE_NO_DEPS) { 520 goog.writeScriptTag_(goog.basePath + 'deps.js'); 521 } 522 } 523 524 525 526 //============================================================================== 527 // Language Enhancements 528 //============================================================================== 529 530 531 /** 532 * This is a "fixed" version of the typeof operator. It differs from the typeof 533 * operator in such a way that null returns 'null' and arrays return 'array'. 534 * @param {*} value The value to get the type of. 535 * @return {string} The name of the type. 536 */ 537 goog.typeOf = function(value) { 538 var s = typeof value; 539 if (s == 'object') { 540 if (value) { 541 // We cannot use constructor == Array or instanceof Array because 542 // different frames have different Array objects. In IE6, if the iframe 543 // where the array was created is destroyed, the array loses its 544 // prototype. Then dereferencing val.splice here throws an exception, so 545 // we can't use goog.isFunction. Calling typeof directly returns 'unknown' 546 // so that will work. In this case, this function will return false and 547 // most array functions will still work because the array is still 548 // array-like (supports length and []) even though it has lost its 549 // prototype. 550 // Mark Miller noticed that Object.prototype.toString 551 // allows access to the unforgeable [[Class]] property. 552 // 15.2.4.2 Object.prototype.toString ( ) 553 // When the toString method is called, the following steps are taken: 554 // 1. Get the [[Class]] property of this object. 555 // 2. Compute a string value by concatenating the three strings 556 // "[object ", Result(1), and "]". 557 // 3. Return Result(2). 558 // and this behavior survives the destruction of the execution context. 559 if (value instanceof Array || // Works quickly in same execution context. 560 // If value is from a different execution context then 561 // !(value instanceof Object), which lets us early out in the common 562 // case when value is from the same context but not an array. 563 // The {if (value)} check above means we don't have to worry about 564 // undefined behavior of Object.prototype.toString on null/undefined. 565 // 566 // HACK: In order to use an Object prototype method on the arbitrary 567 // value, the compiler requires the value be cast to type Object, 568 // even though the ECMA spec explicitly allows it. 569 (!(value instanceof Object) && 570 (Object.prototype.toString.call( 571 /** @type {Object} */ (value)) == '[object Array]') || 572 573 // In IE all non value types are wrapped as objects across window 574 // boundaries (not iframe though) so we have to do object detection 575 // for this edge case 576 typeof value.length == 'number' && 577 typeof value.splice != 'undefined' && 578 typeof value.propertyIsEnumerable != 'undefined' && 579 !value.propertyIsEnumerable('splice') 580 581 )) { 582 return 'array'; 583 } 584 // HACK: There is still an array case that fails. 585 // function ArrayImpostor() {} 586 // ArrayImpostor.prototype = []; 587 // var impostor = new ArrayImpostor; 588 // this can be fixed by getting rid of the fast path 589 // (value instanceof Array) and solely relying on 590 // (value && Object.prototype.toString.vall(value) === '[object Array]') 591 // but that would require many more function calls and is not warranted 592 // unless closure code is receiving objects from untrusted sources. 593 594 // IE in cross-window calls does not correctly marshal the function type 595 // (it appears just as an object) so we cannot use just typeof val == 596 // 'function'. However, if the object has a call property, it is a 597 // function. 598 if (!(value instanceof Object) && 599 (Object.prototype.toString.call( 600 /** @type {Object} */ (value)) == '[object Function]' || 601 typeof value.call != 'undefined' && 602 typeof value.propertyIsEnumerable != 'undefined' && 603 !value.propertyIsEnumerable('call'))) { 604 return 'function'; 605 } 606 607 608 } else { 609 return 'null'; 610 } 611 612 // In Safari typeof nodeList returns 'function', and on Firefox 613 // typeof behaves similarly for HTML{Applet,Embed,Object}Elements 614 // and RegExps. We would like to return object for those and we can 615 // detect an invalid function by making sure that the function 616 // object has a call method. 617 } else if (s == 'function' && typeof value.call == 'undefined') { 618 return 'object'; 619 } 620 return s; 621 }; 622 623 624 /** 625 * Safe way to test whether a property is enumarable. It allows testing 626 * for enumerable on objects where 'propertyIsEnumerable' is overridden or 627 * does not exist (like DOM nodes in IE). Does not use browser native 628 * Object.propertyIsEnumerable. 629 * @param {Object} object The object to test if the property is enumerable. 630 * @param {string} propName The property name to check for. 631 * @return {boolean} True if the property is enumarable. 632 * @private 633 */ 634 goog.propertyIsEnumerableCustom_ = function(object, propName) { 635 // KJS in Safari 2 is not ECMAScript compatible and lacks crucial methods 636 // such as propertyIsEnumerable. We therefore use a workaround. 637 // Does anyone know a more efficient work around? 638 if (propName in object) { 639 for (var key in object) { 640 if (key == propName && 641 Object.prototype.hasOwnProperty.call(object, propName)) { 642 return true; 643 } 644 } 645 } 646 return false; 647 }; 648 649 650 /** 651 * Safe way to test whether a property is enumarable. It allows testing 652 * for enumerable on objects where 'propertyIsEnumerable' is overridden or 653 * does not exist (like DOM nodes in IE). 654 * @param {Object} object The object to test if the property is enumerable. 655 * @param {string} propName The property name to check for. 656 * @return {boolean} True if the property is enumarable. 657 * @private 658 */ 659 goog.propertyIsEnumerable_ = function(object, propName) { 660 // In IE if object is from another window, cannot use propertyIsEnumerable 661 // from this window's Object. Will raise a 'JScript object expected' error. 662 if (object instanceof Object) { 663 return Object.prototype.propertyIsEnumerable.call(object, propName); 664 } else { 665 return goog.propertyIsEnumerableCustom_(object, propName); 666 } 667 }; 668 669 670 /** 671 * Returns true if the specified value is not |undefined|. 672 * WARNING: Do not use this to test if an object has a property. Use the in 673 * operator instead. Additionally, this function assumes that the global 674 * undefined variable has not been redefined. 675 * @param {*} val Variable to test. 676 * @return {boolean} Whether variable is defined. 677 */ 678 goog.isDef = function(val) { 679 return val !== undefined; 680 }; 681 682 683 /** 684 * Returns true if the specified value is |null| 685 * @param {*} val Variable to test. 686 * @return {boolean} Whether variable is null. 687 */ 688 goog.isNull = function(val) { 689 return val === null; 690 }; 691 692 693 /** 694 * Returns true if the specified value is defined and not null 695 * @param {*} val Variable to test. 696 * @return {boolean} Whether variable is defined and not null. 697 */ 698 goog.isDefAndNotNull = function(val) { 699 // Note that undefined == null. 700 return val != null; 701 }; 702 703 704 /** 705 * Returns true if the specified value is an array 706 * @param {*} val Variable to test. 707 * @return {boolean} Whether variable is an array. 708 */ 709 goog.isArray = function(val) { 710 return goog.typeOf(val) == 'array'; 711 }; 712 713 714 /** 715 * Returns true if the object looks like an array. To qualify as array like 716 * the value needs to be either a NodeList or an object with a Number length 717 * property. 718 * @param {*} val Variable to test. 719 * @return {boolean} Whether variable is an array. 720 */ 721 goog.isArrayLike = function(val) { 722 var type = goog.typeOf(val); 723 return type == 'array' || type == 'object' && typeof val.length == 'number'; 724 }; 725 726 727 /** 728 * Returns true if the object looks like a Date. To qualify as Date-like 729 * the value needs to be an object and have a getFullYear() function. 730 * @param {*} val Variable to test. 731 * @return {boolean} Whether variable is a like a Date. 732 */ 733 goog.isDateLike = function(val) { 734 return goog.isObject(val) && typeof val.getFullYear == 'function'; 735 }; 736 737 738 /** 739 * Returns true if the specified value is a string 740 * @param {*} val Variable to test. 741 * @return {boolean} Whether variable is a string. 742 */ 743 goog.isString = function(val) { 744 return typeof val == 'string'; 745 }; 746 747 748 /** 749 * Returns true if the specified value is a boolean 750 * @param {*} val Variable to test. 751 * @return {boolean} Whether variable is boolean. 752 */ 753 goog.isBoolean = function(val) { 754 return typeof val == 'boolean'; 755 }; 756 757 758 /** 759 * Returns true if the specified value is a number 760 * @param {*} val Variable to test. 761 * @return {boolean} Whether variable is a number. 762 */ 763 goog.isNumber = function(val) { 764 return typeof val == 'number'; 765 }; 766 767 768 /** 769 * Returns true if the specified value is a function 770 * @param {*} val Variable to test. 771 * @return {boolean} Whether variable is a function. 772 */ 773 goog.isFunction = function(val) { 774 return goog.typeOf(val) == 'function'; 775 }; 776 777 778 /** 779 * Returns true if the specified value is an object. This includes arrays 780 * and functions. 781 * @param {*} val Variable to test. 782 * @return {boolean} Whether variable is an object. 783 */ 784 goog.isObject = function(val) { 785 var type = goog.typeOf(val); 786 return type == 'object' || type == 'array' || type == 'function'; 787 }; 788 789 790 /** 791 * Gets a unique ID for an object. This mutates the object so that further 792 * calls with the same object as a parameter returns the same value. The unique 793 * ID is guaranteed to be unique across the current session amongst objects that 794 * are passed into {@code getUid}. There is no guarantee that the ID is unique 795 * or consistent across sessions. 796 * 797 * @param {Object} obj The object to get the unique ID for. 798 * @return {number} The unique ID for the object. 799 */ 800 goog.getUid = function(obj) { 801 // TODO(user): Make the type stricter, do not accept null. 802 803 // In IE, DOM nodes do not extend Object so they do not have this method. 804 // we need to check hasOwnProperty because the proto might have this set. 805 if (obj.hasOwnProperty && obj.hasOwnProperty(goog.UID_PROPERTY_)) { 806 return obj[goog.UID_PROPERTY_]; 807 } 808 if (!obj[goog.UID_PROPERTY_]) { 809 obj[goog.UID_PROPERTY_] = ++goog.uidCounter_; 810 } 811 return obj[goog.UID_PROPERTY_]; 812 }; 813 814 815 /** 816 * Removes the unique ID from an object. This is useful if the object was 817 * previously mutated using {@code goog.getUid} in which case the mutation is 818 * undone. 819 * @param {Object} obj The object to remove the unique ID field from. 820 */ 821 goog.removeUid = function(obj) { 822 // TODO(user): Make the type stricter, do not accept null. 823 824 // DOM nodes in IE are not instance of Object and throws exception 825 // for delete. Instead we try to use removeAttribute 826 if ('removeAttribute' in obj) { 827 obj.removeAttribute(goog.UID_PROPERTY_); 828 } 829 /** @preserveTry */ 830 try { 831 delete obj[goog.UID_PROPERTY_]; 832 } catch (ex) { 833 } 834 }; 835 836 837 /** 838 * Name for unique ID property. Initialized in a way to help avoid collisions 839 * with other closure javascript on the same page. 840 * @type {string} 841 * @private 842 */ 843 goog.UID_PROPERTY_ = 'closure_uid_' + 844 Math.floor(Math.random() * 2147483648).toString(36); 845 846 847 /** 848 * Counter for UID. 849 * @type {number} 850 * @private 851 */ 852 goog.uidCounter_ = 0; 853 854 855 /** 856 * Adds a hash code field to an object. The hash code is unique for the 857 * given object. 858 * @param {Object} obj The object to get the hash code for. 859 * @return {number} The hash code for the object. 860 * @deprecated Use goog.getUid instead. 861 */ 862 goog.getHashCode = goog.getUid; 863 864 865 /** 866 * Removes the hash code field from an object. 867 * @param {Object} obj The object to remove the field from. 868 * @deprecated Use goog.removeUid instead. 869 */ 870 goog.removeHashCode = goog.removeUid; 871 872 873 /** 874 * Clones a value. The input may be an Object, Array, or basic type. Objects and 875 * arrays will be cloned recursively. 876 * 877 * WARNINGS: 878 * <code>goog.cloneObject</code> does not detect reference loops. Objects that 879 * refer to themselves will cause infinite recursion. 880 * 881 * <code>goog.cloneObject</code> is unaware of unique identifiers, and copies 882 * UIDs created by <code>getUid</code> into cloned results. 883 * 884 * @param {*} obj The value to clone. 885 * @return {*} A clone of the input value. 886 * @deprecated goog.cloneObject is unsafe. Prefer the goog.object methods. 887 */ 888 goog.cloneObject = function(obj) { 889 var type = goog.typeOf(obj); 890 if (type == 'object' || type == 'array') { 891 if (obj.clone) { 892 return obj.clone(); 893 } 894 var clone = type == 'array' ? [] : {}; 895 for (var key in obj) { 896 clone[key] = goog.cloneObject(obj[key]); 897 } 898 return clone; 899 } 900 901 return obj; 902 }; 903 904 905 /** 906 * Forward declaration for the clone method. This is necessary until the 907 * compiler can better support duck-typing constructs as used in 908 * goog.cloneObject. 909 * 910 * TODO(user): Remove once the JSCompiler can infer that the check for 911 * proto.clone is safe in goog.cloneObject. 912 * 913 * @type {Function} 914 */ 915 Object.prototype.clone; 916 917 918 /** 919 * Partially applies this function to a particular 'this object' and zero or 920 * more arguments. The result is a new function with some arguments of the first 921 * function pre-filled and the value of |this| 'pre-specified'.<br><br> 922 * 923 * Remaining arguments specified at call-time are appended to the pre- 924 * specified ones.<br><br> 925 * 926 * Also see: {@link #partial}.<br><br> 927 * 928 * Usage: 929 * <pre>var barMethBound = bind(myFunction, myObj, 'arg1', 'arg2'); 930 * barMethBound('arg3', 'arg4');</pre> 931 * 932 * @param {Function} fn A function to partially apply. 933 * @param {Object|undefined} selfObj Specifies the object which |this| should 934 * point to when the function is run. If the value is null or undefined, it 935 * will default to the global object. 936 * @param {...*} var_args Additional arguments that are partially 937 * applied to the function. 938 * 939 * @return {!Function} A partially-applied form of the function bind() was 940 * invoked as a method of. 941 */ 942 goog.bind = function(fn, selfObj, var_args) { 943 var context = selfObj || goog.global; 944 945 if (arguments.length > 2) { 946 var boundArgs = Array.prototype.slice.call(arguments, 2); 947 return function() { 948 // Prepend the bound arguments to the current arguments. 949 var newArgs = Array.prototype.slice.call(arguments); 950 Array.prototype.unshift.apply(newArgs, boundArgs); 951 return fn.apply(context, newArgs); 952 }; 953 954 } else { 955 return function() { 956 return fn.apply(context, arguments); 957 }; 958 } 959 }; 960 961 962 /** 963 * Like bind(), except that a 'this object' is not required. Useful when the 964 * target function is already bound. 965 * 966 * Usage: 967 * var g = partial(f, arg1, arg2); 968 * g(arg3, arg4); 969 * 970 * @param {Function} fn A function to partially apply. 971 * @param {...*} var_args Additional arguments that are partially 972 * applied to fn. 973 * @return {!Function} A partially-applied form of the function bind() was 974 * invoked as a method of. 975 */ 976 goog.partial = function(fn, var_args) { 977 var args = Array.prototype.slice.call(arguments, 1); 978 return function() { 979 // Prepend the bound arguments to the current arguments. 980 var newArgs = Array.prototype.slice.call(arguments); 981 newArgs.unshift.apply(newArgs, args); 982 return fn.apply(this, newArgs); 983 }; 984 }; 985 986 987 /** 988 * Copies all the members of a source object to a target object. This method 989 * does not work on all browsers for all objects that contain keys such as 990 * toString or hasOwnProperty. Use goog.object.extend for this purpose. 991 * @param {Object} target Target. 992 * @param {Object} source Source. 993 */ 994 goog.mixin = function(target, source) { 995 for (var x in source) { 996 target[x] = source[x]; 997 } 998 999 // For IE7 or lower, the for-in-loop does not contain any properties that are 1000 // not enumerable on the prototype object (for example, isPrototypeOf from 1001 // Object.prototype) but also it will not include 'replace' on objects that 1002 // extend String and change 'replace' (not that it is common for anyone to 1003 // extend anything except Object). 1004 }; 1005 1006 1007 /** 1008 * @return {number} An integer value representing the number of milliseconds 1009 * between midnight, January 1, 1970 and the current time. 1010 */ 1011 goog.now = Date.now || (function() { 1012 // Unary plus operator converts its operand to a number which in the case of 1013 // a date is done by calling getTime(). 1014 return +new Date(); 1015 }); 1016 1017 1018 /** 1019 * Evals javascript in the global scope. In IE this uses execScript, other 1020 * browsers use goog.global.eval. If goog.global.eval does not evaluate in the 1021 * global scope (for example, in Safari), appends a script tag instead. 1022 * Throws an exception if neither execScript or eval is defined. 1023 * @param {string} script JavaScript string. 1024 */ 1025 goog.globalEval = function(script) { 1026 if (goog.global.execScript) { 1027 goog.global.execScript(script, 'JavaScript'); 1028 } else if (goog.global.eval) { 1029 // Test to see if eval works 1030 if (goog.evalWorksForGlobals_ == null) { 1031 goog.global.eval('var _et_ = 1;'); 1032 if (typeof goog.global['_et_'] != 'undefined') { 1033 delete goog.global['_et_']; 1034 goog.evalWorksForGlobals_ = true; 1035 } else { 1036 goog.evalWorksForGlobals_ = false; 1037 } 1038 } 1039 1040 if (goog.evalWorksForGlobals_) { 1041 goog.global.eval(script); 1042 } else { 1043 var doc = goog.global.document; 1044 var scriptElt = doc.createElement('script'); 1045 scriptElt.type = 'text/javascript'; 1046 scriptElt.defer = false; 1047 // Note(user): can't use .innerHTML since "t('<test>')" will fail and 1048 // .text doesn't work in Safari 2. Therefore we append a text node. 1049 scriptElt.appendChild(doc.createTextNode(script)); 1050 doc.body.appendChild(scriptElt); 1051 doc.body.removeChild(scriptElt); 1052 } 1053 } else { 1054 throw Error('goog.globalEval not available'); 1055 } 1056 }; 1057 1058 1059 /** 1060 * A macro for defining composite types. 1061 * 1062 * By assigning goog.typedef to a name, this tells JSCompiler that this is not 1063 * the name of a class, but rather it's the name of a composite type. 1064 * 1065 * For example, 1066 * /** @type {Array|NodeList} / goog.ArrayLike = goog.typedef; 1067 * will tell JSCompiler to replace all appearances of goog.ArrayLike in type 1068 * definitions with the union of Array and NodeList. 1069 * 1070 * Does nothing in uncompiled code. 1071 */ 1072 goog.typedef = true; 1073 1074 1075 /** 1076 * Optional map of CSS class names to obfuscated names used with 1077 * goog.getCssName(). 1078 * @type {Object|undefined} 1079 * @private 1080 * @see goog.setCssNameMapping 1081 */ 1082 goog.cssNameMapping_; 1083 1084 1085 /** 1086 * Handles strings that are intended to be used as CSS class names. 1087 * 1088 * Without JS Compiler the arguments are simple joined with a hyphen and passed 1089 * through unaltered. 1090 * 1091 * With the JS Compiler the arguments are inlined, e.g: 1092 * var x = goog.getCssName('foo'); 1093 * var y = goog.getCssName(this.baseClass, 'active'); 1094 * becomes: 1095 * var x= 'foo'; 1096 * var y = this.baseClass + '-active'; 1097 * 1098 * If a CSS renaming map is passed to the compiler it will replace symbols in 1099 * the classname. If one argument is passed it will be processed, if two are 1100 * passed only the modifier will be processed, as it is assumed the first 1101 * argument was generated as a result of calling goog.getCssName. 1102 * 1103 * Names are split on 'hyphen' and processed in parts such that the following 1104 * are equivalent: 1105 * var base = goog.getCssName('baseclass'); 1106 * goog.getCssName(base, 'modifier'); 1107 * goog.getCSsName('baseclass-modifier'); 1108 * 1109 * If any part does not appear in the renaming map a warning is logged and the 1110 * original, unobfuscated class name is inlined. 1111 * 1112 * @param {string} className The class name. 1113 * @param {string=} opt_modifier A modifier to be appended to the class name. 1114 * @return {string} The class name or the concatenation of the class name and 1115 * the modifier. 1116 */ 1117 goog.getCssName = function(className, opt_modifier) { 1118 var cssName = className + (opt_modifier ? '-' + opt_modifier : ''); 1119 return (goog.cssNameMapping_ && (cssName in goog.cssNameMapping_)) ? 1120 goog.cssNameMapping_[cssName] : cssName; 1121 }; 1122 1123 1124 /** 1125 * Sets the map to check when returning a value from goog.getCssName(). Example: 1126 * <pre> 1127 * goog.setCssNameMapping({ 1128 * "goog-menu": "a", 1129 * "goog-menu-disabled": "a-b", 1130 * "CSS_LOGO": "b", 1131 * "hidden": "c" 1132 * }); 1133 * 1134 * // The following evaluates to: "a a-b". 1135 * goog.getCssName('goog-menu') + ' ' + goog.getCssName('goog-menu', 'disabled') 1136 * </pre> 1137 * When declared as a map of string literals to string literals, the JSCompiler 1138 * will replace all calls to goog.getCssName() using the supplied map if the 1139 * --closure_pass flag is set. 1140 * 1141 * @param {!Object} mapping A map of strings to strings where keys are possible 1142 * arguments to goog.getCssName() and values are the corresponding values 1143 * that should be returned. 1144 */ 1145 goog.setCssNameMapping = function(mapping) { 1146 goog.cssNameMapping_ = mapping; 1147 }; 1148 1149 1150 /** 1151 * Abstract implementation of goog.getMsg for use with localized messages. 1152 * @param {string} str Translatable string, places holders in the form {$foo}. 1153 * @param {Object=} opt_values Map of place holder name to value. 1154 * @return {string} message with placeholders filled. 1155 */ 1156 goog.getMsg = function(str, opt_values) { 1157 var values = opt_values || {}; 1158 for (var key in values) { 1159 str = str.replace(new RegExp('\\{\\$' + key + '\\}', 'gi'), values[key]); 1160 } 1161 return str; 1162 }; 1163 1164 1165 /** 1166 * Exposes an unobfuscated global namespace path for the given object. 1167 * Note that fields of the exported object *will* be obfuscated, 1168 * unless they are exported in turn via this function or 1169 * goog.exportProperty 1170 * 1171 * <p>Also handy for making public items that are defined in anonymous 1172 * closures. 1173 * 1174 * ex. goog.exportSymbol('Foo', Foo); 1175 * 1176 * ex. goog.exportSymbol('public.path.Foo.staticFunction', 1177 * Foo.staticFunction); 1178 * public.path.Foo.staticFunction(); 1179 * 1180 * ex. goog.exportSymbol('public.path.Foo.prototype.myMethod', 1181 * Foo.prototype.myMethod); 1182 * new public.path.Foo().myMethod(); 1183 * 1184 * @param {string} publicPath Unobfuscated name to export. 1185 * @param {*} object Object the name should point to. 1186 * @param {Object=} opt_objectToExportTo The object to add the path to; default 1187 * is |goog.global|. 1188 */ 1189 goog.exportSymbol = function(publicPath, object, opt_objectToExportTo) { 1190 goog.exportPath_(publicPath, object, opt_objectToExportTo); 1191 }; 1192 1193 1194 /** 1195 * Exports a property unobfuscated into the object's namespace. 1196 * ex. goog.exportProperty(Foo, 'staticFunction', Foo.staticFunction); 1197 * ex. goog.exportProperty(Foo.prototype, 'myMethod', Foo.prototype.myMethod); 1198 * @param {Object} object Object whose static property is being exported. 1199 * @param {string} publicName Unobfuscated name to export. 1200 * @param {*} symbol Object the name should point to. 1201 */ 1202 goog.exportProperty = function(object, publicName, symbol) { 1203 object[publicName] = symbol; 1204 }; 1205 1206 1207 /** 1208 * Inherit the prototype methods from one constructor into another. 1209 * 1210 * Usage: 1211 * <pre> 1212 * function ParentClass(a, b) { } 1213 * ParentClass.prototype.foo = function(a) { } 1214 * 1215 * function ChildClass(a, b, c) { 1216 * ParentClass.call(this, a, b); 1217 * } 1218 * 1219 * goog.inherits(ChildClass, ParentClass); 1220 * 1221 * var child = new ChildClass('a', 'b', 'see'); 1222 * child.foo(); // works 1223 * </pre> 1224 * 1225 * In addition, a superclass' implementation of a method can be invoked 1226 * as follows: 1227 * 1228 * <pre> 1229 * ChildClass.prototype.foo = function(a) { 1230 * ChildClass.superClass_.foo.call(this, a); 1231 * // other code 1232 * }; 1233 * </pre> 1234 * 1235 * @param {Function} childCtor Child class. 1236 * @param {Function} parentCtor Parent class. 1237 */ 1238 goog.inherits = function(childCtor, parentCtor) { 1239 /** @constructor */ 1240 function tempCtor() {}; 1241 tempCtor.prototype = parentCtor.prototype; 1242 childCtor.superClass_ = parentCtor.prototype; 1243 childCtor.prototype = new tempCtor(); 1244 childCtor.prototype.constructor = childCtor; 1245 }; 1246 1247 1248 /** 1249 * Call up to the superclass. 1250 * 1251 * If this is called from a constructor, then this calls the superclass 1252 * contructor with arguments 1-N. 1253 * 1254 * If this is called from a prototype method, then you must pass 1255 * the name of the method as the second argument to this function. If 1256 * you do not, you will get a runtime error. This calls the superclass' 1257 * method with arguments 2-N. 1258 * 1259 * This function only works if you use goog.inherits to express 1260 * inheritance relationships between your classes. 1261 * 1262 * This function is a compiler primitive. At compile-time, the 1263 * compiler will do macro expansion to remove a lot of 1264 * the extra overhead that this function introduces. The compiler 1265 * will also enforce a lot of the assumptions that this function 1266 * makes, and treat it as a compiler error if you break them. 1267 * 1268 * @param {!Object} me Should always be "this". 1269 * @param {*=} opt_methodName The method name if calling a super method. 1270 * @param {...*} var_args The rest of the arguments. 1271 * @return {*} The return value of the superclass method. 1272 */ 1273 goog.base = function(me, opt_methodName, var_args) { 1274 var caller = arguments.callee.caller; 1275 if (caller.superClass_) { 1276 // This is a constructor. Call the superclass constructor. 1277 return caller.superClass_.constructor.apply( 1278 me, Array.prototype.slice.call(arguments, 1)); 1279 } 1280 1281 var args = Array.prototype.slice.call(arguments, 2); 1282 var foundCaller = false; 1283 for (var ctor = me.constructor; 1284 ctor; ctor = ctor.superClass_ && ctor.superClass_.constructor) { 1285 if (ctor.prototype[opt_methodName] === caller) { 1286 foundCaller = true; 1287 } else if (foundCaller) { 1288 return ctor.prototype[opt_methodName].apply(me, args); 1289 } 1290 } 1291 1292 // If we did not find the caller in the prototype chain, 1293 // then one of two things happened: 1294 // 1) The caller is an instance method. 1295 // 2) This method was not called by the right caller. 1296 if (me[opt_methodName] === caller) { 1297 return me.constructor.prototype[opt_methodName].apply(me, args); 1298 } else { 1299 throw Error( 1300 'goog.base called from a method of one name ' + 1301 'to a method of a different name'); 1302 } 1303 }; 1304 1305 1306 1307