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