Upstream version 5.34.98.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / src / base.js
1 // Copyright (c) 2012 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 'use strict';
6
7
8 /**
9  * The global object.
10  * @type {!Object}
11  * @const
12  */
13 var global = this;
14
15
16 /** Platform, package, object property, and Event support. */
17 this.base = (function() {
18   /**
19    * Base path for modules. Used to form URLs for module 'require' requests.
20    */
21   var moduleBasePath = '.';
22   function setModuleBasePath(path) {
23     if (path[path.length - 1] == '/')
24       path = path.substring(0, path.length - 1);
25     moduleBasePath = path;
26   }
27
28   function mLog(text, opt_indentLevel) {
29     if (true)
30       return;
31
32     var spacing = '';
33     var indentLevel = opt_indentLevel || 0;
34     for (var i = 0; i < indentLevel; i++)
35       spacing += ' ';
36     console.log(spacing + text);
37   }
38
39   /**
40    * Builds an object structure for the provided namespace path,
41    * ensuring that names that already exist are not overwritten. For
42    * example:
43    * 'a.b.c' -> a = {};a.b={};a.b.c={};
44    * @param {string} name Name of the object that this file defines.
45    * @param {*=} opt_object The object to expose at the end of the path.
46    * @param {Object=} opt_objectToExportTo The object to add the path to;
47    *     default is {@code global}.
48    * @private
49    */
50   function exportPath(name, opt_object, opt_objectToExportTo) {
51     var parts = name.split('.');
52     var cur = opt_objectToExportTo || global;
53
54     for (var part; parts.length && (part = parts.shift());) {
55       if (!parts.length && opt_object !== undefined) {
56         // last part and we have an object; use it
57         cur[part] = opt_object;
58       } else if (part in cur) {
59         cur = cur[part];
60       } else {
61         cur = cur[part] = {};
62       }
63     }
64     return cur;
65   };
66
67   var didLoadModules = false;
68   var moduleDependencies = {};
69   var moduleStylesheets = {};
70   var moduleRawScripts = {};
71
72   function addModuleDependency(moduleName, dependentModuleName) {
73     if (!moduleDependencies[moduleName])
74       moduleDependencies[moduleName] = [];
75
76     var dependentModules = moduleDependencies[moduleName];
77     var found = false;
78     for (var i = 0; i < dependentModules.length; i++)
79       if (dependentModules[i] == dependentModuleName)
80         found = true;
81       if (!found)
82         dependentModules.push(dependentModuleName);
83   }
84
85   function addModuleRawScriptDependency(moduleName, rawScriptName) {
86     if (!moduleRawScripts[moduleName])
87       moduleRawScripts[moduleName] = [];
88
89     var dependentRawScripts = moduleRawScripts[moduleName];
90     var found = false;
91     for (var i = 0; i < moduleRawScripts.length; i++)
92       if (dependentRawScripts[i] == rawScriptName)
93         found = true;
94       if (!found)
95         dependentRawScripts.push(rawScriptName);
96   }
97
98   function addModuleStylesheet(moduleName, stylesheetName) {
99     if (!moduleStylesheets[moduleName])
100       moduleStylesheets[moduleName] = [];
101
102     var stylesheets = moduleStylesheets[moduleName];
103     var found = false;
104     for (var i = 0; i < stylesheets.length; i++)
105       if (stylesheets[i] == stylesheetName)
106         found = true;
107       if (!found)
108         stylesheets.push(stylesheetName);
109   }
110
111   function ensureDepsLoaded() {
112     if (window.FLATTENED)
113       return;
114
115     if (didLoadModules)
116       return;
117     didLoadModules = true;
118
119     var req = new XMLHttpRequest();
120     var src = '/deps.js';
121     req.open('GET', src, false);
122     req.send(null);
123     if (req.status != 200) {
124       var serverSideException = JSON.parse(req.responseText);
125       var msg = 'You have a module problem: ' +
126           serverSideException.message;
127       var baseWarningEl = document.createElement('div');
128       baseWarningEl.style.backgroundColor = 'white';
129       baseWarningEl.style.border = '3px solid red';
130       baseWarningEl.style.boxSizing = 'border-box';
131       baseWarningEl.style.color = 'black';
132       baseWarningEl.style.display = '-webkit-flex';
133       baseWarningEl.style.height = '100%';
134       baseWarningEl.style.left = 0;
135       baseWarningEl.style.padding = '8px';
136       baseWarningEl.style.position = 'fixed';
137       baseWarningEl.style.top = 0;
138       baseWarningEl.style.webkitFlexDirection = 'column';
139       baseWarningEl.style.width = '100%';
140       baseWarningEl.innerHTML =
141           '<h2>Module parsing problem</h2>' +
142           '<div id="message"></div>' +
143           '<pre id="details"></pre>';
144       baseWarningEl.querySelector('#message').textContent =
145           serverSideException.message;
146       var detailsEl = baseWarningEl.querySelector('#details');
147       detailsEl.textContent = serverSideException.details;
148       detailsEl.style.webkitFlex = '1 1 auto';
149       detailsEl.style.overflow = 'auto';
150
151       if (!document.body) {
152         setTimeout(function() {
153           document.body.appendChild(baseWarningEl);
154         }, 150);
155       } else {
156         document.body.appendChild(baseWarningEl);
157       }
158       throw new Error(msg);
159     }
160
161     base.addModuleDependency = addModuleDependency;
162     base.addModuleRawScriptDependency = addModuleRawScriptDependency;
163     base.addModuleStylesheet = addModuleStylesheet;
164     try {
165       // By construction, the deps should call addModuleDependency.
166       eval(req.responseText);
167     } catch (e) {
168       throw new Error('When loading deps, got ' +
169                       e.stack ? e.stack : e.message);
170     }
171     delete base.addModuleStylesheet;
172     delete base.addModuleRawScriptDependency;
173     delete base.addModuleDependency;
174   }
175
176   // TODO(dsinclair): Remove this when HTML imports land as the templates
177   // will be pulled in by the requireTemplate calls.
178   var templatesLoaded_ = false;
179   function ensureTemplatesLoaded() {
180     if (templatesLoaded_ || window.FLATTENED)
181       return;
182     templatesLoaded_ = true;
183
184     var req = new XMLHttpRequest();
185     req.open('GET', '/templates', false);
186     req.send(null);
187
188     var elem = document.createElement('div');
189     elem.innerHTML = req.responseText;
190     while (elem.hasChildNodes())
191       document.head.appendChild(elem.removeChild(elem.firstChild));
192   }
193
194   var moduleLoadStatus = {};
195   var rawScriptLoadStatus = {};
196   function require(modules, opt_indentLevel) {
197     var indentLevel = opt_indentLevel || 0;
198     var dependentModules = modules;
199     if (!(modules instanceof Array))
200       dependentModules = [modules];
201
202     ensureDepsLoaded();
203     ensureTemplatesLoaded();
204
205     dependentModules.forEach(function(module) {
206       requireModule(module, indentLevel);
207     });
208   }
209
210   var modulesWaiting = [];
211   function requireModule(dependentModuleName, indentLevel) {
212     if (window.FLATTENED) {
213       if (!window.FLATTENED[dependentModuleName]) {
214         throw new Error('Somehow, module ' + dependentModuleName +
215                         ' didn\'t get stored in the flattened js file! ' +
216                         'You may need to rerun ' +
217                         'build/generate_about_tracing_contents.py');
218       }
219       return;
220     }
221
222     if (moduleLoadStatus[dependentModuleName] == 'APPENDED')
223       return;
224
225     if (moduleLoadStatus[dependentModuleName] == 'RESOLVING')
226       return;
227
228     mLog('require(' + dependentModuleName + ')', indentLevel);
229     moduleLoadStatus[dependentModuleName] = 'RESOLVING';
230     requireDependencies(dependentModuleName, indentLevel);
231
232     loadScript(dependentModuleName.replace(/\./g, '/') + '.js');
233     moduleLoadStatus[name] = 'APPENDED';
234   }
235
236   function requireDependencies(dependentModuleName, indentLevel) {
237     // Load the module's dependent scripts after.
238     var dependentModules = moduleDependencies[dependentModuleName] || [];
239     require(dependentModules, indentLevel + 1);
240
241     // Load the module stylesheet first.
242     var stylesheets = moduleStylesheets[dependentModuleName] || [];
243     for (var i = 0; i < stylesheets.length; i++)
244       requireStylesheet(stylesheets[i]);
245
246     // Load the module raw scripts next
247     var rawScripts = moduleRawScripts[dependentModuleName] || [];
248     for (var i = 0; i < rawScripts.length; i++) {
249       var rawScriptName = rawScripts[i];
250       if (rawScriptLoadStatus[rawScriptName])
251         continue;
252
253       loadScript(rawScriptName);
254       mLog('load(' + rawScriptName + ')', indentLevel);
255       rawScriptLoadStatus[rawScriptName] = 'APPENDED';
256     }
257   }
258
259   function loadScript(path) {
260     var scriptEl = document.createElement('script');
261     scriptEl.src = moduleBasePath + '/' + path;
262     scriptEl.type = 'text/javascript';
263     scriptEl.defer = true;
264     scriptEl.async = false;
265     base.doc.head.appendChild(scriptEl);
266   }
267
268   /**
269    * Adds a dependency on a raw javascript file, e.g. a third party
270    * library.
271    * @param {String} rawScriptName The path to the script file, relative to
272    * moduleBasePath.
273    */
274   function requireRawScript(rawScriptPath) {
275     if (window.FLATTENED_RAW_SCRIPTS) {
276       if (!window.FLATTENED_RAW_SCRIPTS[rawScriptPath]) {
277         throw new Error('Somehow, ' + rawScriptPath +
278             ' didn\'t get stored in the flattened js file! ' +
279             'You may need to rerun build/generate_about_tracing_contents.py');
280       }
281       return;
282     }
283
284     if (rawScriptLoadStatus[rawScriptPath])
285       return;
286     throw new Error(rawScriptPath + ' should already have been loaded.' +
287         ' Did you forget to run build/generate_about_tracing_contents.py?');
288   }
289
290   var stylesheetLoadStatus = {};
291   function requireStylesheet(dependentStylesheetName) {
292     if (window.FLATTENED)
293       return;
294
295     if (stylesheetLoadStatus[dependentStylesheetName])
296       return;
297     stylesheetLoadStatus[dependentStylesheetName] = true;
298
299     var localPath = dependentStylesheetName.replace(/\./g, '/') + '.css';
300     var stylesheetPath = moduleBasePath + '/' + localPath;
301
302     var linkEl = document.createElement('link');
303     linkEl.setAttribute('rel', 'stylesheet');
304     linkEl.setAttribute('href', stylesheetPath);
305     base.doc.head.appendChild(linkEl);
306   }
307
308   var templateLoadStatus = {};
309   function requireTemplate(template) {
310     if (window.FLATTENED)
311       return;
312
313     if (templateLoadStatus[template])
314       return;
315     templateLoadStatus[template] = true;
316
317     var localPath = template.replace(/\./g, '/') + '.html';
318     var importPath = moduleBasePath + '/' + localPath;
319
320     var linkEl = document.createElement('link');
321     linkEl.setAttribute('rel', 'import');
322     linkEl.setAttribute('href', importPath);
323     // TODO(dsinclair): Enable when HTML imports are available.
324     //base.doc.head.appendChild(linkEl);
325   }
326
327   function exportTo(namespace, fn) {
328     var obj = exportPath(namespace);
329     try {
330       var exports = fn();
331     } catch (e) {
332       console.log('While running exports for ', namespace, ':');
333       console.log(e.stack || e);
334       return;
335     }
336
337     for (var propertyName in exports) {
338       // Maybe we should check the prototype chain here? The current usage
339       // pattern is always using an object literal so we only care about own
340       // properties.
341       var propertyDescriptor = Object.getOwnPropertyDescriptor(exports,
342                                                                propertyName);
343       if (propertyDescriptor) {
344         Object.defineProperty(obj, propertyName, propertyDescriptor);
345         mLog('  +' + propertyName);
346       }
347     }
348   };
349
350   /**
351    * Initialization which must be deferred until run-time.
352    */
353   function initialize() {
354     // If 'document' isn't defined, then we must be being pre-compiled,
355     // so set a trap so that we're initialized on first access at run-time.
356     if (!global.document) {
357       var originalBase = base;
358
359       Object.defineProperty(global, 'base', {
360         get: function() {
361           Object.defineProperty(global, 'base', {value: originalBase});
362           originalBase.initialize();
363           return originalBase;
364         },
365         configurable: true
366       });
367
368       return;
369     }
370
371     base.doc = document;
372
373     base.isMac = /Mac/.test(navigator.platform);
374     base.isWindows = /Win/.test(navigator.platform);
375     base.isChromeOS = /CrOS/.test(navigator.userAgent);
376     base.isLinux = /Linux/.test(navigator.userAgent);
377     base.isGTK = /GTK/.test(chrome.toolkit);
378     base.isViews = /views/.test(chrome.toolkit);
379
380     setModuleBasePath('/src');
381   }
382
383   return {
384     set moduleBasePath(path) {
385       setModuleBasePath(path);
386     },
387
388     get moduleBasePath() {
389       return moduleBasePath;
390     },
391
392     initialize: initialize,
393
394     require: require,
395     requireStylesheet: requireStylesheet,
396     requireRawScript: requireRawScript,
397     requireTemplate: requireTemplate,
398     exportTo: exportTo
399   };
400 })();
401
402 base.initialize();