PageRenderTime 49ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/ruhlamat_website/o3djs/base.js

http://demoasp.googlecode.com/
JavaScript | 794 lines | 377 code | 82 blank | 335 comment | 94 complexity | f290b378148952b7ad99acafa7419f8c MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1
  1. /*
  2. * Copyright 2009, Google Inc.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are
  7. * met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above
  12. * copyright notice, this list of conditions and the following disclaimer
  13. * in the documentation and/or other materials provided with the
  14. * distribution.
  15. * * Neither the name of Google Inc. nor the names of its
  16. * contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. /**
  32. * @fileoverview Base for all o3d sample utilties.
  33. * For more information about o3d see
  34. * http://code.google.com/p/o3d.
  35. *
  36. *
  37. * The main point of this module is to provide a central place to
  38. * have an init function to register an o3d namespace object because many other
  39. * modules need access to it.
  40. */
  41. /**
  42. * A namespace for all the o3djs utility libraries.
  43. * @namespace
  44. */
  45. var o3djs = o3djs || {};
  46. /**
  47. * Define this because the Google internal JSCompiler needs goog.typedef below.
  48. */
  49. var goog = goog || {};
  50. /**
  51. * A macro for defining composite types.
  52. *
  53. * By assigning goog.typedef to a name, this tells Google internal JSCompiler
  54. * that this is not the name of a class, but rather it's the name of a composite
  55. * type.
  56. *
  57. * For example,
  58. * /** @type {Array|NodeList} / goog.ArrayLike = goog.typedef;
  59. * will tell JSCompiler to replace all appearances of goog.ArrayLike in type
  60. * definitions with the union of Array and NodeList.
  61. *
  62. * Does nothing in uncompiled code.
  63. */
  64. goog.typedef = true;
  65. /**
  66. * Reference to the global context. In most cases this will be 'window'.
  67. */
  68. o3djs.global = this;
  69. /**
  70. * Flag used to force a function to run in the browser when it is called
  71. * from V8.
  72. * @type {boolean}
  73. */
  74. o3djs.BROWSER_ONLY = true;
  75. /**
  76. * Array of namespaces that have been provided.
  77. * @private
  78. * @type {!Array.<string>}
  79. */
  80. o3djs.provided_ = [];
  81. /**
  82. * Creates object stubs for a namespace. When present in a file,
  83. * o3djs.provide also indicates that the file defines the indicated
  84. * object.
  85. * @param {string} name name of the object that this file defines.
  86. */
  87. o3djs.provide = function(name) {
  88. // Ensure that the same namespace isn't provided twice.
  89. if (o3djs.getObjectByName(name) &&
  90. !o3djs.implicitNamespaces_[name]) {
  91. throw 'Namespace "' + name + '" already declared.';
  92. }
  93. var namespace = name;
  94. while ((namespace = namespace.substring(0, namespace.lastIndexOf('.')))) {
  95. o3djs.implicitNamespaces_[namespace] = true;
  96. }
  97. o3djs.exportPath_(name);
  98. o3djs.provided_.push(name);
  99. };
  100. /**
  101. * Namespaces implicitly defined by o3djs.provide. For example,
  102. * o3djs.provide('o3djs.events.Event') implicitly declares
  103. * that 'o3djs' and 'o3djs.events' must be namespaces.
  104. *
  105. * @type {Object}
  106. * @private
  107. */
  108. o3djs.implicitNamespaces_ = {};
  109. /**
  110. * Builds an object structure for the provided namespace path,
  111. * ensuring that names that already exist are not overwritten. For
  112. * example:
  113. * "a.b.c" -> a = {};a.b={};a.b.c={};
  114. * Used by o3djs.provide and o3djs.exportSymbol.
  115. * @param {string} name name of the object that this file defines.
  116. * @param {Object} opt_object the object to expose at the end of the path.
  117. * @param {Object} opt_objectToExportTo The object to add the path to; default
  118. * is |o3djs.global|.
  119. * @private
  120. */
  121. o3djs.exportPath_ = function(name, opt_object, opt_objectToExportTo) {
  122. var parts = name.split('.');
  123. var cur = opt_objectToExportTo || o3djs.global;
  124. var part;
  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. // Parentheses added to eliminate strict JS warning in Firefox.
  132. while (parts.length && (part = parts.shift())) {
  133. if (!parts.length && o3djs.isDef(opt_object)) {
  134. // last part and we have an object; use it.
  135. cur[part] = opt_object;
  136. } else if (cur[part]) {
  137. cur = cur[part];
  138. } else {
  139. cur = cur[part] = {};
  140. }
  141. }
  142. };
  143. /**
  144. * Returns an object based on its fully qualified external name. If you are
  145. * using a compilation pass that renames property names beware that using this
  146. * function will not find renamed properties.
  147. *
  148. * @param {string} name The fully qualified name.
  149. * @param {Object} opt_obj The object within which to look; default is
  150. * |o3djs.global|.
  151. * @return {Object} The object or, if not found, null.
  152. */
  153. o3djs.getObjectByName = function(name, opt_obj) {
  154. var parts = name.split('.');
  155. var cur = opt_obj || o3djs.global;
  156. for (var pp = 0; pp < parts.length; ++pp) {
  157. var part = parts[pp];
  158. if (cur[part]) {
  159. cur = cur[part];
  160. } else {
  161. return null;
  162. }
  163. }
  164. return cur;
  165. };
  166. /**
  167. * Implements a system for the dynamic resolution of dependencies.
  168. * @param {string} rule Rule to include, in the form o3djs.package.part.
  169. */
  170. o3djs.require = function(rule) {
  171. // if the object already exists we do not need do do anything
  172. if (o3djs.getObjectByName(rule)) {
  173. return;
  174. }
  175. var path = o3djs.getPathFromRule_(rule);
  176. if (path) {
  177. o3djs.included_[path] = true;
  178. o3djs.writeScripts_();
  179. } else {
  180. throw new Error('o3djs.require could not find: ' + rule);
  181. }
  182. };
  183. /**
  184. * Path for included scripts.
  185. * @type {string}
  186. */
  187. o3djs.basePath = '';
  188. /**
  189. * Object used to keep track of urls that have already been added. This
  190. * record allows the prevention of circular dependencies.
  191. * @type {Object}
  192. * @private
  193. */
  194. o3djs.included_ = {};
  195. /**
  196. * This object is used to keep track of dependencies and other data that is
  197. * used for loading scripts.
  198. * @private
  199. * @type {Object}
  200. */
  201. o3djs.dependencies_ = {
  202. visited: {}, // used when resolving dependencies to prevent us from
  203. // visiting the file twice.
  204. written: {} // used to keep track of script files we have written.
  205. };
  206. /**
  207. * Tries to detect the base path of the o3djs-base.js script that
  208. * bootstraps the o3djs libraries.
  209. * @private
  210. */
  211. o3djs.findBasePath_ = function() {
  212. var doc = o3djs.global.document;
  213. if (typeof doc == 'undefined') {
  214. return;
  215. }
  216. if (o3djs.global.BASE_PATH) {
  217. o3djs.basePath = o3djs.global.BASE_PATH;
  218. return;
  219. } else {
  220. // HACKHACK to hide compiler warnings :(
  221. o3djs.global.BASE_PATH = null;
  222. }
  223. var scripts = doc.getElementsByTagName('script');
  224. for (var script, i = 0; script = scripts[i]; i++) {
  225. var src = script.src;
  226. var l = src.length;
  227. if (src.substr(l - 13) == 'o3djs/base.js') {
  228. o3djs.basePath = src.substr(0, l - 13);
  229. return;
  230. }
  231. }
  232. };
  233. /**
  234. * Writes a script tag if, and only if, that script hasn't already been added
  235. * to the document. (Must be called at execution time.)
  236. * @param {string} src Script source.
  237. * @private
  238. */
  239. o3djs.writeScriptTag_ = function(src) {
  240. var doc = o3djs.global.document;
  241. if (typeof doc != 'undefined' &&
  242. !o3djs.dependencies_.written[src]) {
  243. o3djs.dependencies_.written[src] = true;
  244. doc.write('<script type="text/javascript" src="' +
  245. src + '"></' + 'script>');
  246. }
  247. };
  248. /**
  249. * Resolves dependencies based on the dependencies added using addDependency
  250. * and calls writeScriptTag_ in the correct order.
  251. * @private
  252. */
  253. o3djs.writeScripts_ = function() {
  254. // the scripts we need to write this time.
  255. var scripts = [];
  256. var seenScript = {};
  257. var deps = o3djs.dependencies_;
  258. function visitNode(path) {
  259. if (path in deps.written) {
  260. return;
  261. }
  262. // we have already visited this one. We can get here if we have cyclic
  263. // dependencies.
  264. if (path in deps.visited) {
  265. if (!(path in seenScript)) {
  266. seenScript[path] = true;
  267. scripts.push(path);
  268. }
  269. return;
  270. }
  271. deps.visited[path] = true;
  272. if (!(path in seenScript)) {
  273. seenScript[path] = true;
  274. scripts.push(path);
  275. }
  276. }
  277. for (var path in o3djs.included_) {
  278. if (!deps.written[path]) {
  279. visitNode(path);
  280. }
  281. }
  282. for (var i = 0; i < scripts.length; i++) {
  283. if (scripts[i]) {
  284. o3djs.writeScriptTag_(o3djs.basePath + scripts[i]);
  285. } else {
  286. throw Error('Undefined script input');
  287. }
  288. }
  289. };
  290. /**
  291. * Looks at the dependency rules and tries to determine the script file that
  292. * fulfills a particular rule.
  293. * @param {string} rule In the form o3djs.namespace.Class or
  294. * project.script.
  295. * @return {string?} Url corresponding to the rule, or null.
  296. * @private
  297. */
  298. o3djs.getPathFromRule_ = function(rule) {
  299. var parts = rule.split('.');
  300. return parts.join('/') + '.js';
  301. };
  302. o3djs.findBasePath_();
  303. /**
  304. * Returns true if the specified value is not |undefined|.
  305. * WARNING: Do not use this to test if an object has a property. Use the in
  306. * operator instead.
  307. * @param {*} val Variable to test.
  308. * @return {boolean} Whether variable is defined.
  309. */
  310. o3djs.isDef = function(val) {
  311. return typeof val != 'undefined';
  312. };
  313. /**
  314. * Exposes an unobfuscated global namespace path for the given object.
  315. * Note that fields of the exported object *will* be obfuscated,
  316. * unless they are exported in turn via this function or
  317. * o3djs.exportProperty.
  318. *
  319. * <p>Also handy for making public items that are defined in anonymous
  320. * closures.
  321. *
  322. * ex. o3djs.exportSymbol('Foo', Foo);
  323. *
  324. * ex. o3djs.exportSymbol('public.path.Foo.staticFunction',
  325. * Foo.staticFunction);
  326. * public.path.Foo.staticFunction();
  327. *
  328. * ex. o3djs.exportSymbol('public.path.Foo.prototype.myMethod',
  329. * Foo.prototype.myMethod);
  330. * new public.path.Foo().myMethod();
  331. *
  332. * @param {string} publicPath Unobfuscated name to export.
  333. * @param {Object} object Object the name should point to.
  334. * @param {Object} opt_objectToExportTo The object to add the path to; default
  335. * is |o3djs.global|.
  336. */
  337. o3djs.exportSymbol = function(publicPath, object, opt_objectToExportTo) {
  338. o3djs.exportPath_(publicPath, object, opt_objectToExportTo);
  339. };
  340. /**
  341. * This string contains JavaScript code to initialize a new V8 instance.
  342. * @private
  343. * @type {string}
  344. */
  345. o3djs.v8Initializer_ = '';
  346. /**
  347. * This array contains references to objects that v8 needs to bind to when
  348. * it initializes.
  349. * @private
  350. * @type {!Array.<Object>}
  351. */
  352. o3djs.v8InitializerArgs_ = [];
  353. /**
  354. * Converts any JavaScript value to a string representation that when evaluated
  355. * will result in an equal value.
  356. * @param {*} value Any value.
  357. * @return {string} A string representation for the value.
  358. * @private
  359. */
  360. o3djs.valueToString_ = function(value) {
  361. switch (typeof(value)) {
  362. case 'undefined':
  363. return 'undefined';
  364. case 'string':
  365. var escaped = escape(value);
  366. if (escaped === value) {
  367. return '"' + value + '"';
  368. } else {
  369. return 'unescape("' + escaped + '")';
  370. }
  371. case 'object':
  372. if (value === null) {
  373. return 'null';
  374. } else {
  375. // TODO: all the other builtin JavaScript objects like Date,
  376. // Number, Boolean, etc.
  377. if (value instanceof RegExp) {
  378. var result =
  379. 'new RegExp(' + o3djs.valueToString_(value.source) + ', "';
  380. if (value.global) {
  381. result += 'g';
  382. }
  383. if (value.ignoreCase) {
  384. result += 'i';
  385. }
  386. if (value.multiline) {
  387. result += 'm';
  388. }
  389. result += '")';
  390. return result;
  391. } else if (o3djs.base.isArray(value)) {
  392. var valueAsArray = /** @type {!Array} */ (value);
  393. var result = '[';
  394. var separator = '';
  395. for (var i = 0; i < valueAsArray.length; ++i) {
  396. result += separator + o3djs.valueToString_(valueAsArray[i]);
  397. separator = ',';
  398. }
  399. result += ']\n';
  400. return result;
  401. } else {
  402. var valueAsObject = /** @type {!Object} */ (value);
  403. var result = '{\n';
  404. var separator = '';
  405. for (var propertyName in valueAsObject) {
  406. result += separator + '"' + propertyName + '": ' +
  407. o3djs.valueToString_(valueAsObject[propertyName]);
  408. separator = ',';
  409. }
  410. result += '}\n';
  411. return result;
  412. }
  413. }
  414. default:
  415. return value.toString()
  416. }
  417. };
  418. /**
  419. * Given an object holding a namespace and the name of that namespace,
  420. * generates a string that when evaluated will populate the namespace.
  421. * @param {!Object} namespaceObject An object holding a namespace.
  422. * @param {string} namespaceName The name of the namespace.
  423. * @param {!Array.<Object>} opt_args An array of objects that will be used
  424. * together with the initializer string to populate a namespace. The args
  425. * may be referenced from initializer code as args_[i] where i is the index
  426. * in the array.
  427. * @return {string} A string that will populate the namespace.
  428. * @private
  429. */
  430. o3djs.namespaceInitializer_ = function(namespaceObject,
  431. namespaceName,
  432. opt_args) {
  433. var result = namespaceName + ' = {};\n';
  434. for (var propertyName in namespaceObject) {
  435. var propertyNamespaceName = namespaceName + '.' + propertyName;
  436. var propertyValue = namespaceObject[propertyName];
  437. if (typeof(propertyValue) === 'object' && propertyValue !== null &&
  438. !o3djs.base.isArray(propertyValue) &&
  439. !(propertyValue instanceof RegExp)) {
  440. result += o3djs.namespaceInitializer_(propertyValue,
  441. propertyNamespaceName);
  442. } else {
  443. var valueAsString = o3djs.valueToString_(propertyValue);
  444. // If this is a browser only function then bind to the browser version
  445. // of the function rather than create a new function in V8.
  446. if (typeof(propertyValue) == 'function' &&
  447. valueAsString.indexOf('o3djs.BROWSER_ONLY') != -1) {
  448. valueAsString = 'args_[' + opt_args.length + ']';
  449. opt_args.push(propertyValue);
  450. }
  451. result += propertyNamespaceName + ' = ' + valueAsString + ';\n';
  452. if (typeof(propertyValue) === 'function' && propertyValue.prototype) {
  453. result += o3djs.namespaceInitializer_(
  454. propertyValue.prototype,
  455. propertyNamespaceName + '.prototype');
  456. }
  457. }
  458. }
  459. return result;
  460. };
  461. o3djs.provide('o3djs.base');
  462. /**
  463. * The base module for o3djs.
  464. * @namespace
  465. */
  466. o3djs.base = o3djs.base || {};
  467. /**
  468. * The a Javascript copy of the o3d namespace object. (holds constants, enums,
  469. * etc...)
  470. * @type {o3d.o3d}
  471. */
  472. o3djs.base.o3d = null;
  473. /**
  474. * Snapshots the current state of all provided namespaces. This state will be
  475. * used to initialize future V8 instances. It is automatically
  476. * called by o3djs.util.makeClients.
  477. */
  478. o3djs.base.snapshotProvidedNamespaces = function() {
  479. // Snapshot the V8 initializer string from the current state of browser
  480. // JavaScript the first time this is called.
  481. o3djs.v8Initializer_ = 'function(args_) {\n';
  482. o3djs.v8InitializerArgs_ = [];
  483. for (var i = 0; i < o3djs.provided_.length; ++i) {
  484. var object = o3djs.getObjectByName(o3djs.provided_[i]);
  485. o3djs.v8Initializer_ += o3djs.namespaceInitializer_(
  486. /** @type {!Object} */ (object),
  487. o3djs.provided_[i],
  488. o3djs.v8InitializerArgs_);
  489. }
  490. o3djs.v8Initializer_ += '}\n';
  491. };
  492. /**
  493. * Initializes the o3djs.sample library in a v8 instance. This should be called
  494. * for every V8 instance that uses the sample library. It is automatically
  495. * called by o3djs.util.makeClients.
  496. * @param {!o3d.plugin} clientObject O3D.Plugin Object.
  497. */
  498. o3djs.base.initV8 = function(clientObject) {
  499. var v8Init = function(initializer, args) {
  500. // Set up the o3djs namespace.
  501. var o3djsBrowser = o3djs;
  502. o3djs = {};
  503. o3djs.browser = o3djsBrowser;
  504. o3djs.global = (function() { return this; })();
  505. o3djs.require = function(rule) {}
  506. o3djs.provide = function(rule) {}
  507. // Evaluate the initializer string with the arguments containing bindings
  508. // to browser side objects.
  509. eval('(' + initializer + ')')(args);
  510. // Make sure this points to the o3d namespace for this particular
  511. // instance of the plugin.
  512. o3djs.base.o3d = plugin.o3d;
  513. };
  514. clientObject.eval(v8Init.toString())(o3djs.v8Initializer_,
  515. o3djs.v8InitializerArgs_);
  516. };
  517. /**
  518. * Initializes the o3djs.sample library.
  519. * Basically all it does is record the o3djs.namespace object which is used by
  520. * other functions to look up o3d constants.
  521. *
  522. * @param {!Element} clientObject O3D.Plugin Object.
  523. */
  524. o3djs.base.init = function(clientObject) {
  525. function recursivelyCopyProperties(object) {
  526. var copy = {};
  527. var hasProperties = false;
  528. for (var key in object) {
  529. var property = object[key];
  530. if (typeof property == 'object' || typeof property == 'function') {
  531. property = recursivelyCopyProperties(property);
  532. }
  533. if (typeof property != 'undefined') {
  534. copy[key] = property;
  535. hasProperties = true;
  536. }
  537. }
  538. return hasProperties ? copy : undefined;
  539. }
  540. try {
  541. o3djs.base.o3d = recursivelyCopyProperties(clientObject.o3d);
  542. } catch (e) {
  543. // Firefox 2 raises an exception when trying to enumerate a NPObject
  544. o3djs.base.o3d = clientObject.o3d;
  545. }
  546. // Because of a bug in chrome, it is not possible for the browser to enumerate
  547. // the properties of an NPObject.
  548. // Chrome bug: http://code.google.com/p/chromium/issues/detail?id=5743
  549. o3djs.base.o3d = o3djs.base.o3d || clientObject.o3d;
  550. };
  551. /**
  552. * Determine whether a value is an array. Do not use instanceof because that
  553. * will not work for V8 arrays (the browser thinks they are Objects).
  554. * @param {*} value A value.
  555. * @return {boolean} Whether the value is an array.
  556. */
  557. o3djs.base.isArray = function(value) {
  558. var valueAsObject = /** @type {!Object} */ (value);
  559. return typeof(value) === 'object' && value !== null &&
  560. 'length' in valueAsObject && 'splice' in valueAsObject;
  561. };
  562. /**
  563. * Check if the o3djs library has been initialized.
  564. * @return {boolean} true if ready, false if not.
  565. */
  566. o3djs.base.ready = function() {
  567. return o3djs.base.o3d != null;
  568. };
  569. /**
  570. * A stub for later optionally converting obfuscated names
  571. * @private
  572. * @param {string} name Name to un-obfuscate.
  573. * @return {string} un-obfuscated name.
  574. */
  575. o3djs.base.maybeDeobfuscateFunctionName_ = function(name) {
  576. return name;
  577. };
  578. /**
  579. * Makes one class inherit from another.
  580. * @param {!Object} subClass Class that wants to inherit.
  581. * @param {!Object} superClass Class to inherit from.
  582. */
  583. o3djs.base.inherit = function(subClass, superClass) {
  584. /**
  585. * TmpClass.
  586. * @constructor
  587. */
  588. var TmpClass = function() { };
  589. TmpClass.prototype = superClass.prototype;
  590. subClass.prototype = new TmpClass();
  591. };
  592. /**
  593. * Parses an error stack from an exception
  594. * @param {!Exception} excp The exception to get a stack trace from.
  595. * @return {!Array.<string>} An array of strings of the stack trace.
  596. */
  597. o3djs.base.parseErrorStack = function(excp) {
  598. var stack = [];
  599. var name;
  600. var line;
  601. if (!excp || !excp.stack) {
  602. return stack;
  603. }
  604. var stacklist = excp.stack.split('\n');
  605. for (var i = 0; i < stacklist.length - 1; i++) {
  606. var framedata = stacklist[i];
  607. name = framedata.match(/^([a-zA-Z0-9_$]*)/)[1];
  608. if (name) {
  609. name = o3djs.base.maybeDeobfuscateFunctionName_(name);
  610. } else {
  611. name = 'anonymous';
  612. }
  613. var result = framedata.match(/(.*:[0-9]+)$/);
  614. line = result && result[1];
  615. if (!line) {
  616. line = '(unknown)';
  617. }
  618. stack[stack.length] = name + ' : ' + line
  619. }
  620. // remove top level anonymous functions to match IE
  621. var omitRegexp = /^anonymous :/;
  622. while (stack.length && omitRegexp.exec(stack[stack.length - 1])) {
  623. stack.length = stack.length - 1;
  624. }
  625. return stack;
  626. };
  627. /**
  628. * Gets a function name from a function object.
  629. * @param {!function(...): *} aFunction The function object to try to get a
  630. * name from.
  631. * @return {string} function name or 'anonymous' if not found.
  632. */
  633. o3djs.base.getFunctionName = function(aFunction) {
  634. var regexpResult = aFunction.toString().match(/function(\s*)(\w*)/);
  635. if (regexpResult && regexpResult.length >= 2 && regexpResult[2]) {
  636. return o3djs.base.maybeDeobfuscateFunctionName_(regexpResult[2]);
  637. }
  638. return 'anonymous';
  639. };
  640. /**
  641. * Pretty prints an exception's stack, if it has one.
  642. * @param {Array.<string>} stack An array of errors.
  643. * @return {string} The pretty stack.
  644. */
  645. o3djs.base.formatErrorStack = function(stack) {
  646. var result = '';
  647. for (var i = 0; i < stack.length; i++) {
  648. result += '> ' + stack[i] + '\n';
  649. }
  650. return result;
  651. };
  652. /**
  653. * Gets a stack trace as a string.
  654. * @param {number} stripCount The number of entries to strip from the top of the
  655. * stack. Example: Pass in 1 to remove yourself from the stack trace.
  656. * @return {string} The stack trace.
  657. */
  658. o3djs.base.getStackTrace = function(stripCount) {
  659. var result = '';
  660. if (typeof(arguments.caller) != 'undefined') { // IE, not ECMA
  661. for (var a = arguments.caller; a != null; a = a.caller) {
  662. result += '> ' + o3djs.base.getFunctionName(a.callee) + '\n';
  663. if (a.caller == a) {
  664. result += '*';
  665. break;
  666. }
  667. }
  668. } else { // Mozilla, not ECMA
  669. // fake an exception so we can get Mozilla's error stack
  670. var testExcp;
  671. try {
  672. eval('var var;');
  673. } catch (testExcp) {
  674. var stack = o3djs.base.parseErrorStack(testExcp);
  675. result += o3djs.base.formatErrorStack(stack.slice(3 + stripCount,
  676. stack.length));
  677. }
  678. }
  679. return result;
  680. };
  681. /**
  682. * Sets the error handler on a client to a handler that displays an alert on the
  683. * first error.
  684. * @param {!o3d.Client} client The client object of the plugin.
  685. */
  686. o3djs.base.setErrorHandler = function(client) {
  687. client.setErrorCallback(
  688. function(msg) {
  689. // Clear the error callback. Otherwise if the callback is happening
  690. // during rendering it's possible the user will not be able to
  691. // get out of an infinite loop of alerts.
  692. client.clearErrorCallback();
  693. alert('ERROR: ' + msg + '\n' + o3djs.base.getStackTrace(1));
  694. });
  695. };
  696. /**
  697. * Returns true if the user's browser is Microsoft IE.
  698. * @return {boolean} true if the user's browser is Microsoft IE.
  699. */
  700. o3djs.base.IsMSIE = function() {
  701. var ua = navigator.userAgent.toLowerCase();
  702. var msie = /msie/.test(ua) && !/opera/.test(ua);
  703. return msie;
  704. };
  705. /**
  706. * Returns true if the user's browser is Chrome 1.0, that requires a workaround
  707. * to create the plugin.
  708. * @return {boolean} true if the user's browser is Chrome 1.0.
  709. */
  710. o3djs.base.IsChrome10 = function() {
  711. return navigator.userAgent.indexOf('Chrome/1.0') >= 0;
  712. };