base.js (81069B)
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 * @author arv@google.com (Erik Arvidsson) 23 * 24 * @provideGoog 25 */ 26 27 28 /** 29 * @define {boolean} Overridden to true by the compiler when --closure_pass 30 * or --mark_as_compiled is specified. 31 */ 32 var COMPILED = false; 33 34 35 /** 36 * Base namespace for the Closure library. Checks to see goog is already 37 * defined in the current scope before assigning to prevent clobbering if 38 * base.js is loaded more than once. 39 * 40 * @const 41 */ 42 var goog = goog || {}; 43 44 45 /** 46 * Reference to the global context. In most cases this will be 'window'. 47 */ 48 goog.global = this; 49 50 51 /** 52 * A hook for overriding the define values in uncompiled mode. 53 * 54 * In uncompiled mode, {@code CLOSURE_UNCOMPILED_DEFINES} may be defined before 55 * loading base.js. If a key is defined in {@code CLOSURE_UNCOMPILED_DEFINES}, 56 * {@code goog.define} will use the value instead of the default value. This 57 * allows flags to be overwritten without compilation (this is normally 58 * accomplished with the compiler's "define" flag). 59 * 60 * Example: 61 * <pre> 62 * var CLOSURE_UNCOMPILED_DEFINES = {'goog.DEBUG': false}; 63 * </pre> 64 * 65 * @type {Object<string, (string|number|boolean)>|undefined} 66 */ 67 goog.global.CLOSURE_UNCOMPILED_DEFINES; 68 69 70 /** 71 * A hook for overriding the define values in uncompiled or compiled mode, 72 * like CLOSURE_UNCOMPILED_DEFINES but effective in compiled code. In 73 * uncompiled code CLOSURE_UNCOMPILED_DEFINES takes precedence. 74 * 75 * Also unlike CLOSURE_UNCOMPILED_DEFINES the values must be number, boolean or 76 * string literals or the compiler will emit an error. 77 * 78 * While any @define value may be set, only those set with goog.define will be 79 * effective for uncompiled code. 80 * 81 * Example: 82 * <pre> 83 * var CLOSURE_DEFINES = {'goog.DEBUG': false} ; 84 * </pre> 85 * 86 * @type {Object<string, (string|number|boolean)>|undefined} 87 */ 88 goog.global.CLOSURE_DEFINES; 89 90 91 /** 92 * Returns true if the specified value is not undefined. 93 * WARNING: Do not use this to test if an object has a property. Use the in 94 * operator instead. 95 * 96 * @param {?} val Variable to test. 97 * @return {boolean} Whether variable is defined. 98 */ 99 goog.isDef = function(val) { 100 // void 0 always evaluates to undefined and hence we do not need to depend on 101 // the definition of the global variable named 'undefined'. 102 return val !== void 0; 103 }; 104 105 106 /** 107 * Builds an object structure for the provided namespace path, ensuring that 108 * names that already exist are not overwritten. For example: 109 * "a.b.c" -> a = {};a.b={};a.b.c={}; 110 * Used by goog.provide and goog.exportSymbol. 111 * @param {string} name name of the object that this file defines. 112 * @param {*=} opt_object the object to expose at the end of the path. 113 * @param {Object=} opt_objectToExportTo The object to add the path to; default 114 * is |goog.global|. 115 * @private 116 */ 117 goog.exportPath_ = function(name, opt_object, opt_objectToExportTo) { 118 var parts = name.split('.'); 119 var cur = opt_objectToExportTo || goog.global; 120 121 // Internet Explorer exhibits strange behavior when throwing errors from 122 // methods externed in this manner. See the testExportSymbolExceptions in 123 // base_test.html for an example. 124 if (!(parts[0] in cur) && cur.execScript) { 125 cur.execScript('var ' + parts[0]); 126 } 127 128 // Certain browsers cannot parse code in the form for((a in b); c;); 129 // This pattern is produced by the JSCompiler when it collapses the 130 // statement above into the conditional loop below. To prevent this from 131 // happening, use a for-loop and reserve the init logic as below. 132 133 // Parentheses added to eliminate strict JS warning in Firefox. 134 for (var part; parts.length && (part = parts.shift());) { 135 if (!parts.length && goog.isDef(opt_object)) { 136 // last part and we have an object; use it 137 cur[part] = opt_object; 138 } else if (cur[part]) { 139 cur = cur[part]; 140 } else { 141 cur = cur[part] = {}; 142 } 143 } 144 }; 145 146 147 /** 148 * Defines a named value. In uncompiled mode, the value is retrieved from 149 * CLOSURE_DEFINES or CLOSURE_UNCOMPILED_DEFINES if the object is defined and 150 * has the property specified, and otherwise used the defined defaultValue. 151 * When compiled the default can be overridden using the compiler 152 * options or the value set in the CLOSURE_DEFINES object. 153 * 154 * @param {string} name The distinguished name to provide. 155 * @param {string|number|boolean} defaultValue 156 */ 157 goog.define = function(name, defaultValue) { 158 var value = defaultValue; 159 if (!COMPILED) { 160 if (goog.global.CLOSURE_UNCOMPILED_DEFINES && 161 Object.prototype.hasOwnProperty.call( 162 goog.global.CLOSURE_UNCOMPILED_DEFINES, name)) { 163 value = goog.global.CLOSURE_UNCOMPILED_DEFINES[name]; 164 } else if (goog.global.CLOSURE_DEFINES && 165 Object.prototype.hasOwnProperty.call( 166 goog.global.CLOSURE_DEFINES, name)) { 167 value = goog.global.CLOSURE_DEFINES[name]; 168 } 169 } 170 goog.exportPath_(name, value); 171 }; 172 173 174 /** 175 * @define {boolean} DEBUG is provided as a convenience so that debugging code 176 * that should not be included in a production js_binary can be easily stripped 177 * by specifying --define goog.DEBUG=false to the JSCompiler. For example, most 178 * toString() methods should be declared inside an "if (goog.DEBUG)" conditional 179 * because they are generally used for debugging purposes and it is difficult 180 * for the JSCompiler to statically determine whether they are used. 181 */ 182 goog.define('goog.DEBUG', true); 183 184 185 /** 186 * @define {string} LOCALE defines the locale being used for compilation. It is 187 * used to select locale specific data to be compiled in js binary. BUILD rule 188 * can specify this value by "--define goog.LOCALE=<locale_name>" as JSCompiler 189 * option. 190 * 191 * Take into account that the locale code format is important. You should use 192 * the canonical Unicode format with hyphen as a delimiter. Language must be 193 * lowercase, Language Script - Capitalized, Region - UPPERCASE. 194 * There are few examples: pt-BR, en, en-US, sr-Latin-BO, zh-Hans-CN. 195 * 196 * See more info about locale codes here: 197 * http://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers 198 * 199 * For language codes you should use values defined by ISO 693-1. See it here 200 * http://www.w3.org/WAI/ER/IG/ert/iso639.htm. There is only one exception from 201 * this rule: the Hebrew language. For legacy reasons the old code (iw) should 202 * be used instead of the new code (he), see http://wiki/Main/IIISynonyms. 203 */ 204 goog.define('goog.LOCALE', 'en'); // default to en 205 206 207 /** 208 * @define {boolean} Whether this code is running on trusted sites. 209 * 210 * On untrusted sites, several native functions can be defined or overridden by 211 * external libraries like Prototype, Datejs, and JQuery and setting this flag 212 * to false forces closure to use its own implementations when possible. 213 * 214 * If your JavaScript can be loaded by a third party site and you are wary about 215 * relying on non-standard implementations, specify 216 * "--define goog.TRUSTED_SITE=false" to the JSCompiler. 217 */ 218 goog.define('goog.TRUSTED_SITE', true); 219 220 221 /** 222 * @define {boolean} Whether a project is expected to be running in strict mode. 223 * 224 * This define can be used to trigger alternate implementations compatible with 225 * running in EcmaScript Strict mode or warn about unavailable functionality. 226 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode 227 * 228 */ 229 goog.define('goog.STRICT_MODE_COMPATIBLE', false); 230 231 232 /** 233 * @define {boolean} Whether code that calls {@link goog.setTestOnly} should 234 * be disallowed in the compilation unit. 235 */ 236 goog.define('goog.DISALLOW_TEST_ONLY_CODE', COMPILED && !goog.DEBUG); 237 238 239 /** 240 * Defines a namespace in Closure. 241 * 242 * A namespace may only be defined once in a codebase. It may be defined using 243 * goog.provide() or goog.module(). 244 * 245 * The presence of one or more goog.provide() calls in a file indicates 246 * that the file defines the given objects/namespaces. 247 * Provided symbols must not be null or undefined. 248 * 249 * In addition, goog.provide() creates the object stubs for a namespace 250 * (for example, goog.provide("goog.foo.bar") will create the object 251 * goog.foo.bar if it does not already exist). 252 * 253 * Build tools also scan for provide/require/module statements 254 * to discern dependencies, build dependency files (see deps.js), etc. 255 * 256 * @see goog.require 257 * @see goog.module 258 * @param {string} name Namespace provided by this file in the form 259 * "goog.package.part". 260 */ 261 goog.provide = function(name) { 262 if (!COMPILED) { 263 // Ensure that the same namespace isn't provided twice. 264 // A goog.module/goog.provide maps a goog.require to a specific file 265 if (goog.isProvided_(name)) { 266 throw Error('Namespace "' + name + '" already declared.'); 267 } 268 } 269 270 goog.constructNamespace_(name); 271 }; 272 273 274 /** 275 * @param {string} name Namespace provided by this file in the form 276 * "goog.package.part". 277 * @param {Object=} opt_obj The object to embed in the namespace. 278 * @private 279 */ 280 goog.constructNamespace_ = function(name, opt_obj) { 281 if (!COMPILED) { 282 delete goog.implicitNamespaces_[name]; 283 284 var namespace = name; 285 while ((namespace = namespace.substring(0, namespace.lastIndexOf('.')))) { 286 if (goog.getObjectByName(namespace)) { 287 break; 288 } 289 goog.implicitNamespaces_[namespace] = true; 290 } 291 } 292 293 goog.exportPath_(name, opt_obj); 294 }; 295 296 297 /** 298 * Module identifier validation regexp. 299 * Note: This is a conservative check, it is very possible to be more lenient, 300 * the primary exclusion here is "/" and "\" and a leading ".", these 301 * restrictions are intended to leave the door open for using goog.require 302 * with relative file paths rather than module identifiers. 303 * @private 304 */ 305 goog.VALID_MODULE_RE_ = /^[a-zA-Z_$][a-zA-Z0-9._$]*$/; 306 307 308 /** 309 * Defines a module in Closure. 310 * 311 * Marks that this file must be loaded as a module and claims the namespace. 312 * 313 * A namespace may only be defined once in a codebase. It may be defined using 314 * goog.provide() or goog.module(). 315 * 316 * goog.module() has three requirements: 317 * - goog.module may not be used in the same file as goog.provide. 318 * - goog.module must be the first statement in the file. 319 * - only one goog.module is allowed per file. 320 * 321 * When a goog.module annotated file is loaded, it is enclosed in 322 * a strict function closure. This means that: 323 * - any variables declared in a goog.module file are private to the file 324 * (not global), though the compiler is expected to inline the module. 325 * - The code must obey all the rules of "strict" JavaScript. 326 * - the file will be marked as "use strict" 327 * 328 * NOTE: unlike goog.provide, goog.module does not declare any symbols by 329 * itself. If declared symbols are desired, use 330 * goog.module.declareLegacyNamespace(). 331 * 332 * 333 * See the public goog.module proposal: http://goo.gl/Va1hin 334 * 335 * @param {string} name Namespace provided by this file in the form 336 * "goog.package.part", is expected but not required. 337 */ 338 goog.module = function(name) { 339 if (!goog.isString(name) || 340 !name || 341 name.search(goog.VALID_MODULE_RE_) == -1) { 342 throw Error('Invalid module identifier'); 343 } 344 if (!goog.isInModuleLoader_()) { 345 throw Error('Module ' + name + ' has been loaded incorrectly.'); 346 } 347 if (goog.moduleLoaderState_.moduleName) { 348 throw Error('goog.module may only be called once per module.'); 349 } 350 351 // Store the module name for the loader. 352 goog.moduleLoaderState_.moduleName = name; 353 if (!COMPILED) { 354 // Ensure that the same namespace isn't provided twice. 355 // A goog.module/goog.provide maps a goog.require to a specific file 356 if (goog.isProvided_(name)) { 357 throw Error('Namespace "' + name + '" already declared.'); 358 } 359 delete goog.implicitNamespaces_[name]; 360 } 361 }; 362 363 364 /** 365 * @param {string} name The module identifier. 366 * @return {?} The module exports for an already loaded module or null. 367 * 368 * Note: This is not an alternative to goog.require, it does not 369 * indicate a hard dependency, instead it is used to indicate 370 * an optional dependency or to access the exports of a module 371 * that has already been loaded. 372 * @suppress {missingProvide} 373 */ 374 goog.module.get = function(name) { 375 return goog.module.getInternal_(name); 376 }; 377 378 379 /** 380 * @param {string} name The module identifier. 381 * @return {?} The module exports for an already loaded module or null. 382 * @private 383 */ 384 goog.module.getInternal_ = function(name) { 385 if (!COMPILED) { 386 if (goog.isProvided_(name)) { 387 // goog.require only return a value with-in goog.module files. 388 return name in goog.loadedModules_ ? 389 goog.loadedModules_[name] : 390 goog.getObjectByName(name); 391 } else { 392 return null; 393 } 394 } 395 }; 396 397 398 /** 399 * @private {?{ 400 * moduleName: (string|undefined), 401 * declareTestMethods: boolean 402 * }} 403 */ 404 goog.moduleLoaderState_ = null; 405 406 407 /** 408 * @private 409 * @return {boolean} Whether a goog.module is currently being initialized. 410 */ 411 goog.isInModuleLoader_ = function() { 412 return goog.moduleLoaderState_ != null; 413 }; 414 415 416 /** 417 * Indicate that a module's exports that are known test methods should 418 * be copied to the global object. This makes the test methods visible to 419 * test runners that inspect the global object. 420 * 421 * TODO(johnlenz): Make the test framework aware of goog.module so 422 * that this isn't necessary. Alternately combine this with goog.setTestOnly 423 * to minimize boiler plate. 424 * @suppress {missingProvide} 425 */ 426 goog.module.declareTestMethods = function() { 427 if (!goog.isInModuleLoader_()) { 428 throw new Error('goog.module.declareTestMethods must be called from ' + 429 'within a goog.module'); 430 } 431 goog.moduleLoaderState_.declareTestMethods = true; 432 }; 433 434 435 /** 436 * Provide the module's exports as a globally accessible object under the 437 * module's declared name. This is intended to ease migration to goog.module 438 * for files that have existing usages. 439 * @suppress {missingProvide} 440 */ 441 goog.module.declareLegacyNamespace = function() { 442 if (!COMPILED && !goog.isInModuleLoader_()) { 443 throw new Error('goog.module.declareLegacyNamespace must be called from ' + 444 'within a goog.module'); 445 } 446 if (!COMPILED && !goog.moduleLoaderState_.moduleName) { 447 throw Error('goog.module must be called prior to ' + 448 'goog.module.declareLegacyNamespace.'); 449 } 450 goog.moduleLoaderState_.declareLegacyNamespace = true; 451 }; 452 453 454 /** 455 * Marks that the current file should only be used for testing, and never for 456 * live code in production. 457 * 458 * In the case of unit tests, the message may optionally be an exact namespace 459 * for the test (e.g. 'goog.stringTest'). The linter will then ignore the extra 460 * provide (if not explicitly defined in the code). 461 * 462 * @param {string=} opt_message Optional message to add to the error that's 463 * raised when used in production code. 464 */ 465 goog.setTestOnly = function(opt_message) { 466 if (goog.DISALLOW_TEST_ONLY_CODE) { 467 opt_message = opt_message || ''; 468 throw Error('Importing test-only code into non-debug environment' + 469 (opt_message ? ': ' + opt_message : '.')); 470 } 471 }; 472 473 474 /** 475 * Forward declares a symbol. This is an indication to the compiler that the 476 * symbol may be used in the source yet is not required and may not be provided 477 * in compilation. 478 * 479 * The most common usage of forward declaration is code that takes a type as a 480 * function parameter but does not need to require it. By forward declaring 481 * instead of requiring, no hard dependency is made, and (if not required 482 * elsewhere) the namespace may never be required and thus, not be pulled 483 * into the JavaScript binary. If it is required elsewhere, it will be type 484 * checked as normal. 485 * 486 * 487 * @param {string} name The namespace to forward declare in the form of 488 * "goog.package.part". 489 */ 490 goog.forwardDeclare = function(name) {}; 491 492 493 if (!COMPILED) { 494 495 /** 496 * Check if the given name has been goog.provided. This will return false for 497 * names that are available only as implicit namespaces. 498 * @param {string} name name of the object to look for. 499 * @return {boolean} Whether the name has been provided. 500 * @private 501 */ 502 goog.isProvided_ = function(name) { 503 return (name in goog.loadedModules_) || 504 (!goog.implicitNamespaces_[name] && 505 goog.isDefAndNotNull(goog.getObjectByName(name))); 506 }; 507 508 /** 509 * Namespaces implicitly defined by goog.provide. For example, 510 * goog.provide('goog.events.Event') implicitly declares that 'goog' and 511 * 'goog.events' must be namespaces. 512 * 513 * @type {!Object<string, (boolean|undefined)>} 514 * @private 515 */ 516 goog.implicitNamespaces_ = {'goog.module': true}; 517 518 // NOTE: We add goog.module as an implicit namespace as goog.module is defined 519 // here and because the existing module package has not been moved yet out of 520 // the goog.module namespace. This satisifies both the debug loader and 521 // ahead-of-time dependency management. 522 } 523 524 525 /** 526 * Returns an object based on its fully qualified external name. The object 527 * is not found if null or undefined. If you are using a compilation pass that 528 * renames property names beware that using this function will not find renamed 529 * properties. 530 * 531 * @param {string} name The fully qualified name. 532 * @param {Object=} opt_obj The object within which to look; default is 533 * |goog.global|. 534 * @return {?} The value (object or primitive) or, if not found, null. 535 */ 536 goog.getObjectByName = function(name, opt_obj) { 537 var parts = name.split('.'); 538 var cur = opt_obj || goog.global; 539 for (var part; part = parts.shift(); ) { 540 if (goog.isDefAndNotNull(cur[part])) { 541 cur = cur[part]; 542 } else { 543 return null; 544 } 545 } 546 return cur; 547 }; 548 549 550 /** 551 * Globalizes a whole namespace, such as goog or goog.lang. 552 * 553 * @param {!Object} obj The namespace to globalize. 554 * @param {Object=} opt_global The object to add the properties to. 555 * @deprecated Properties may be explicitly exported to the global scope, but 556 * this should no longer be done in bulk. 557 */ 558 goog.globalize = function(obj, opt_global) { 559 var global = opt_global || goog.global; 560 for (var x in obj) { 561 global[x] = obj[x]; 562 } 563 }; 564 565 566 /** 567 * Adds a dependency from a file to the files it requires. 568 * @param {string} relPath The path to the js file. 569 * @param {!Array<string>} provides An array of strings with 570 * the names of the objects this file provides. 571 * @param {!Array<string>} requires An array of strings with 572 * the names of the objects this file requires. 573 * @param {boolean=} opt_isModule Whether this dependency must be loaded as 574 * a module as declared by goog.module. 575 */ 576 goog.addDependency = function(relPath, provides, requires, opt_isModule) { 577 if (goog.DEPENDENCIES_ENABLED) { 578 var provide, require; 579 var path = relPath.replace(/\\/g, '/'); 580 var deps = goog.dependencies_; 581 for (var i = 0; provide = provides[i]; i++) { 582 deps.nameToPath[provide] = path; 583 deps.pathIsModule[path] = !!opt_isModule; 584 } 585 for (var j = 0; require = requires[j]; j++) { 586 if (!(path in deps.requires)) { 587 deps.requires[path] = {}; 588 } 589 deps.requires[path][require] = true; 590 } 591 } 592 }; 593 594 595 596 597 // NOTE(nnaze): The debug DOM loader was included in base.js as an original way 598 // to do "debug-mode" development. The dependency system can sometimes be 599 // confusing, as can the debug DOM loader's asynchronous nature. 600 // 601 // With the DOM loader, a call to goog.require() is not blocking -- the script 602 // will not load until some point after the current script. If a namespace is 603 // needed at runtime, it needs to be defined in a previous script, or loaded via 604 // require() with its registered dependencies. 605 // User-defined namespaces may need their own deps file. See http://go/js_deps, 606 // http://go/genjsdeps, or, externally, DepsWriter. 607 // https://developers.google.com/closure/library/docs/depswriter 608 // 609 // Because of legacy clients, the DOM loader can't be easily removed from 610 // base.js. Work is being done to make it disableable or replaceable for 611 // different environments (DOM-less JavaScript interpreters like Rhino or V8, 612 // for example). See bootstrap/ for more information. 613 614 615 /** 616 * @define {boolean} Whether to enable the debug loader. 617 * 618 * If enabled, a call to goog.require() will attempt to load the namespace by 619 * appending a script tag to the DOM (if the namespace has been registered). 620 * 621 * If disabled, goog.require() will simply assert that the namespace has been 622 * provided (and depend on the fact that some outside tool correctly ordered 623 * the script). 624 */ 625 goog.define('goog.ENABLE_DEBUG_LOADER', true); 626 627 628 /** 629 * @param {string} msg 630 * @private 631 */ 632 goog.logToConsole_ = function(msg) { 633 if (goog.global.console) { 634 goog.global.console['error'](msg); 635 } 636 }; 637 638 639 /** 640 * Implements a system for the dynamic resolution of dependencies that works in 641 * parallel with the BUILD system. Note that all calls to goog.require will be 642 * stripped by the JSCompiler when the --closure_pass option is used. 643 * @see goog.provide 644 * @param {string} name Namespace to include (as was given in goog.provide()) in 645 * the form "goog.package.part". 646 * @return {?} If called within a goog.module file, the associated namespace or 647 * module otherwise null. 648 */ 649 goog.require = function(name) { 650 651 // If the object already exists we do not need do do anything. 652 if (!COMPILED) { 653 if (goog.ENABLE_DEBUG_LOADER && goog.IS_OLD_IE_) { 654 goog.maybeProcessDeferredDep_(name); 655 } 656 657 if (goog.isProvided_(name)) { 658 if (goog.isInModuleLoader_()) { 659 return goog.module.getInternal_(name); 660 } else { 661 return null; 662 } 663 } 664 665 if (goog.ENABLE_DEBUG_LOADER) { 666 var path = goog.getPathFromDeps_(name); 667 if (path) { 668 goog.included_[path] = true; 669 goog.writeScripts_(); 670 return null; 671 } 672 } 673 674 var errorMessage = 'goog.require could not find: ' + name; 675 goog.logToConsole_(errorMessage); 676 677 throw Error(errorMessage); 678 } 679 }; 680 681 682 /** 683 * Path for included scripts. 684 * @type {string} 685 */ 686 goog.basePath = ''; 687 688 689 /** 690 * A hook for overriding the base path. 691 * @type {string|undefined} 692 */ 693 goog.global.CLOSURE_BASE_PATH; 694 695 696 /** 697 * Whether to write out Closure's deps file. By default, the deps are written. 698 * @type {boolean|undefined} 699 */ 700 goog.global.CLOSURE_NO_DEPS; 701 702 703 /** 704 * A function to import a single script. This is meant to be overridden when 705 * Closure is being run in non-HTML contexts, such as web workers. It's defined 706 * in the global scope so that it can be set before base.js is loaded, which 707 * allows deps.js to be imported properly. 708 * 709 * The function is passed the script source, which is a relative URI. It should 710 * return true if the script was imported, false otherwise. 711 * @type {(function(string): boolean)|undefined} 712 */ 713 goog.global.CLOSURE_IMPORT_SCRIPT; 714 715 716 /** 717 * Null function used for default values of callbacks, etc. 718 * @return {void} Nothing. 719 */ 720 goog.nullFunction = function() {}; 721 722 723 /** 724 * The identity function. Returns its first argument. 725 * 726 * @param {*=} opt_returnValue The single value that will be returned. 727 * @param {...*} var_args Optional trailing arguments. These are ignored. 728 * @return {?} The first argument. We can't know the type -- just pass it along 729 * without type. 730 * @deprecated Use goog.functions.identity instead. 731 */ 732 goog.identityFunction = function(opt_returnValue, var_args) { 733 return opt_returnValue; 734 }; 735 736 737 /** 738 * When defining a class Foo with an abstract method bar(), you can do: 739 * Foo.prototype.bar = goog.abstractMethod 740 * 741 * Now if a subclass of Foo fails to override bar(), an error will be thrown 742 * when bar() is invoked. 743 * 744 * Note: This does not take the name of the function to override as an argument 745 * because that would make it more difficult to obfuscate our JavaScript code. 746 * 747 * @type {!Function} 748 * @throws {Error} when invoked to indicate the method should be overridden. 749 */ 750 goog.abstractMethod = function() { 751 throw Error('unimplemented abstract method'); 752 }; 753 754 755 /** 756 * Adds a {@code getInstance} static method that always returns the same 757 * instance object. 758 * @param {!Function} ctor The constructor for the class to add the static 759 * method to. 760 */ 761 goog.addSingletonGetter = function(ctor) { 762 ctor.getInstance = function() { 763 if (ctor.instance_) { 764 return ctor.instance_; 765 } 766 if (goog.DEBUG) { 767 // NOTE: JSCompiler can't optimize away Array#push. 768 goog.instantiatedSingletons_[goog.instantiatedSingletons_.length] = ctor; 769 } 770 return ctor.instance_ = new ctor; 771 }; 772 }; 773 774 775 /** 776 * All singleton classes that have been instantiated, for testing. Don't read 777 * it directly, use the {@code goog.testing.singleton} module. The compiler 778 * removes this variable if unused. 779 * @type {!Array<!Function>} 780 * @private 781 */ 782 goog.instantiatedSingletons_ = []; 783 784 785 /** 786 * @define {boolean} Whether to load goog.modules using {@code eval} when using 787 * the debug loader. This provides a better debugging experience as the 788 * source is unmodified and can be edited using Chrome Workspaces or similar. 789 * However in some environments the use of {@code eval} is banned 790 * so we provide an alternative. 791 */ 792 goog.define('goog.LOAD_MODULE_USING_EVAL', true); 793 794 795 /** 796 * @define {boolean} Whether the exports of goog.modules should be sealed when 797 * possible. 798 */ 799 goog.define('goog.SEAL_MODULE_EXPORTS', goog.DEBUG); 800 801 802 /** 803 * The registry of initialized modules: 804 * the module identifier to module exports map. 805 * @private @const {!Object<string, ?>} 806 */ 807 goog.loadedModules_ = {}; 808 809 810 /** 811 * True if goog.dependencies_ is available. 812 * @const {boolean} 813 */ 814 goog.DEPENDENCIES_ENABLED = !COMPILED && goog.ENABLE_DEBUG_LOADER; 815 816 817 if (goog.DEPENDENCIES_ENABLED) { 818 /** 819 * Object used to keep track of urls that have already been added. This record 820 * allows the prevention of circular dependencies. 821 * @private {!Object<string, boolean>} 822 */ 823 goog.included_ = {}; 824 825 826 /** 827 * This object is used to keep track of dependencies and other data that is 828 * used for loading scripts. 829 * @private 830 * @type {{ 831 * pathIsModule: !Object<string, boolean>, 832 * nameToPath: !Object<string, string>, 833 * requires: !Object<string, !Object<string, boolean>>, 834 * visited: !Object<string, boolean>, 835 * written: !Object<string, boolean>, 836 * deferred: !Object<string, string> 837 * }} 838 */ 839 goog.dependencies_ = { 840 pathIsModule: {}, // 1 to 1 841 842 nameToPath: {}, // 1 to 1 843 844 requires: {}, // 1 to many 845 846 // Used when resolving dependencies to prevent us from visiting file twice. 847 visited: {}, 848 849 written: {}, // Used to keep track of script files we have written. 850 851 deferred: {} // Used to track deferred module evaluations in old IEs 852 }; 853 854 855 /** 856 * Tries to detect whether is in the context of an HTML document. 857 * @return {boolean} True if it looks like HTML document. 858 * @private 859 */ 860 goog.inHtmlDocument_ = function() { 861 var doc = goog.global.document; 862 return typeof doc != 'undefined' && 863 'write' in doc; // XULDocument misses write. 864 }; 865 866 867 /** 868 * Tries to detect the base path of base.js script that bootstraps Closure. 869 * @private 870 */ 871 goog.findBasePath_ = function() { 872 if (goog.isDef(goog.global.CLOSURE_BASE_PATH)) { 873 goog.basePath = goog.global.CLOSURE_BASE_PATH; 874 return; 875 } else if (!goog.inHtmlDocument_()) { 876 return; 877 } 878 var doc = goog.global.document; 879 var scripts = doc.getElementsByTagName('SCRIPT'); 880 // Search backwards since the current script is in almost all cases the one 881 // that has base.js. 882 for (var i = scripts.length - 1; i >= 0; --i) { 883 var script = /** @type {!HTMLScriptElement} */ (scripts[i]); 884 var src = script.src; 885 var qmark = src.lastIndexOf('?'); 886 var l = qmark == -1 ? src.length : qmark; 887 if (src.substr(l - 7, 7) == 'base.js') { 888 goog.basePath = src.substr(0, l - 7); 889 return; 890 } 891 } 892 }; 893 894 895 /** 896 * Imports a script if, and only if, that script hasn't already been imported. 897 * (Must be called at execution time) 898 * @param {string} src Script source. 899 * @param {string=} opt_sourceText The optionally source text to evaluate 900 * @private 901 */ 902 goog.importScript_ = function(src, opt_sourceText) { 903 var importScript = goog.global.CLOSURE_IMPORT_SCRIPT || 904 goog.writeScriptTag_; 905 if (importScript(src, opt_sourceText)) { 906 goog.dependencies_.written[src] = true; 907 } 908 }; 909 910 911 /** @const @private {boolean} */ 912 goog.IS_OLD_IE_ = !!(!goog.global.atob && goog.global.document && 913 goog.global.document.all); 914 915 916 /** 917 * Given a URL initiate retrieval and execution of the module. 918 * @param {string} src Script source URL. 919 * @private 920 */ 921 goog.importModule_ = function(src) { 922 // In an attempt to keep browsers from timing out loading scripts using 923 // synchronous XHRs, put each load in its own script block. 924 var bootstrap = 'goog.retrieveAndExecModule_("' + src + '");'; 925 926 if (goog.importScript_('', bootstrap)) { 927 goog.dependencies_.written[src] = true; 928 } 929 }; 930 931 932 /** @private {!Array<string>} */ 933 goog.queuedModules_ = []; 934 935 936 /** 937 * Return an appropriate module text. Suitable to insert into 938 * a script tag (that is unescaped). 939 * @param {string} srcUrl 940 * @param {string} scriptText 941 * @return {string} 942 * @private 943 */ 944 goog.wrapModule_ = function(srcUrl, scriptText) { 945 if (!goog.LOAD_MODULE_USING_EVAL || !goog.isDef(goog.global.JSON)) { 946 return '' + 947 'goog.loadModule(function(exports) {' + 948 '"use strict";' + 949 scriptText + 950 '\n' + // terminate any trailing single line comment. 951 ';return exports' + 952 '});' + 953 '\n//# sourceURL=' + srcUrl + '\n'; 954 } else { 955 return '' + 956 'goog.loadModule(' + 957 goog.global.JSON.stringify( 958 scriptText + '\n//# sourceURL=' + srcUrl + '\n') + 959 ');'; 960 } 961 }; 962 963 // On IE9 and earlier, it is necessary to handle 964 // deferred module loads. In later browsers, the 965 // code to be evaluated is simply inserted as a script 966 // block in the correct order. To eval deferred 967 // code at the right time, we piggy back on goog.require to call 968 // goog.maybeProcessDeferredDep_. 969 // 970 // The goog.requires are used both to bootstrap 971 // the loading process (when no deps are available) and 972 // declare that they should be available. 973 // 974 // Here we eval the sources, if all the deps are available 975 // either already eval'd or goog.require'd. This will 976 // be the case when all the dependencies have already 977 // been loaded, and the dependent module is loaded. 978 // 979 // But this alone isn't sufficient because it is also 980 // necessary to handle the case where there is no root 981 // that is not deferred. For that there we register for an event 982 // and trigger goog.loadQueuedModules_ handle any remaining deferred 983 // evaluations. 984 985 /** 986 * Handle any remaining deferred goog.module evals. 987 * @private 988 */ 989 goog.loadQueuedModules_ = function() { 990 var count = goog.queuedModules_.length; 991 if (count > 0) { 992 var queue = goog.queuedModules_; 993 goog.queuedModules_ = []; 994 for (var i = 0; i < count; i++) { 995 var path = queue[i]; 996 goog.maybeProcessDeferredPath_(path); 997 } 998 } 999 }; 1000 1001 1002 /** 1003 * Eval the named module if its dependencies are 1004 * available. 1005 * @param {string} name The module to load. 1006 * @private 1007 */ 1008 goog.maybeProcessDeferredDep_ = function(name) { 1009 if (goog.isDeferredModule_(name) && 1010 goog.allDepsAreAvailable_(name)) { 1011 var path = goog.getPathFromDeps_(name); 1012 goog.maybeProcessDeferredPath_(goog.basePath + path); 1013 } 1014 }; 1015 1016 /** 1017 * @param {string} name The module to check. 1018 * @return {boolean} Whether the name represents a 1019 * module whose evaluation has been deferred. 1020 * @private 1021 */ 1022 goog.isDeferredModule_ = function(name) { 1023 var path = goog.getPathFromDeps_(name); 1024 if (path && goog.dependencies_.pathIsModule[path]) { 1025 var abspath = goog.basePath + path; 1026 return (abspath) in goog.dependencies_.deferred; 1027 } 1028 return false; 1029 }; 1030 1031 /** 1032 * @param {string} name The module to check. 1033 * @return {boolean} Whether the name represents a 1034 * module whose declared dependencies have all been loaded 1035 * (eval'd or a deferred module load) 1036 * @private 1037 */ 1038 goog.allDepsAreAvailable_ = function(name) { 1039 var path = goog.getPathFromDeps_(name); 1040 if (path && (path in goog.dependencies_.requires)) { 1041 for (var requireName in goog.dependencies_.requires[path]) { 1042 if (!goog.isProvided_(requireName) && 1043 !goog.isDeferredModule_(requireName)) { 1044 return false; 1045 } 1046 } 1047 } 1048 return true; 1049 }; 1050 1051 1052 /** 1053 * @param {string} abspath 1054 * @private 1055 */ 1056 goog.maybeProcessDeferredPath_ = function(abspath) { 1057 if (abspath in goog.dependencies_.deferred) { 1058 var src = goog.dependencies_.deferred[abspath]; 1059 delete goog.dependencies_.deferred[abspath]; 1060 goog.globalEval(src); 1061 } 1062 }; 1063 1064 1065 /** 1066 * @param {function(?):?|string} moduleDef The module definition. 1067 */ 1068 goog.loadModule = function(moduleDef) { 1069 // NOTE: we allow function definitions to be either in the from 1070 // of a string to eval (which keeps the original source intact) or 1071 // in a eval forbidden environment (CSP) we allow a function definition 1072 // which in its body must call {@code goog.module}, and return the exports 1073 // of the module. 1074 var previousState = goog.moduleLoaderState_; 1075 try { 1076 goog.moduleLoaderState_ = { 1077 moduleName: undefined, declareTestMethods: false}; 1078 var exports; 1079 if (goog.isFunction(moduleDef)) { 1080 exports = moduleDef.call(goog.global, {}); 1081 } else if (goog.isString(moduleDef)) { 1082 exports = goog.loadModuleFromSource_.call(goog.global, moduleDef); 1083 } else { 1084 throw Error('Invalid module definition'); 1085 } 1086 1087 var moduleName = goog.moduleLoaderState_.moduleName; 1088 if (!goog.isString(moduleName) || !moduleName) { 1089 throw Error('Invalid module name \"' + moduleName + '\"'); 1090 } 1091 1092 // Don't seal legacy namespaces as they may be uses as a parent of 1093 // another namespace 1094 if (goog.moduleLoaderState_.declareLegacyNamespace) { 1095 goog.constructNamespace_(moduleName, exports); 1096 } else if (goog.SEAL_MODULE_EXPORTS && Object.seal) { 1097 Object.seal(exports); 1098 } 1099 1100 goog.loadedModules_[moduleName] = exports; 1101 if (goog.moduleLoaderState_.declareTestMethods) { 1102 for (var entry in exports) { 1103 if (entry.indexOf('test', 0) === 0 || 1104 entry == 'tearDown' || 1105 entry == 'setUp' || 1106 entry == 'setUpPage' || 1107 entry == 'tearDownPage') { 1108 goog.global[entry] = exports[entry]; 1109 } 1110 } 1111 } 1112 } finally { 1113 goog.moduleLoaderState_ = previousState; 1114 } 1115 }; 1116 1117 1118 /** 1119 * @param {string} source 1120 * @return {!Object} 1121 * @private 1122 */ 1123 goog.loadModuleFromSource_ = function(source) { 1124 // NOTE: we avoid declaring parameters or local variables here to avoid 1125 // masking globals or leaking values into the module definition. 1126 'use strict'; 1127 var exports = {}; 1128 eval(arguments[0]); 1129 return exports; 1130 }; 1131 1132 1133 /** 1134 * The default implementation of the import function. Writes a script tag to 1135 * import the script. 1136 * 1137 * @param {string} src The script url. 1138 * @param {string=} opt_sourceText The optionally source text to evaluate 1139 * @return {boolean} True if the script was imported, false otherwise. 1140 * @private 1141 */ 1142 goog.writeScriptTag_ = function(src, opt_sourceText) { 1143 if (goog.inHtmlDocument_()) { 1144 var doc = goog.global.document; 1145 1146 // If the user tries to require a new symbol after document load, 1147 // something has gone terribly wrong. Doing a document.write would 1148 // wipe out the page. 1149 if (doc.readyState == 'complete') { 1150 // Certain test frameworks load base.js multiple times, which tries 1151 // to write deps.js each time. If that happens, just fail silently. 1152 // These frameworks wipe the page between each load of base.js, so this 1153 // is OK. 1154 var isDeps = /\bdeps.js$/.test(src); 1155 if (isDeps) { 1156 return false; 1157 } else { 1158 throw Error('Cannot write "' + src + '" after document load'); 1159 } 1160 } 1161 1162 var isOldIE = goog.IS_OLD_IE_; 1163 1164 if (opt_sourceText === undefined) { 1165 if (!isOldIE) { 1166 doc.write( 1167 '<script type="application/javascript" src="' + 1168 src + '"></' + 'script>'); 1169 } else { 1170 var state = " onreadystatechange='goog.onScriptLoad_(this, " + 1171 ++goog.lastNonModuleScriptIndex_ + ")' "; 1172 doc.write( 1173 '<script type="application/javascript" src="' + 1174 src + '"' + state + '></' + 'script>'); 1175 } 1176 } else { 1177 doc.write( 1178 '<script type="application/javascript">' + 1179 opt_sourceText + 1180 '</' + 'script>'); 1181 } 1182 return true; 1183 } else { 1184 return false; 1185 } 1186 }; 1187 1188 1189 /** @private {number} */ 1190 goog.lastNonModuleScriptIndex_ = 0; 1191 1192 1193 /** 1194 * A readystatechange handler for legacy IE 1195 * @param {!HTMLScriptElement} script 1196 * @param {number} scriptIndex 1197 * @return {boolean} 1198 * @private 1199 */ 1200 goog.onScriptLoad_ = function(script, scriptIndex) { 1201 // for now load the modules when we reach the last script, 1202 // later allow more inter-mingling. 1203 if (script.readyState == 'complete' && 1204 goog.lastNonModuleScriptIndex_ == scriptIndex) { 1205 goog.loadQueuedModules_(); 1206 } 1207 return true; 1208 }; 1209 1210 /** 1211 * Resolves dependencies based on the dependencies added using addDependency 1212 * and calls importScript_ in the correct order. 1213 * @private 1214 */ 1215 goog.writeScripts_ = function() { 1216 /** @type {!Array<string>} The scripts we need to write this time. */ 1217 var scripts = []; 1218 var seenScript = {}; 1219 var deps = goog.dependencies_; 1220 1221 /** @param {string} path */ 1222 function visitNode(path) { 1223 if (path in deps.written) { 1224 return; 1225 } 1226 1227 // We have already visited this one. We can get here if we have cyclic 1228 // dependencies. 1229 if (path in deps.visited) { 1230 if (!(path in seenScript)) { 1231 seenScript[path] = true; 1232 scripts.push(path); 1233 } 1234 return; 1235 } 1236 1237 deps.visited[path] = true; 1238 1239 if (path in deps.requires) { 1240 for (var requireName in deps.requires[path]) { 1241 // If the required name is defined, we assume that it was already 1242 // bootstrapped by other means. 1243 if (!goog.isProvided_(requireName)) { 1244 if (requireName in deps.nameToPath) { 1245 visitNode(deps.nameToPath[requireName]); 1246 } else { 1247 throw Error('Undefined nameToPath for ' + requireName); 1248 } 1249 } 1250 } 1251 } 1252 1253 if (!(path in seenScript)) { 1254 seenScript[path] = true; 1255 scripts.push(path); 1256 } 1257 } 1258 1259 for (var path in goog.included_) { 1260 if (!deps.written[path]) { 1261 visitNode(path); 1262 } 1263 } 1264 1265 // record that we are going to load all these scripts. 1266 for (var i = 0; i < scripts.length; i++) { 1267 var path = scripts[i]; 1268 goog.dependencies_.written[path] = true; 1269 } 1270 1271 // If a module is loaded synchronously then we need to 1272 // clear the current inModuleLoader value, and restore it when we are 1273 // done loading the current "requires". 1274 var moduleState = goog.moduleLoaderState_; 1275 goog.moduleLoaderState_ = null; 1276 1277 var loadingModule = false; 1278 for (var i = 0; i < scripts.length; i++) { 1279 var path = scripts[i]; 1280 if (path) { 1281 if (!deps.pathIsModule[path]) { 1282 goog.importScript_(goog.basePath + path); 1283 } else { 1284 loadingModule = true; 1285 goog.importModule_(goog.basePath + path); 1286 } 1287 } else { 1288 goog.moduleLoaderState_ = moduleState; 1289 throw Error('Undefined script input'); 1290 } 1291 } 1292 1293 // restore the current "module loading state" 1294 goog.moduleLoaderState_ = moduleState; 1295 }; 1296 1297 1298 /** 1299 * Looks at the dependency rules and tries to determine the script file that 1300 * fulfills a particular rule. 1301 * @param {string} rule In the form goog.namespace.Class or project.script. 1302 * @return {?string} Url corresponding to the rule, or null. 1303 * @private 1304 */ 1305 goog.getPathFromDeps_ = function(rule) { 1306 if (rule in goog.dependencies_.nameToPath) { 1307 return goog.dependencies_.nameToPath[rule]; 1308 } else { 1309 return null; 1310 } 1311 }; 1312 1313 goog.findBasePath_(); 1314 1315 // Allow projects to manage the deps files themselves. 1316 if (!goog.global.CLOSURE_NO_DEPS) { 1317 goog.importScript_(goog.basePath + 'deps.js'); 1318 } 1319 } 1320 1321 1322 /** 1323 * Normalize a file path by removing redundant ".." and extraneous "." file 1324 * path components. 1325 * @param {string} path 1326 * @return {string} 1327 * @private 1328 */ 1329 goog.normalizePath_ = function(path) { 1330 var components = path.split('/'); 1331 var i = 0; 1332 while (i < components.length) { 1333 if (components[i] == '.') { 1334 components.splice(i, 1); 1335 } else if (i && components[i] == '..' && 1336 components[i - 1] && components[i - 1] != '..') { 1337 components.splice(--i, 2); 1338 } else { 1339 i++; 1340 } 1341 } 1342 return components.join('/'); 1343 }; 1344 1345 1346 /** 1347 * Retrieve and execute a module. 1348 * @param {string} src Script source URL. 1349 * @private 1350 */ 1351 goog.retrieveAndExecModule_ = function(src) { 1352 if (!COMPILED) { 1353 // The full but non-canonicalized URL for later use. 1354 var originalPath = src; 1355 // Canonicalize the path, removing any /./ or /../ since Chrome's debugging 1356 // console doesn't auto-canonicalize XHR loads as it does <script> srcs. 1357 src = goog.normalizePath_(src); 1358 1359 var importScript = goog.global.CLOSURE_IMPORT_SCRIPT || 1360 goog.writeScriptTag_; 1361 1362 var scriptText = null; 1363 1364 var xhr = new goog.global['XMLHttpRequest'](); 1365 1366 /** @this {Object} */ 1367 xhr.onload = function() { 1368 scriptText = this.responseText; 1369 }; 1370 xhr.open('get', src, false); 1371 xhr.send(); 1372 1373 scriptText = xhr.responseText; 1374 1375 if (scriptText != null) { 1376 var execModuleScript = goog.wrapModule_(src, scriptText); 1377 var isOldIE = goog.IS_OLD_IE_; 1378 if (isOldIE) { 1379 goog.dependencies_.deferred[originalPath] = execModuleScript; 1380 goog.queuedModules_.push(originalPath); 1381 } else { 1382 importScript(src, execModuleScript); 1383 } 1384 } else { 1385 throw new Error('load of ' + src + 'failed'); 1386 } 1387 } 1388 }; 1389 1390 1391 //============================================================================== 1392 // Language Enhancements 1393 //============================================================================== 1394 1395 1396 /** 1397 * This is a "fixed" version of the typeof operator. It differs from the typeof 1398 * operator in such a way that null returns 'null' and arrays return 'array'. 1399 * @param {*} value The value to get the type of. 1400 * @return {string} The name of the type. 1401 */ 1402 goog.typeOf = function(value) { 1403 var s = typeof value; 1404 if (s == 'object') { 1405 if (value) { 1406 // Check these first, so we can avoid calling Object.prototype.toString if 1407 // possible. 1408 // 1409 // IE improperly marshals tyepof across execution contexts, but a 1410 // cross-context object will still return false for "instanceof Object". 1411 if (value instanceof Array) { 1412 return 'array'; 1413 } else if (value instanceof Object) { 1414 return s; 1415 } 1416 1417 // HACK: In order to use an Object prototype method on the arbitrary 1418 // value, the compiler requires the value be cast to type Object, 1419 // even though the ECMA spec explicitly allows it. 1420 var className = Object.prototype.toString.call( 1421 /** @type {Object} */ (value)); 1422 // In Firefox 3.6, attempting to access iframe window objects' length 1423 // property throws an NS_ERROR_FAILURE, so we need to special-case it 1424 // here. 1425 if (className == '[object Window]') { 1426 return 'object'; 1427 } 1428 1429 // We cannot always use constructor == Array or instanceof Array because 1430 // different frames have different Array objects. In IE6, if the iframe 1431 // where the array was created is destroyed, the array loses its 1432 // prototype. Then dereferencing val.splice here throws an exception, so 1433 // we can't use goog.isFunction. Calling typeof directly returns 'unknown' 1434 // so that will work. In this case, this function will return false and 1435 // most array functions will still work because the array is still 1436 // array-like (supports length and []) even though it has lost its 1437 // prototype. 1438 // Mark Miller noticed that Object.prototype.toString 1439 // allows access to the unforgeable [[Class]] property. 1440 // 15.2.4.2 Object.prototype.toString ( ) 1441 // When the toString method is called, the following steps are taken: 1442 // 1. Get the [[Class]] property of this object. 1443 // 2. Compute a string value by concatenating the three strings 1444 // "[object ", Result(1), and "]". 1445 // 3. Return Result(2). 1446 // and this behavior survives the destruction of the execution context. 1447 if ((className == '[object Array]' || 1448 // In IE all non value types are wrapped as objects across window 1449 // boundaries (not iframe though) so we have to do object detection 1450 // for this edge case. 1451 typeof value.length == 'number' && 1452 typeof value.splice != 'undefined' && 1453 typeof value.propertyIsEnumerable != 'undefined' && 1454 !value.propertyIsEnumerable('splice') 1455 1456 )) { 1457 return 'array'; 1458 } 1459 // HACK: There is still an array case that fails. 1460 // function ArrayImpostor() {} 1461 // ArrayImpostor.prototype = []; 1462 // var impostor = new ArrayImpostor; 1463 // this can be fixed by getting rid of the fast path 1464 // (value instanceof Array) and solely relying on 1465 // (value && Object.prototype.toString.vall(value) === '[object Array]') 1466 // but that would require many more function calls and is not warranted 1467 // unless closure code is receiving objects from untrusted sources. 1468 1469 // IE in cross-window calls does not correctly marshal the function type 1470 // (it appears just as an object) so we cannot use just typeof val == 1471 // 'function'. However, if the object has a call property, it is a 1472 // function. 1473 if ((className == '[object Function]' || 1474 typeof value.call != 'undefined' && 1475 typeof value.propertyIsEnumerable != 'undefined' && 1476 !value.propertyIsEnumerable('call'))) { 1477 return 'function'; 1478 } 1479 1480 } else { 1481 return 'null'; 1482 } 1483 1484 } else if (s == 'function' && typeof value.call == 'undefined') { 1485 // In Safari typeof nodeList returns 'function', and on Firefox typeof 1486 // behaves similarly for HTML{Applet,Embed,Object}, Elements and RegExps. We 1487 // would like to return object for those and we can detect an invalid 1488 // function by making sure that the function object has a call method. 1489 return 'object'; 1490 } 1491 return s; 1492 }; 1493 1494 1495 /** 1496 * Returns true if the specified value is null. 1497 * @param {?} val Variable to test. 1498 * @return {boolean} Whether variable is null. 1499 */ 1500 goog.isNull = function(val) { 1501 return val === null; 1502 }; 1503 1504 1505 /** 1506 * Returns true if the specified value is defined and not null. 1507 * @param {?} val Variable to test. 1508 * @return {boolean} Whether variable is defined and not null. 1509 */ 1510 goog.isDefAndNotNull = function(val) { 1511 // Note that undefined == null. 1512 return val != null; 1513 }; 1514 1515 1516 /** 1517 * Returns true if the specified value is an array. 1518 * @param {?} val Variable to test. 1519 * @return {boolean} Whether variable is an array. 1520 */ 1521 goog.isArray = function(val) { 1522 return goog.typeOf(val) == 'array'; 1523 }; 1524 1525 1526 /** 1527 * Returns true if the object looks like an array. To qualify as array like 1528 * the value needs to be either a NodeList or an object with a Number length 1529 * property. As a special case, a function value is not array like, because its 1530 * length property is fixed to correspond to the number of expected arguments. 1531 * @param {?} val Variable to test. 1532 * @return {boolean} Whether variable is an array. 1533 */ 1534 goog.isArrayLike = function(val) { 1535 var type = goog.typeOf(val); 1536 // We do not use goog.isObject here in order to exclude function values. 1537 return type == 'array' || type == 'object' && typeof val.length == 'number'; 1538 }; 1539 1540 1541 /** 1542 * Returns true if the object looks like a Date. To qualify as Date-like the 1543 * value needs to be an object and have a getFullYear() function. 1544 * @param {?} val Variable to test. 1545 * @return {boolean} Whether variable is a like a Date. 1546 */ 1547 goog.isDateLike = function(val) { 1548 return goog.isObject(val) && typeof val.getFullYear == 'function'; 1549 }; 1550 1551 1552 /** 1553 * Returns true if the specified value is a string. 1554 * @param {?} val Variable to test. 1555 * @return {boolean} Whether variable is a string. 1556 */ 1557 goog.isString = function(val) { 1558 return typeof val == 'string'; 1559 }; 1560 1561 1562 /** 1563 * Returns true if the specified value is a boolean. 1564 * @param {?} val Variable to test. 1565 * @return {boolean} Whether variable is boolean. 1566 */ 1567 goog.isBoolean = function(val) { 1568 return typeof val == 'boolean'; 1569 }; 1570 1571 1572 /** 1573 * Returns true if the specified value is a number. 1574 * @param {?} val Variable to test. 1575 * @return {boolean} Whether variable is a number. 1576 */ 1577 goog.isNumber = function(val) { 1578 return typeof val == 'number'; 1579 }; 1580 1581 1582 /** 1583 * Returns true if the specified value is a function. 1584 * @param {?} val Variable to test. 1585 * @return {boolean} Whether variable is a function. 1586 */ 1587 goog.isFunction = function(val) { 1588 return goog.typeOf(val) == 'function'; 1589 }; 1590 1591 1592 /** 1593 * Returns true if the specified value is an object. This includes arrays and 1594 * functions. 1595 * @param {?} val Variable to test. 1596 * @return {boolean} Whether variable is an object. 1597 */ 1598 goog.isObject = function(val) { 1599 var type = typeof val; 1600 return type == 'object' && val != null || type == 'function'; 1601 // return Object(val) === val also works, but is slower, especially if val is 1602 // not an object. 1603 }; 1604 1605 1606 /** 1607 * Gets a unique ID for an object. This mutates the object so that further calls 1608 * with the same object as a parameter returns the same value. The unique ID is 1609 * guaranteed to be unique across the current session amongst objects that are 1610 * passed into {@code getUid}. There is no guarantee that the ID is unique or 1611 * consistent across sessions. It is unsafe to generate unique ID for function 1612 * prototypes. 1613 * 1614 * @param {Object} obj The object to get the unique ID for. 1615 * @return {number} The unique ID for the object. 1616 */ 1617 goog.getUid = function(obj) { 1618 // TODO(arv): Make the type stricter, do not accept null. 1619 1620 // In Opera window.hasOwnProperty exists but always returns false so we avoid 1621 // using it. As a consequence the unique ID generated for BaseClass.prototype 1622 // and SubClass.prototype will be the same. 1623 return obj[goog.UID_PROPERTY_] || 1624 (obj[goog.UID_PROPERTY_] = ++goog.uidCounter_); 1625 }; 1626 1627 1628 /** 1629 * Whether the given object is already assigned a unique ID. 1630 * 1631 * This does not modify the object. 1632 * 1633 * @param {!Object} obj The object to check. 1634 * @return {boolean} Whether there is an assigned unique id for the object. 1635 */ 1636 goog.hasUid = function(obj) { 1637 return !!obj[goog.UID_PROPERTY_]; 1638 }; 1639 1640 1641 /** 1642 * Removes the unique ID from an object. This is useful if the object was 1643 * previously mutated using {@code goog.getUid} in which case the mutation is 1644 * undone. 1645 * @param {Object} obj The object to remove the unique ID field from. 1646 */ 1647 goog.removeUid = function(obj) { 1648 // TODO(arv): Make the type stricter, do not accept null. 1649 1650 // In IE, DOM nodes are not instances of Object and throw an exception if we 1651 // try to delete. Instead we try to use removeAttribute. 1652 if ('removeAttribute' in obj) { 1653 obj.removeAttribute(goog.UID_PROPERTY_); 1654 } 1655 /** @preserveTry */ 1656 try { 1657 delete obj[goog.UID_PROPERTY_]; 1658 } catch (ex) { 1659 } 1660 }; 1661 1662 1663 /** 1664 * Name for unique ID property. Initialized in a way to help avoid collisions 1665 * with other closure JavaScript on the same page. 1666 * @type {string} 1667 * @private 1668 */ 1669 goog.UID_PROPERTY_ = 'closure_uid_' + ((Math.random() * 1e9) >>> 0); 1670 1671 1672 /** 1673 * Counter for UID. 1674 * @type {number} 1675 * @private 1676 */ 1677 goog.uidCounter_ = 0; 1678 1679 1680 /** 1681 * Adds a hash code field to an object. The hash code is unique for the 1682 * given object. 1683 * @param {Object} obj The object to get the hash code for. 1684 * @return {number} The hash code for the object. 1685 * @deprecated Use goog.getUid instead. 1686 */ 1687 goog.getHashCode = goog.getUid; 1688 1689 1690 /** 1691 * Removes the hash code field from an object. 1692 * @param {Object} obj The object to remove the field from. 1693 * @deprecated Use goog.removeUid instead. 1694 */ 1695 goog.removeHashCode = goog.removeUid; 1696 1697 1698 /** 1699 * Clones a value. The input may be an Object, Array, or basic type. Objects and 1700 * arrays will be cloned recursively. 1701 * 1702 * WARNINGS: 1703 * <code>goog.cloneObject</code> does not detect reference loops. Objects that 1704 * refer to themselves will cause infinite recursion. 1705 * 1706 * <code>goog.cloneObject</code> is unaware of unique identifiers, and copies 1707 * UIDs created by <code>getUid</code> into cloned results. 1708 * 1709 * @param {*} obj The value to clone. 1710 * @return {*} A clone of the input value. 1711 * @deprecated goog.cloneObject is unsafe. Prefer the goog.object methods. 1712 */ 1713 goog.cloneObject = function(obj) { 1714 var type = goog.typeOf(obj); 1715 if (type == 'object' || type == 'array') { 1716 if (obj.clone) { 1717 return obj.clone(); 1718 } 1719 var clone = type == 'array' ? [] : {}; 1720 for (var key in obj) { 1721 clone[key] = goog.cloneObject(obj[key]); 1722 } 1723 return clone; 1724 } 1725 1726 return obj; 1727 }; 1728 1729 1730 /** 1731 * A native implementation of goog.bind. 1732 * @param {Function} fn A function to partially apply. 1733 * @param {Object|undefined} selfObj Specifies the object which this should 1734 * point to when the function is run. 1735 * @param {...*} var_args Additional arguments that are partially applied to the 1736 * function. 1737 * @return {!Function} A partially-applied form of the function bind() was 1738 * invoked as a method of. 1739 * @private 1740 * @suppress {deprecated} The compiler thinks that Function.prototype.bind is 1741 * deprecated because some people have declared a pure-JS version. 1742 * Only the pure-JS version is truly deprecated. 1743 */ 1744 goog.bindNative_ = function(fn, selfObj, var_args) { 1745 return /** @type {!Function} */ (fn.call.apply(fn.bind, arguments)); 1746 }; 1747 1748 1749 /** 1750 * A pure-JS implementation of goog.bind. 1751 * @param {Function} fn A function to partially apply. 1752 * @param {Object|undefined} selfObj Specifies the object which this should 1753 * point to when the function is run. 1754 * @param {...*} var_args Additional arguments that are partially applied to the 1755 * function. 1756 * @return {!Function} A partially-applied form of the function bind() was 1757 * invoked as a method of. 1758 * @private 1759 */ 1760 goog.bindJs_ = function(fn, selfObj, var_args) { 1761 if (!fn) { 1762 throw new Error(); 1763 } 1764 1765 if (arguments.length > 2) { 1766 var boundArgs = Array.prototype.slice.call(arguments, 2); 1767 return function() { 1768 // Prepend the bound arguments to the current arguments. 1769 var newArgs = Array.prototype.slice.call(arguments); 1770 Array.prototype.unshift.apply(newArgs, boundArgs); 1771 return fn.apply(selfObj, newArgs); 1772 }; 1773 1774 } else { 1775 return function() { 1776 return fn.apply(selfObj, arguments); 1777 }; 1778 } 1779 }; 1780 1781 1782 /** 1783 * Partially applies this function to a particular 'this object' and zero or 1784 * more arguments. The result is a new function with some arguments of the first 1785 * function pre-filled and the value of this 'pre-specified'. 1786 * 1787 * Remaining arguments specified at call-time are appended to the pre-specified 1788 * ones. 1789 * 1790 * Also see: {@link #partial}. 1791 * 1792 * Usage: 1793 * <pre>var barMethBound = bind(myFunction, myObj, 'arg1', 'arg2'); 1794 * barMethBound('arg3', 'arg4');</pre> 1795 * 1796 * @param {?function(this:T, ...)} fn A function to partially apply. 1797 * @param {T} selfObj Specifies the object which this should point to when the 1798 * function is run. 1799 * @param {...*} var_args Additional arguments that are partially applied to the 1800 * function. 1801 * @return {!Function} A partially-applied form of the function bind() was 1802 * invoked as a method of. 1803 * @template T 1804 * @suppress {deprecated} See above. 1805 */ 1806 goog.bind = function(fn, selfObj, var_args) { 1807 // TODO(nicksantos): narrow the type signature. 1808 if (Function.prototype.bind && 1809 // NOTE(nicksantos): Somebody pulled base.js into the default Chrome 1810 // extension environment. This means that for Chrome extensions, they get 1811 // the implementation of Function.prototype.bind that calls goog.bind 1812 // instead of the native one. Even worse, we don't want to introduce a 1813 // circular dependency between goog.bind and Function.prototype.bind, so 1814 // we have to hack this to make sure it works correctly. 1815 Function.prototype.bind.toString().indexOf('native code') != -1) { 1816 goog.bind = goog.bindNative_; 1817 } else { 1818 goog.bind = goog.bindJs_; 1819 } 1820 return goog.bind.apply(null, arguments); 1821 }; 1822 1823 1824 /** 1825 * Like bind(), except that a 'this object' is not required. Useful when the 1826 * target function is already bound. 1827 * 1828 * Usage: 1829 * var g = partial(f, arg1, arg2); 1830 * g(arg3, arg4); 1831 * 1832 * @param {Function} fn A function to partially apply. 1833 * @param {...*} var_args Additional arguments that are partially applied to fn. 1834 * @return {!Function} A partially-applied form of the function bind() was 1835 * invoked as a method of. 1836 */ 1837 goog.partial = function(fn, var_args) { 1838 var args = Array.prototype.slice.call(arguments, 1); 1839 return function() { 1840 // Clone the array (with slice()) and append additional arguments 1841 // to the existing arguments. 1842 var newArgs = args.slice(); 1843 newArgs.push.apply(newArgs, arguments); 1844 return fn.apply(this, newArgs); 1845 }; 1846 }; 1847 1848 1849 /** 1850 * Copies all the members of a source object to a target object. This method 1851 * does not work on all browsers for all objects that contain keys such as 1852 * toString or hasOwnProperty. Use goog.object.extend for this purpose. 1853 * @param {Object} target Target. 1854 * @param {Object} source Source. 1855 */ 1856 goog.mixin = function(target, source) { 1857 for (var x in source) { 1858 target[x] = source[x]; 1859 } 1860 1861 // For IE7 or lower, the for-in-loop does not contain any properties that are 1862 // not enumerable on the prototype object (for example, isPrototypeOf from 1863 // Object.prototype) but also it will not include 'replace' on objects that 1864 // extend String and change 'replace' (not that it is common for anyone to 1865 // extend anything except Object). 1866 }; 1867 1868 1869 /** 1870 * @return {number} An integer value representing the number of milliseconds 1871 * between midnight, January 1, 1970 and the current time. 1872 */ 1873 goog.now = (goog.TRUSTED_SITE && Date.now) || (function() { 1874 // Unary plus operator converts its operand to a number which in the case of 1875 // a date is done by calling getTime(). 1876 return +new Date(); 1877 }); 1878 1879 1880 /** 1881 * Evals JavaScript in the global scope. In IE this uses execScript, other 1882 * browsers use goog.global.eval. If goog.global.eval does not evaluate in the 1883 * global scope (for example, in Safari), appends a script tag instead. 1884 * Throws an exception if neither execScript or eval is defined. 1885 * @param {string} script JavaScript string. 1886 */ 1887 goog.globalEval = function(script) { 1888 if (goog.global.execScript) { 1889 goog.global.execScript(script, 'JavaScript'); 1890 } else if (goog.global.eval) { 1891 // Test to see if eval works 1892 if (goog.evalWorksForGlobals_ == null) { 1893 goog.global.eval('var _et_ = 1;'); 1894 if (typeof goog.global['_et_'] != 'undefined') { 1895 delete goog.global['_et_']; 1896 goog.evalWorksForGlobals_ = true; 1897 } else { 1898 goog.evalWorksForGlobals_ = false; 1899 } 1900 } 1901 1902 if (goog.evalWorksForGlobals_) { 1903 goog.global.eval(script); 1904 } else { 1905 var doc = goog.global.document; 1906 var scriptElt = doc.createElement('SCRIPT'); 1907 scriptElt.type = 'application/javascript'; 1908 scriptElt.defer = false; 1909 // Note(user): can't use .innerHTML since "t('<test>')" will fail and 1910 // .text doesn't work in Safari 2. Therefore we append a text node. 1911 scriptElt.appendChild(doc.createTextNode(script)); 1912 doc.body.appendChild(scriptElt); 1913 doc.body.removeChild(scriptElt); 1914 } 1915 } else { 1916 throw Error('goog.globalEval not available'); 1917 } 1918 }; 1919 1920 1921 /** 1922 * Indicates whether or not we can call 'eval' directly to eval code in the 1923 * global scope. Set to a Boolean by the first call to goog.globalEval (which 1924 * empirically tests whether eval works for globals). @see goog.globalEval 1925 * @type {?boolean} 1926 * @private 1927 */ 1928 goog.evalWorksForGlobals_ = null; 1929 1930 1931 /** 1932 * Optional map of CSS class names to obfuscated names used with 1933 * goog.getCssName(). 1934 * @private {!Object<string, string>|undefined} 1935 * @see goog.setCssNameMapping 1936 */ 1937 goog.cssNameMapping_; 1938 1939 1940 /** 1941 * Optional obfuscation style for CSS class names. Should be set to either 1942 * 'BY_WHOLE' or 'BY_PART' if defined. 1943 * @type {string|undefined} 1944 * @private 1945 * @see goog.setCssNameMapping 1946 */ 1947 goog.cssNameMappingStyle_; 1948 1949 1950 /** 1951 * Handles strings that are intended to be used as CSS class names. 1952 * 1953 * This function works in tandem with @see goog.setCssNameMapping. 1954 * 1955 * Without any mapping set, the arguments are simple joined with a hyphen and 1956 * passed through unaltered. 1957 * 1958 * When there is a mapping, there are two possible styles in which these 1959 * mappings are used. In the BY_PART style, each part (i.e. in between hyphens) 1960 * of the passed in css name is rewritten according to the map. In the BY_WHOLE 1961 * style, the full css name is looked up in the map directly. If a rewrite is 1962 * not specified by the map, the compiler will output a warning. 1963 * 1964 * When the mapping is passed to the compiler, it will replace calls to 1965 * goog.getCssName with the strings from the mapping, e.g. 1966 * var x = goog.getCssName('foo'); 1967 * var y = goog.getCssName(this.baseClass, 'active'); 1968 * becomes: 1969 * var x= 'foo'; 1970 * var y = this.baseClass + '-active'; 1971 * 1972 * If one argument is passed it will be processed, if two are passed only the 1973 * modifier will be processed, as it is assumed the first argument was generated 1974 * as a result of calling goog.getCssName. 1975 * 1976 * @param {string} className The class name. 1977 * @param {string=} opt_modifier A modifier to be appended to the class name. 1978 * @return {string} The class name or the concatenation of the class name and 1979 * the modifier. 1980 */ 1981 goog.getCssName = function(className, opt_modifier) { 1982 var getMapping = function(cssName) { 1983 return goog.cssNameMapping_[cssName] || cssName; 1984 }; 1985 1986 var renameByParts = function(cssName) { 1987 // Remap all the parts individually. 1988 var parts = cssName.split('-'); 1989 var mapped = []; 1990 for (var i = 0; i < parts.length; i++) { 1991 mapped.push(getMapping(parts[i])); 1992 } 1993 return mapped.join('-'); 1994 }; 1995 1996 var rename; 1997 if (goog.cssNameMapping_) { 1998 rename = goog.cssNameMappingStyle_ == 'BY_WHOLE' ? 1999 getMapping : renameByParts; 2000 } else { 2001 rename = function(a) { 2002 return a; 2003 }; 2004 } 2005 2006 if (opt_modifier) { 2007 return className + '-' + rename(opt_modifier); 2008 } else { 2009 return rename(className); 2010 } 2011 }; 2012 2013 2014 /** 2015 * Sets the map to check when returning a value from goog.getCssName(). Example: 2016 * <pre> 2017 * goog.setCssNameMapping({ 2018 * "goog": "a", 2019 * "disabled": "b", 2020 * }); 2021 * 2022 * var x = goog.getCssName('goog'); 2023 * // The following evaluates to: "a a-b". 2024 * goog.getCssName('goog') + ' ' + goog.getCssName(x, 'disabled') 2025 * </pre> 2026 * When declared as a map of string literals to string literals, the JSCompiler 2027 * will replace all calls to goog.getCssName() using the supplied map if the 2028 * --closure_pass flag is set. 2029 * 2030 * @param {!Object} mapping A map of strings to strings where keys are possible 2031 * arguments to goog.getCssName() and values are the corresponding values 2032 * that should be returned. 2033 * @param {string=} opt_style The style of css name mapping. There are two valid 2034 * options: 'BY_PART', and 'BY_WHOLE'. 2035 * @see goog.getCssName for a description. 2036 */ 2037 goog.setCssNameMapping = function(mapping, opt_style) { 2038 goog.cssNameMapping_ = mapping; 2039 goog.cssNameMappingStyle_ = opt_style; 2040 }; 2041 2042 2043 /** 2044 * To use CSS renaming in compiled mode, one of the input files should have a 2045 * call to goog.setCssNameMapping() with an object literal that the JSCompiler 2046 * can extract and use to replace all calls to goog.getCssName(). In uncompiled 2047 * mode, JavaScript code should be loaded before this base.js file that declares 2048 * a global variable, CLOSURE_CSS_NAME_MAPPING, which is used below. This is 2049 * to ensure that the mapping is loaded before any calls to goog.getCssName() 2050 * are made in uncompiled mode. 2051 * 2052 * A hook for overriding the CSS name mapping. 2053 * @type {!Object<string, string>|undefined} 2054 */ 2055 goog.global.CLOSURE_CSS_NAME_MAPPING; 2056 2057 2058 if (!COMPILED && goog.global.CLOSURE_CSS_NAME_MAPPING) { 2059 // This does not call goog.setCssNameMapping() because the JSCompiler 2060 // requires that goog.setCssNameMapping() be called with an object literal. 2061 goog.cssNameMapping_ = goog.global.CLOSURE_CSS_NAME_MAPPING; 2062 } 2063 2064 2065 /** 2066 * Gets a localized message. 2067 * 2068 * This function is a compiler primitive. If you give the compiler a localized 2069 * message bundle, it will replace the string at compile-time with a localized 2070 * version, and expand goog.getMsg call to a concatenated string. 2071 * 2072 * Messages must be initialized in the form: 2073 * <code> 2074 * var MSG_NAME = goog.getMsg('Hello {$placeholder}', {'placeholder': 'world'}); 2075 * </code> 2076 * 2077 * @param {string} str Translatable string, places holders in the form {$foo}. 2078 * @param {Object<string, string>=} opt_values Maps place holder name to value. 2079 * @return {string} message with placeholders filled. 2080 */ 2081 goog.getMsg = function(str, opt_values) { 2082 if (opt_values) { 2083 str = str.replace(/\{\$([^}]+)}/g, function(match, key) { 2084 return key in opt_values ? opt_values[key] : match; 2085 }); 2086 } 2087 return str; 2088 }; 2089 2090 2091 /** 2092 * Gets a localized message. If the message does not have a translation, gives a 2093 * fallback message. 2094 * 2095 * This is useful when introducing a new message that has not yet been 2096 * translated into all languages. 2097 * 2098 * This function is a compiler primitive. Must be used in the form: 2099 * <code>var x = goog.getMsgWithFallback(MSG_A, MSG_B);</code> 2100 * where MSG_A and MSG_B were initialized with goog.getMsg. 2101 * 2102 * @param {string} a The preferred message. 2103 * @param {string} b The fallback message. 2104 * @return {string} The best translated message. 2105 */ 2106 goog.getMsgWithFallback = function(a, b) { 2107 return a; 2108 }; 2109 2110 2111 /** 2112 * Exposes an unobfuscated global namespace path for the given object. 2113 * Note that fields of the exported object *will* be obfuscated, unless they are 2114 * exported in turn via this function or goog.exportProperty. 2115 * 2116 * Also handy for making public items that are defined in anonymous closures. 2117 * 2118 * ex. goog.exportSymbol('public.path.Foo', Foo); 2119 * 2120 * ex. goog.exportSymbol('public.path.Foo.staticFunction', Foo.staticFunction); 2121 * public.path.Foo.staticFunction(); 2122 * 2123 * ex. goog.exportSymbol('public.path.Foo.prototype.myMethod', 2124 * Foo.prototype.myMethod); 2125 * new public.path.Foo().myMethod(); 2126 * 2127 * @param {string} publicPath Unobfuscated name to export. 2128 * @param {*} object Object the name should point to. 2129 * @param {Object=} opt_objectToExportTo The object to add the path to; default 2130 * is goog.global. 2131 */ 2132 goog.exportSymbol = function(publicPath, object, opt_objectToExportTo) { 2133 goog.exportPath_(publicPath, object, opt_objectToExportTo); 2134 }; 2135 2136 2137 /** 2138 * Exports a property unobfuscated into the object's namespace. 2139 * ex. goog.exportProperty(Foo, 'staticFunction', Foo.staticFunction); 2140 * ex. goog.exportProperty(Foo.prototype, 'myMethod', Foo.prototype.myMethod); 2141 * @param {Object} object Object whose static property is being exported. 2142 * @param {string} publicName Unobfuscated name to export. 2143 * @param {*} symbol Object the name should point to. 2144 */ 2145 goog.exportProperty = function(object, publicName, symbol) { 2146 object[publicName] = symbol; 2147 }; 2148 2149 2150 /** 2151 * Inherit the prototype methods from one constructor into another. 2152 * 2153 * Usage: 2154 * <pre> 2155 * function ParentClass(a, b) { } 2156 * ParentClass.prototype.foo = function(a) { }; 2157 * 2158 * function ChildClass(a, b, c) { 2159 * ChildClass.base(this, 'constructor', a, b); 2160 * } 2161 * goog.inherits(ChildClass, ParentClass); 2162 * 2163 * var child = new ChildClass('a', 'b', 'see'); 2164 * child.foo(); // This works. 2165 * </pre> 2166 * 2167 * @param {Function} childCtor Child class. 2168 * @param {Function} parentCtor Parent class. 2169 */ 2170 goog.inherits = function(childCtor, parentCtor) { 2171 /** @constructor */ 2172 function tempCtor() {}; 2173 tempCtor.prototype = parentCtor.prototype; 2174 childCtor.superClass_ = parentCtor.prototype; 2175 childCtor.prototype = new tempCtor(); 2176 /** @override */ 2177 childCtor.prototype.constructor = childCtor; 2178 2179 /** 2180 * Calls superclass constructor/method. 2181 * 2182 * This function is only available if you use goog.inherits to 2183 * express inheritance relationships between classes. 2184 * 2185 * NOTE: This is a replacement for goog.base and for superClass_ 2186 * property defined in childCtor. 2187 * 2188 * @param {!Object} me Should always be "this". 2189 * @param {string} methodName The method name to call. Calling 2190 * superclass constructor can be done with the special string 2191 * 'constructor'. 2192 * @param {...*} var_args The arguments to pass to superclass 2193 * method/constructor. 2194 * @return {*} The return value of the superclass method/constructor. 2195 */ 2196 childCtor.base = function(me, methodName, var_args) { 2197 // Copying using loop to avoid deop due to passing arguments object to 2198 // function. This is faster in many JS engines as of late 2014. 2199 var args = new Array(arguments.length - 2); 2200 for (var i = 2; i < arguments.length; i++) { 2201 args[i - 2] = arguments[i]; 2202 } 2203 return parentCtor.prototype[methodName].apply(me, args); 2204 }; 2205 }; 2206 2207 2208 /** 2209 * Call up to the superclass. 2210 * 2211 * If this is called from a constructor, then this calls the superclass 2212 * constructor with arguments 1-N. 2213 * 2214 * If this is called from a prototype method, then you must pass the name of the 2215 * method as the second argument to this function. If you do not, you will get a 2216 * runtime error. This calls the superclass' method with arguments 2-N. 2217 * 2218 * This function only works if you use goog.inherits to express inheritance 2219 * relationships between your classes. 2220 * 2221 * This function is a compiler primitive. At compile-time, the compiler will do 2222 * macro expansion to remove a lot of the extra overhead that this function 2223 * introduces. The compiler will also enforce a lot of the assumptions that this 2224 * function makes, and treat it as a compiler error if you break them. 2225 * 2226 * @param {!Object} me Should always be "this". 2227 * @param {*=} opt_methodName The method name if calling a super method. 2228 * @param {...*} var_args The rest of the arguments. 2229 * @return {*} The return value of the superclass method. 2230 * @suppress {es5Strict} This method can not be used in strict mode, but 2231 * all Closure Library consumers must depend on this file. 2232 */ 2233 goog.base = function(me, opt_methodName, var_args) { 2234 var caller = arguments.callee.caller; 2235 2236 if (goog.STRICT_MODE_COMPATIBLE || (goog.DEBUG && !caller)) { 2237 throw Error('arguments.caller not defined. goog.base() cannot be used ' + 2238 'with strict mode code. See ' + 2239 'http://www.ecma-international.org/ecma-262/5.1/#sec-C'); 2240 } 2241 2242 if (caller.superClass_) { 2243 // Copying using loop to avoid deop due to passing arguments object to 2244 // function. This is faster in many JS engines as of late 2014. 2245 var ctorArgs = new Array(arguments.length - 1); 2246 for (var i = 1; i < arguments.length; i++) { 2247 ctorArgs[i - 1] = arguments[i]; 2248 } 2249 // This is a constructor. Call the superclass constructor. 2250 return caller.superClass_.constructor.apply(me, ctorArgs); 2251 } 2252 2253 // Copying using loop to avoid deop due to passing arguments object to 2254 // function. This is faster in many JS engines as of late 2014. 2255 var args = new Array(arguments.length - 2); 2256 for (var i = 2; i < arguments.length; i++) { 2257 args[i - 2] = arguments[i]; 2258 } 2259 var foundCaller = false; 2260 for (var ctor = me.constructor; 2261 ctor; ctor = ctor.superClass_ && ctor.superClass_.constructor) { 2262 if (ctor.prototype[opt_methodName] === caller) { 2263 foundCaller = true; 2264 } else if (foundCaller) { 2265 return ctor.prototype[opt_methodName].apply(me, args); 2266 } 2267 } 2268 2269 // If we did not find the caller in the prototype chain, then one of two 2270 // things happened: 2271 // 1) The caller is an instance method. 2272 // 2) This method was not called by the right caller. 2273 if (me[opt_methodName] === caller) { 2274 return me.constructor.prototype[opt_methodName].apply(me, args); 2275 } else { 2276 throw Error( 2277 'goog.base called from a method of one name ' + 2278 'to a method of a different name'); 2279 } 2280 }; 2281 2282 2283 /** 2284 * Allow for aliasing within scope functions. This function exists for 2285 * uncompiled code - in compiled code the calls will be inlined and the aliases 2286 * applied. In uncompiled code the function is simply run since the aliases as 2287 * written are valid JavaScript. 2288 * 2289 * 2290 * @param {function()} fn Function to call. This function can contain aliases 2291 * to namespaces (e.g. "var dom = goog.dom") or classes 2292 * (e.g. "var Timer = goog.Timer"). 2293 */ 2294 goog.scope = function(fn) { 2295 fn.call(goog.global); 2296 }; 2297 2298 2299 /* 2300 * To support uncompiled, strict mode bundles that use eval to divide source 2301 * like so: 2302 * eval('someSource;//# sourceUrl sourcefile.js'); 2303 * We need to export the globally defined symbols "goog" and "COMPILED". 2304 * Exporting "goog" breaks the compiler optimizations, so we required that 2305 * be defined externally. 2306 * NOTE: We don't use goog.exportSymbol here because we don't want to trigger 2307 * extern generation when that compiler option is enabled. 2308 */ 2309 if (!COMPILED) { 2310 goog.global['COMPILED'] = COMPILED; 2311 } 2312 2313 2314 2315 //============================================================================== 2316 // goog.defineClass implementation 2317 //============================================================================== 2318 2319 2320 /** 2321 * Creates a restricted form of a Closure "class": 2322 * - from the compiler's perspective, the instance returned from the 2323 * constructor is sealed (no new properties may be added). This enables 2324 * better checks. 2325 * - the compiler will rewrite this definition to a form that is optimal 2326 * for type checking and optimization (initially this will be a more 2327 * traditional form). 2328 * 2329 * @param {Function} superClass The superclass, Object or null. 2330 * @param {goog.defineClass.ClassDescriptor} def 2331 * An object literal describing 2332 * the class. It may have the following properties: 2333 * "constructor": the constructor function 2334 * "statics": an object literal containing methods to add to the constructor 2335 * as "static" methods or a function that will receive the constructor 2336 * function as its only parameter to which static properties can 2337 * be added. 2338 * all other properties are added to the prototype. 2339 * @return {!Function} The class constructor. 2340 */ 2341 goog.defineClass = function(superClass, def) { 2342 // TODO(johnlenz): consider making the superClass an optional parameter. 2343 var constructor = def.constructor; 2344 var statics = def.statics; 2345 // Wrap the constructor prior to setting up the prototype and static methods. 2346 if (!constructor || constructor == Object.prototype.constructor) { 2347 constructor = function() { 2348 throw Error('cannot instantiate an interface (no constructor defined).'); 2349 }; 2350 } 2351 2352 var cls = goog.defineClass.createSealingConstructor_(constructor, superClass); 2353 if (superClass) { 2354 goog.inherits(cls, superClass); 2355 } 2356 2357 // Remove all the properties that should not be copied to the prototype. 2358 delete def.constructor; 2359 delete def.statics; 2360 2361 goog.defineClass.applyProperties_(cls.prototype, def); 2362 if (statics != null) { 2363 if (statics instanceof Function) { 2364 statics(cls); 2365 } else { 2366 goog.defineClass.applyProperties_(cls, statics); 2367 } 2368 } 2369 2370 return cls; 2371 }; 2372 2373 2374 /** 2375 * @typedef { 2376 * !Object| 2377 * {constructor:!Function}| 2378 * {constructor:!Function, statics:(Object|function(Function):void)}} 2379 * @suppress {missingProvide} 2380 */ 2381 goog.defineClass.ClassDescriptor; 2382 2383 2384 /** 2385 * @define {boolean} Whether the instances returned by 2386 * goog.defineClass should be sealed when possible. 2387 */ 2388 goog.define('goog.defineClass.SEAL_CLASS_INSTANCES', goog.DEBUG); 2389 2390 2391 /** 2392 * If goog.defineClass.SEAL_CLASS_INSTANCES is enabled and Object.seal is 2393 * defined, this function will wrap the constructor in a function that seals the 2394 * results of the provided constructor function. 2395 * 2396 * @param {!Function} ctr The constructor whose results maybe be sealed. 2397 * @param {Function} superClass The superclass constructor. 2398 * @return {!Function} The replacement constructor. 2399 * @private 2400 */ 2401 goog.defineClass.createSealingConstructor_ = function(ctr, superClass) { 2402 if (goog.defineClass.SEAL_CLASS_INSTANCES && 2403 Object.seal instanceof Function) { 2404 // Don't seal subclasses of unsealable-tagged legacy classes. 2405 if (superClass && superClass.prototype && 2406 superClass.prototype[goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_]) { 2407 return ctr; 2408 } 2409 /** 2410 * @this {Object} 2411 * @return {?} 2412 */ 2413 var wrappedCtr = function() { 2414 // Don't seal an instance of a subclass when it calls the constructor of 2415 // its super class as there is most likely still setup to do. 2416 var instance = ctr.apply(this, arguments) || this; 2417 instance[goog.UID_PROPERTY_] = instance[goog.UID_PROPERTY_]; 2418 if (this.constructor === wrappedCtr) { 2419 Object.seal(instance); 2420 } 2421 return instance; 2422 }; 2423 return wrappedCtr; 2424 } 2425 return ctr; 2426 }; 2427 2428 2429 // TODO(johnlenz): share these values with the goog.object 2430 /** 2431 * The names of the fields that are defined on Object.prototype. 2432 * @type {!Array<string>} 2433 * @private 2434 * @const 2435 */ 2436 goog.defineClass.OBJECT_PROTOTYPE_FIELDS_ = [ 2437 'constructor', 2438 'hasOwnProperty', 2439 'isPrototypeOf', 2440 'propertyIsEnumerable', 2441 'toLocaleString', 2442 'toString', 2443 'valueOf' 2444 ]; 2445 2446 2447 // TODO(johnlenz): share this function with the goog.object 2448 /** 2449 * @param {!Object} target The object to add properties to. 2450 * @param {!Object} source The object to copy properties from. 2451 * @private 2452 */ 2453 goog.defineClass.applyProperties_ = function(target, source) { 2454 // TODO(johnlenz): update this to support ES5 getters/setters 2455 2456 var key; 2457 for (key in source) { 2458 if (Object.prototype.hasOwnProperty.call(source, key)) { 2459 target[key] = source[key]; 2460 } 2461 } 2462 2463 // For IE the for-in-loop does not contain any properties that are not 2464 // enumerable on the prototype object (for example isPrototypeOf from 2465 // Object.prototype) and it will also not include 'replace' on objects that 2466 // extend String and change 'replace' (not that it is common for anyone to 2467 // extend anything except Object). 2468 for (var i = 0; i < goog.defineClass.OBJECT_PROTOTYPE_FIELDS_.length; i++) { 2469 key = goog.defineClass.OBJECT_PROTOTYPE_FIELDS_[i]; 2470 if (Object.prototype.hasOwnProperty.call(source, key)) { 2471 target[key] = source[key]; 2472 } 2473 } 2474 }; 2475 2476 2477 /** 2478 * Sealing classes breaks the older idiom of assigning properties on the 2479 * prototype rather than in the constructor. As such, goog.defineClass 2480 * must not seal subclasses of these old-style classes until they are fixed. 2481 * Until then, this marks a class as "broken", instructing defineClass 2482 * not to seal subclasses. 2483 * @param {!Function} ctr The legacy constructor to tag as unsealable. 2484 */ 2485 goog.tagUnsealableClass = function(ctr) { 2486 if (!COMPILED && goog.defineClass.SEAL_CLASS_INSTANCES) { 2487 ctr.prototype[goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_] = true; 2488 } 2489 }; 2490 2491 2492 /** 2493 * Name for unsealable tag property. 2494 * @const @private {string} 2495 */ 2496 goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_ = 'goog_defineClass_legacy_unsealable';