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.
16 /** Platform, package, object property, and Event support. */
17 this.base = (function() {
19 * Base path for modules. Used to form URLs for module 'require' requests.
21 var moduleBasePath = '.';
22 function setModuleBasePath(path) {
23 if (path[path.length - 1] == '/')
24 path = path.substring(0, path.length - 1);
25 moduleBasePath = path;
28 function mLog(text, opt_indentLevel) {
33 var indentLevel = opt_indentLevel || 0;
34 for (var i = 0; i < indentLevel; i++)
36 console.log(spacing + text);
40 * Builds an object structure for the provided namespace path,
41 * ensuring that names that already exist are not overwritten. For
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}.
50 function exportPath(name, opt_object, opt_objectToExportTo) {
51 var parts = name.split('.');
52 var cur = opt_objectToExportTo || global;
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) {
67 var didLoadModules = false;
68 var moduleDependencies = {};
69 var moduleStylesheets = {};
70 var moduleRawScripts = {};
72 function addModuleDependency(moduleName, dependentModuleName) {
73 if (!moduleDependencies[moduleName])
74 moduleDependencies[moduleName] = [];
76 var dependentModules = moduleDependencies[moduleName];
78 for (var i = 0; i < dependentModules.length; i++)
79 if (dependentModules[i] == dependentModuleName)
82 dependentModules.push(dependentModuleName);
85 function addModuleRawScriptDependency(moduleName, rawScriptName) {
86 if (!moduleRawScripts[moduleName])
87 moduleRawScripts[moduleName] = [];
89 var dependentRawScripts = moduleRawScripts[moduleName];
91 for (var i = 0; i < moduleRawScripts.length; i++)
92 if (dependentRawScripts[i] == rawScriptName)
95 dependentRawScripts.push(rawScriptName);
98 function addModuleStylesheet(moduleName, stylesheetName) {
99 if (!moduleStylesheets[moduleName])
100 moduleStylesheets[moduleName] = [];
102 var stylesheets = moduleStylesheets[moduleName];
104 for (var i = 0; i < stylesheets.length; i++)
105 if (stylesheets[i] == stylesheetName)
108 stylesheets.push(stylesheetName);
111 function ensureDepsLoaded() {
112 if (window.FLATTENED)
117 didLoadModules = true;
119 var req = new XMLHttpRequest();
120 var src = '/deps.js';
121 req.open('GET', src, false);
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';
151 if (!document.body) {
152 setTimeout(function() {
153 document.body.appendChild(baseWarningEl);
156 document.body.appendChild(baseWarningEl);
158 throw new Error(msg);
161 base.addModuleDependency = addModuleDependency;
162 base.addModuleRawScriptDependency = addModuleRawScriptDependency;
163 base.addModuleStylesheet = addModuleStylesheet;
165 // By construction, the deps should call addModuleDependency.
166 eval(req.responseText);
168 throw new Error('When loading deps, got ' +
169 e.stack ? e.stack : e.message);
171 delete base.addModuleStylesheet;
172 delete base.addModuleRawScriptDependency;
173 delete base.addModuleDependency;
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)
182 templatesLoaded_ = true;
184 var req = new XMLHttpRequest();
185 req.open('GET', '/templates', false);
188 var elem = document.createElement('div');
189 elem.innerHTML = req.responseText;
190 while (elem.hasChildNodes())
191 document.head.appendChild(elem.removeChild(elem.firstChild));
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];
203 ensureTemplatesLoaded();
205 dependentModules.forEach(function(module) {
206 requireModule(module, indentLevel);
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');
222 if (moduleLoadStatus[dependentModuleName] == 'APPENDED')
225 if (moduleLoadStatus[dependentModuleName] == 'RESOLVING')
228 mLog('require(' + dependentModuleName + ')', indentLevel);
229 moduleLoadStatus[dependentModuleName] = 'RESOLVING';
230 requireDependencies(dependentModuleName, indentLevel);
232 loadScript(dependentModuleName.replace(/\./g, '/') + '.js');
233 moduleLoadStatus[name] = 'APPENDED';
236 function requireDependencies(dependentModuleName, indentLevel) {
237 // Load the module's dependent scripts after.
238 var dependentModules = moduleDependencies[dependentModuleName] || [];
239 require(dependentModules, indentLevel + 1);
241 // Load the module stylesheet first.
242 var stylesheets = moduleStylesheets[dependentModuleName] || [];
243 for (var i = 0; i < stylesheets.length; i++)
244 requireStylesheet(stylesheets[i]);
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])
253 loadScript(rawScriptName);
254 mLog('load(' + rawScriptName + ')', indentLevel);
255 rawScriptLoadStatus[rawScriptName] = 'APPENDED';
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);
269 * Adds a dependency on a raw javascript file, e.g. a third party
271 * @param {String} rawScriptName The path to the script file, relative to
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');
284 if (rawScriptLoadStatus[rawScriptPath])
286 throw new Error(rawScriptPath + ' should already have been loaded.' +
287 ' Did you forget to run build/generate_about_tracing_contents.py?');
290 var stylesheetLoadStatus = {};
291 function requireStylesheet(dependentStylesheetName) {
292 if (window.FLATTENED)
295 if (stylesheetLoadStatus[dependentStylesheetName])
297 stylesheetLoadStatus[dependentStylesheetName] = true;
299 var localPath = dependentStylesheetName.replace(/\./g, '/') + '.css';
300 var stylesheetPath = moduleBasePath + '/' + localPath;
302 var linkEl = document.createElement('link');
303 linkEl.setAttribute('rel', 'stylesheet');
304 linkEl.setAttribute('href', stylesheetPath);
305 base.doc.head.appendChild(linkEl);
308 var templateLoadStatus = {};
309 function requireTemplate(template) {
310 if (window.FLATTENED)
313 if (templateLoadStatus[template])
315 templateLoadStatus[template] = true;
317 var localPath = template.replace(/\./g, '/') + '.html';
318 var importPath = moduleBasePath + '/' + localPath;
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);
327 function exportTo(namespace, fn) {
328 var obj = exportPath(namespace);
332 console.log('While running exports for ', namespace, ':');
333 console.log(e.stack || e);
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
341 var propertyDescriptor = Object.getOwnPropertyDescriptor(exports,
343 if (propertyDescriptor) {
344 Object.defineProperty(obj, propertyName, propertyDescriptor);
345 mLog(' +' + propertyName);
351 * Initialization which must be deferred until run-time.
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;
359 Object.defineProperty(global, 'base', {
361 Object.defineProperty(global, 'base', {value: originalBase});
362 originalBase.initialize();
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);
380 setModuleBasePath('/src');
384 set moduleBasePath(path) {
385 setModuleBasePath(path);
388 get moduleBasePath() {
389 return moduleBasePath;
392 initialize: initialize,
395 requireStylesheet: requireStylesheet,
396 requireRawScript: requireRawScript,
397 requireTemplate: requireTemplate,