| <!DOCTYPE html> |
| <!-- |
| Copyright (c) 2014 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| |
| <script> |
| 'use strict'; |
| |
| /** |
| * The global object. |
| * @type {!Object} |
| * @const |
| */ |
| var global = this; |
| |
| /** Platform, package, object property, and Event support. */ |
| this.tr = (function() { |
| if (global.tr) { |
| console.warn('Base was multiply initialized. First init wins.'); |
| return global.tr; |
| } |
| |
| /** |
| * Builds an object structure for the provided namespace path, |
| * ensuring that names that already exist are not overwritten. For |
| * example: |
| * 'a.b.c' -> a = {};a.b={};a.b.c={}; |
| * @param {string} name Name of the object that this file defines. |
| * @private |
| */ |
| function exportPath(name) { |
| var parts = name.split('.'); |
| var cur = global; |
| |
| for (var part; parts.length && (part = parts.shift());) { |
| if (part in cur) { |
| cur = cur[part]; |
| } else { |
| cur = cur[part] = {}; |
| } |
| } |
| return cur; |
| }; |
| |
| function isExported(name) { |
| var parts = name.split('.'); |
| var cur = global; |
| |
| for (var part; parts.length && (part = parts.shift());) { |
| if (part in cur) { |
| cur = cur[part]; |
| } else { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| function isDefined(name) { |
| var parts = name.split('.'); |
| |
| var curObject = global; |
| |
| for (var i = 0; i < parts.length; i++) { |
| var partName = parts[i]; |
| var nextObject = curObject[partName]; |
| if (nextObject === undefined) |
| return false; |
| curObject = nextObject; |
| } |
| return true; |
| } |
| |
| var panicElement = undefined; |
| var rawPanicMessages = []; |
| function showPanicElementIfNeeded() { |
| if (panicElement) |
| return; |
| |
| var panicOverlay = document.createElement('div'); |
| panicOverlay.style.backgroundColor = 'white'; |
| panicOverlay.style.border = '3px solid red'; |
| panicOverlay.style.boxSizing = 'border-box'; |
| panicOverlay.style.color = 'black'; |
| panicOverlay.style.display = '-webkit-flex'; |
| panicOverlay.style.height = '100%'; |
| panicOverlay.style.left = 0; |
| panicOverlay.style.padding = '8px'; |
| panicOverlay.style.position = 'fixed'; |
| panicOverlay.style.top = 0; |
| panicOverlay.style.webkitFlexDirection = 'column'; |
| panicOverlay.style.width = '100%'; |
| |
| panicElement = document.createElement('div'); |
| panicElement.style.webkitFlex = '1 1 auto'; |
| panicElement.style.overflow = 'auto'; |
| panicOverlay.appendChild(panicElement); |
| |
| if (!document.body) { |
| setTimeout(function() { |
| document.body.appendChild(panicOverlay); |
| }, 150); |
| } else { |
| document.body.appendChild(panicOverlay); |
| } |
| } |
| |
| function showPanic(panicTitle, panicDetails) { |
| if (tr.isHeadless) { |
| if (panicDetails instanceof Error) |
| throw panicDetails; |
| throw new Error('Panic: ' + panicTitle + ':\n' + panicDetails); |
| } |
| |
| if (panicDetails instanceof Error) |
| panicDetails = panicDetails.stack; |
| |
| showPanicElementIfNeeded(); |
| var panicMessageEl = document.createElement('div'); |
| panicMessageEl.innerHTML = |
| '<h2 id="message"></h2>' + |
| '<pre id="details"></pre>'; |
| panicMessageEl.querySelector('#message').textContent = panicTitle; |
| panicMessageEl.querySelector('#details').textContent = panicDetails; |
| panicElement.appendChild(panicMessageEl); |
| |
| rawPanicMessages.push({ |
| title: panicTitle, |
| details: panicDetails |
| }); |
| } |
| |
| function hasPanic() { |
| return rawPanicMessages.length !== 0; |
| } |
| function getPanicText() { |
| return rawPanicMessages.map(function(msg) { |
| return msg.title; |
| }).join(', '); |
| } |
| |
| function exportTo(namespace, fn) { |
| var obj = exportPath(namespace); |
| var exports = fn(); |
| |
| for (var propertyName in exports) { |
| // Maybe we should check the prototype chain here? The current usage |
| // pattern is always using an object literal so we only care about own |
| // properties. |
| var propertyDescriptor = Object.getOwnPropertyDescriptor(exports, |
| propertyName); |
| if (propertyDescriptor) |
| Object.defineProperty(obj, propertyName, propertyDescriptor); |
| } |
| }; |
| |
| /** |
| * Initialization which must be deferred until run-time. |
| */ |
| function initialize() { |
| if (global.version && global.version()) { |
| tr.isD8 = true; |
| } else if (global.process && global.process.versions.node) { |
| tr.isNode = true; |
| } else { |
| tr.isD8 = false; |
| tr.isNode = false; |
| tr.doc = document; |
| |
| tr.isMac = /Mac/.test(navigator.platform); |
| tr.isWindows = /Win/.test(navigator.platform); |
| tr.isChromeOS = /CrOS/.test(navigator.userAgent); |
| tr.isLinux = /Linux/.test(navigator.userAgent); |
| } |
| tr.isHeadless = tr.isD8 || tr.isNode; |
| } |
| |
| return { |
| initialize: initialize, |
| |
| exportTo: exportTo, |
| isExported: isExported, |
| isDefined: isDefined, |
| |
| showPanic: showPanic, |
| hasPanic: hasPanic, |
| getPanicText: getPanicText |
| }; |
| })(); |
| |
| tr.initialize(); |
| </script> |