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