OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2014 Google Inc. All rights reserved. | 2 * Copyright (C) 2014 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
11 * copyright notice, this list of conditions and the following disclaimer | 11 * copyright notice, this list of conditions and the following disclaimer |
12 * in the documentation and/or other materials provided with the | 12 * in the documentation and/or other materials provided with the |
13 * distribution. | 13 * distribution. |
14 * * Neither the name of Google Inc. nor the names of its | 14 * * Neither the name of Google Inc. nor the names of its |
15 * contributors may be used to endorse or promote products derived from | 15 * contributors may be used to endorse or promote products derived from |
16 * this software without specific prior written permission. | 16 * this software without specific prior written permission. |
17 * | 17 * |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 */ | 29 */ |
30 | |
31 // This gets all concatenated module descriptors in the release mode. | 30 // This gets all concatenated module descriptors in the release mode. |
32 var allDescriptors = []; | 31 var allDescriptors = []; |
33 var applicationDescriptor; | 32 var applicationDescriptor; |
34 var _loadedScripts = {}; | 33 var _loadedScripts = {}; |
35 | 34 |
36 // FIXME: This is a workaround to force Closure compiler provide | 35 // FIXME: This is a workaround to force Closure compiler provide |
37 // the standard ES6 runtime for all modules. This should be removed | 36 // the standard ES6 runtime for all modules. This should be removed |
38 // once Closure provides standard externs for Map et al. | 37 // once Closure provides standard externs for Map et al. |
39 for (var k of []) {} | 38 for (var k of []) { |
| 39 } |
40 | 40 |
41 (function() { | 41 (function() { |
42 var baseUrl = self.location ? self.location.origin + self.location.pathname
: ""; | 42 var baseUrl = self.location ? self.location.origin + self.location.pathname :
''; |
43 self._importScriptPathPrefix = baseUrl.substring(0, baseUrl.lastIndexOf("/")
+ 1); | 43 self._importScriptPathPrefix = baseUrl.substring(0, baseUrl.lastIndexOf('/') +
1); |
44 })(); | 44 })(); |
45 | 45 |
46 /** | 46 /** |
47 * @constructor | 47 * @unrestricted |
48 * @param {!Array.<!Runtime.ModuleDescriptor>} descriptors | |
49 */ | 48 */ |
50 function Runtime(descriptors) | 49 var Runtime = class { |
51 { | 50 /** |
| 51 * @param {!Array.<!Runtime.ModuleDescriptor>} descriptors |
| 52 */ |
| 53 constructor(descriptors) { |
52 /** @type {!Array<!Runtime.Module>} */ | 54 /** @type {!Array<!Runtime.Module>} */ |
53 this._modules = []; | 55 this._modules = []; |
54 /** @type {!Object<string, !Runtime.Module>} */ | 56 /** @type {!Object<string, !Runtime.Module>} */ |
55 this._modulesMap = {}; | 57 this._modulesMap = {}; |
56 /** @type {!Array<!Runtime.Extension>} */ | 58 /** @type {!Array<!Runtime.Extension>} */ |
57 this._extensions = []; | 59 this._extensions = []; |
58 /** @type {!Object<string, !function(new:Object)>} */ | 60 /** @type {!Object<string, !function(new:Object)>} */ |
59 this._cachedTypeClasses = {}; | 61 this._cachedTypeClasses = {}; |
60 /** @type {!Object<string, !Runtime.ModuleDescriptor>} */ | 62 /** @type {!Object<string, !Runtime.ModuleDescriptor>} */ |
61 this._descriptorsMap = {}; | 63 this._descriptorsMap = {}; |
62 | 64 |
63 for (var i = 0; i < descriptors.length; ++i) | 65 for (var i = 0; i < descriptors.length; ++i) |
64 this._registerModule(descriptors[i]); | 66 this._registerModule(descriptors[i]); |
65 } | 67 } |
66 | 68 |
67 /** | 69 /** |
68 * @param {string} url | 70 * @param {string} url |
69 * @return {!Promise.<string>} | 71 * @return {!Promise.<string>} |
70 */ | 72 */ |
71 Runtime.loadResourcePromise = function(url) | 73 static loadResourcePromise(url) { |
72 { | |
73 return new Promise(load); | 74 return new Promise(load); |
74 | 75 |
75 /** | 76 /** |
76 * @param {function(?)} fulfill | 77 * @param {function(?)} fulfill |
77 * @param {function(*)} reject | 78 * @param {function(*)} reject |
78 */ | 79 */ |
79 function load(fulfill, reject) | 80 function load(fulfill, reject) { |
80 { | 81 var xhr = new XMLHttpRequest(); |
81 var xhr = new XMLHttpRequest(); | 82 xhr.open('GET', url, true); |
82 xhr.open("GET", url, true); | 83 xhr.onreadystatechange = onreadystatechange; |
83 xhr.onreadystatechange = onreadystatechange; | |
84 | 84 |
85 /** | 85 /** |
86 * @param {Event} e | 86 * @param {Event} e |
87 */ | 87 */ |
88 function onreadystatechange(e) | 88 function onreadystatechange(e) { |
89 { | 89 if (xhr.readyState !== XMLHttpRequest.DONE) |
90 if (xhr.readyState !== XMLHttpRequest.DONE) | 90 return; |
91 return; | |
92 | 91 |
93 if ([0, 200, 304].indexOf(xhr.status) === -1) // Testing harness fi
le:/// results in 0. | 92 if ([0, 200, 304].indexOf(xhr.status) === -1) // Testing harness file:/
// results in 0. |
94 reject(new Error("While loading from url " + url + " server resp
onded with a status of " + xhr.status)); | 93 reject(new Error('While loading from url ' + url + ' server responded
with a status of ' + xhr.status)); |
95 else | 94 else |
96 fulfill(e.target.response); | 95 fulfill(e.target.response); |
97 } | 96 } |
98 xhr.send(null); | 97 xhr.send(null); |
99 } | 98 } |
100 }; | 99 } |
101 | 100 |
102 /** | 101 /** |
103 * http://tools.ietf.org/html/rfc3986#section-5.2.4 | 102 * http://tools.ietf.org/html/rfc3986#section-5.2.4 |
104 * @param {string} path | 103 * @param {string} path |
105 * @return {string} | 104 * @return {string} |
106 */ | 105 */ |
107 Runtime.normalizePath = function(path) | 106 static normalizePath(path) { |
108 { | 107 if (path.indexOf('..') === -1 && path.indexOf('.') === -1) |
109 if (path.indexOf("..") === -1 && path.indexOf(".") === -1) | 108 return path; |
110 return path; | |
111 | 109 |
112 var normalizedSegments = []; | 110 var normalizedSegments = []; |
113 var segments = path.split("/"); | 111 var segments = path.split('/'); |
114 for (var i = 0; i < segments.length; i++) { | 112 for (var i = 0; i < segments.length; i++) { |
115 var segment = segments[i]; | 113 var segment = segments[i]; |
116 if (segment === ".") | 114 if (segment === '.') |
117 continue; | 115 continue; |
118 else if (segment === "..") | 116 else if (segment === '..') |
119 normalizedSegments.pop(); | 117 normalizedSegments.pop(); |
120 else if (segment) | 118 else if (segment) |
121 normalizedSegments.push(segment); | 119 normalizedSegments.push(segment); |
122 } | 120 } |
123 var normalizedPath = normalizedSegments.join("/"); | 121 var normalizedPath = normalizedSegments.join('/'); |
124 if (normalizedPath[normalizedPath.length - 1] === "/") | 122 if (normalizedPath[normalizedPath.length - 1] === '/') |
125 return normalizedPath; | 123 return normalizedPath; |
126 if (path[0] === "/" && normalizedPath) | 124 if (path[0] === '/' && normalizedPath) |
127 normalizedPath = "/" + normalizedPath; | 125 normalizedPath = '/' + normalizedPath; |
128 if ((path[path.length - 1] === "/") || (segments[segments.length - 1] === ".
") || (segments[segments.length - 1] === "..")) | 126 if ((path[path.length - 1] === '/') || (segments[segments.length - 1] === '.
') || |
129 normalizedPath = normalizedPath + "/"; | 127 (segments[segments.length - 1] === '..')) |
| 128 normalizedPath = normalizedPath + '/'; |
130 | 129 |
131 return normalizedPath; | 130 return normalizedPath; |
132 }; | 131 } |
133 | 132 |
134 /** | 133 /** |
135 * @param {!Array.<string>} scriptNames | 134 * @param {!Array.<string>} scriptNames |
136 * @param {string=} base | 135 * @param {string=} base |
137 * @return {!Promise.<undefined>} | 136 * @return {!Promise.<undefined>} |
138 */ | 137 */ |
139 Runtime._loadScriptsPromise = function(scriptNames, base) | 138 static _loadScriptsPromise(scriptNames, base) { |
140 { | |
141 /** @type {!Array<!Promise<undefined>>} */ | 139 /** @type {!Array<!Promise<undefined>>} */ |
142 var promises = []; | 140 var promises = []; |
143 /** @type {!Array<string>} */ | 141 /** @type {!Array<string>} */ |
144 var urls = []; | 142 var urls = []; |
145 var sources = new Array(scriptNames.length); | 143 var sources = new Array(scriptNames.length); |
146 var scriptToEval = 0; | 144 var scriptToEval = 0; |
147 for (var i = 0; i < scriptNames.length; ++i) { | 145 for (var i = 0; i < scriptNames.length; ++i) { |
148 var scriptName = scriptNames[i]; | 146 var scriptName = scriptNames[i]; |
149 var sourceURL = (base || self._importScriptPathPrefix) + scriptName; | 147 var sourceURL = (base || self._importScriptPathPrefix) + scriptName; |
150 | 148 |
151 var schemaIndex = sourceURL.indexOf("://") + 3; | 149 var schemaIndex = sourceURL.indexOf('://') + 3; |
152 var pathIndex = sourceURL.indexOf("/", schemaIndex); | 150 var pathIndex = sourceURL.indexOf('/', schemaIndex); |
153 if (pathIndex === -1) | 151 if (pathIndex === -1) |
154 pathIndex = sourceURL.length; | 152 pathIndex = sourceURL.length; |
155 sourceURL = sourceURL.substring(0, pathIndex) + Runtime.normalizePath(so
urceURL.substring(pathIndex)); | 153 sourceURL = sourceURL.substring(0, pathIndex) + Runtime.normalizePath(sour
ceURL.substring(pathIndex)); |
156 | 154 |
157 if (_loadedScripts[sourceURL]) | 155 if (_loadedScripts[sourceURL]) |
158 continue; | 156 continue; |
159 urls.push(sourceURL); | 157 urls.push(sourceURL); |
160 promises.push(Runtime.loadResourcePromise(sourceURL).then(scriptSourceLo
aded.bind(null, i), scriptSourceLoaded.bind(null, i, undefined))); | 158 promises.push(Runtime.loadResourcePromise(sourceURL).then( |
| 159 scriptSourceLoaded.bind(null, i), scriptSourceLoaded.bind(null, i, und
efined))); |
161 } | 160 } |
162 return Promise.all(promises).then(undefined); | 161 return Promise.all(promises).then(undefined); |
163 | 162 |
164 /** | 163 /** |
165 * @param {number} scriptNumber | 164 * @param {number} scriptNumber |
166 * @param {string=} scriptSource | 165 * @param {string=} scriptSource |
167 */ | 166 */ |
168 function scriptSourceLoaded(scriptNumber, scriptSource) | 167 function scriptSourceLoaded(scriptNumber, scriptSource) { |
169 { | 168 sources[scriptNumber] = scriptSource || ''; |
170 sources[scriptNumber] = scriptSource || ""; | 169 // Eval scripts as fast as possible. |
171 // Eval scripts as fast as possible. | 170 while (typeof sources[scriptToEval] !== 'undefined') { |
172 while (typeof sources[scriptToEval] !== "undefined") { | 171 evaluateScript(urls[scriptToEval], sources[scriptToEval]); |
173 evaluateScript(urls[scriptToEval], sources[scriptToEval]); | 172 ++scriptToEval; |
174 ++scriptToEval; | 173 } |
175 } | |
176 } | 174 } |
177 | 175 |
178 /** | 176 /** |
179 * @param {string} sourceURL | 177 * @param {string} sourceURL |
180 * @param {string=} scriptSource | 178 * @param {string=} scriptSource |
181 */ | 179 */ |
182 function evaluateScript(sourceURL, scriptSource) | 180 function evaluateScript(sourceURL, scriptSource) { |
183 { | 181 _loadedScripts[sourceURL] = true; |
184 _loadedScripts[sourceURL] = true; | 182 if (!scriptSource) { |
185 if (!scriptSource) { | 183 // Do not reject, as this is normal in the hosted mode. |
186 // Do not reject, as this is normal in the hosted mode. | 184 console.error('Empty response arrived for script \'' + sourceURL + '\'')
; |
187 console.error("Empty response arrived for script '" + sourceURL + "'
"); | 185 return; |
188 return; | 186 } |
189 } | 187 self.eval(scriptSource + '\n//# sourceURL=' + sourceURL); |
190 self.eval(scriptSource + "\n//# sourceURL=" + sourceURL); | |
191 } | 188 } |
192 }; | 189 } |
193 | 190 |
194 /** | 191 /** |
195 * @type {!Object.<string, string>} | 192 * @param {string} url |
196 */ | 193 * @param {boolean} appendSourceURL |
197 Runtime._queryParamsObject = { __proto__: null }; | 194 * @return {!Promise<undefined>} |
198 | 195 */ |
199 Runtime._instanceSymbol = Symbol("instance"); | 196 static loadResourceIntoCache(url, appendSourceURL) { |
200 Runtime._extensionSymbol = Symbol("extension"); | 197 return Runtime.loadResourcePromise(url).then( |
201 | 198 cacheResource.bind(this, url), cacheResource.bind(this, url, undefined))
; |
202 /** | |
203 * @type {!Object.<string, string>} | |
204 */ | |
205 Runtime.cachedResources = { __proto__: null }; | |
206 | |
207 /** | |
208 * @param {string} url | |
209 * @param {boolean} appendSourceURL | |
210 * @return {!Promise<undefined>} | |
211 */ | |
212 Runtime.loadResourceIntoCache = function(url, appendSourceURL) | |
213 { | |
214 return Runtime.loadResourcePromise(url).then(cacheResource.bind(this, url),
cacheResource.bind(this, url, undefined)); | |
215 | 199 |
216 /** | 200 /** |
217 * @param {string} path | 201 * @param {string} path |
218 * @param {string=} content | 202 * @param {string=} content |
219 */ | 203 */ |
220 function cacheResource(path, content) | 204 function cacheResource(path, content) { |
221 { | 205 if (!content) { |
222 if (!content) { | 206 console.error('Failed to load resource: ' + path); |
223 console.error("Failed to load resource: " + path); | 207 return; |
224 return; | 208 } |
225 } | 209 var sourceURL = appendSourceURL ? Runtime.resolveSourceURL(path) : ''; |
226 var sourceURL = appendSourceURL ? Runtime.resolveSourceURL(path) : ""; | 210 Runtime.cachedResources[path] = content + sourceURL; |
227 Runtime.cachedResources[path] = content + sourceURL; | |
228 } | 211 } |
229 }; | 212 } |
230 | 213 |
231 /** | 214 /** |
232 * @param {string} appName | 215 * @param {string} appName |
233 * @return {!Promise.<undefined>} | 216 * @return {!Promise.<undefined>} |
234 */ | 217 */ |
235 Runtime.startApplication = function(appName) | 218 static startApplication(appName) { |
236 { | 219 console.timeStamp('Runtime.startApplication'); |
237 console.timeStamp("Runtime.startApplication"); | |
238 | 220 |
239 var allDescriptorsByName = {}; | 221 var allDescriptorsByName = {}; |
240 for (var i = 0; i < allDescriptors.length; ++i) { | 222 for (var i = 0; i < allDescriptors.length; ++i) { |
241 var d = allDescriptors[i]; | 223 var d = allDescriptors[i]; |
242 allDescriptorsByName[d["name"]] = d; | 224 allDescriptorsByName[d['name']] = d; |
243 } | 225 } |
244 | 226 |
245 var applicationPromise; | 227 var applicationPromise; |
246 if (applicationDescriptor) | 228 if (applicationDescriptor) |
247 applicationPromise = Promise.resolve(applicationDescriptor); | 229 applicationPromise = Promise.resolve(applicationDescriptor); |
248 else | 230 else |
249 applicationPromise = Runtime.loadResourcePromise(appName + ".json").then
(JSON.parse.bind(JSON)); | 231 applicationPromise = Runtime.loadResourcePromise(appName + '.json').then(J
SON.parse.bind(JSON)); |
250 | 232 |
251 return applicationPromise.then(parseModuleDescriptors); | 233 return applicationPromise.then(parseModuleDescriptors); |
252 | 234 |
253 /** | 235 /** |
254 * @param {!{modules: !Array.<!Object>, has_html: boolean}} appDescriptor | 236 * @param {!{modules: !Array.<!Object>, has_html: boolean}} appDescriptor |
255 * @return {!Promise.<undefined>} | 237 * @return {!Promise.<undefined>} |
256 */ | 238 */ |
257 function parseModuleDescriptors(appDescriptor) | 239 function parseModuleDescriptors(appDescriptor) { |
258 { | 240 var configuration = appDescriptor.modules; |
259 var configuration = appDescriptor.modules; | 241 var moduleJSONPromises = []; |
260 var moduleJSONPromises = []; | 242 var coreModuleNames = []; |
261 var coreModuleNames = []; | 243 for (var i = 0; i < configuration.length; ++i) { |
262 for (var i = 0; i < configuration.length; ++i) { | 244 var descriptor = configuration[i]; |
263 var descriptor = configuration[i]; | 245 var name = descriptor['name']; |
264 var name = descriptor["name"]; | 246 var moduleJSON = allDescriptorsByName[name]; |
265 var moduleJSON = allDescriptorsByName[name]; | 247 if (moduleJSON) |
266 if (moduleJSON) | 248 moduleJSONPromises.push(Promise.resolve(moduleJSON)); |
267 moduleJSONPromises.push(Promise.resolve(moduleJSON)); | 249 else |
268 else | 250 moduleJSONPromises.push(Runtime.loadResourcePromise(name + '/module.js
on').then(JSON.parse.bind(JSON))); |
269 moduleJSONPromises.push(Runtime.loadResourcePromise(name + "/mod
ule.json").then(JSON.parse.bind(JSON))); | 251 if (descriptor['type'] === 'autostart') |
270 if (descriptor["type"] === "autostart") | 252 coreModuleNames.push(name); |
271 coreModuleNames.push(name); | 253 } |
| 254 |
| 255 return Promise.all(moduleJSONPromises).then(instantiateRuntime); |
| 256 |
| 257 /** |
| 258 * @param {!Array.<!Object>} moduleDescriptors |
| 259 * @return {!Promise.<undefined>} |
| 260 */ |
| 261 function instantiateRuntime(moduleDescriptors) { |
| 262 for (var i = 0; i < moduleDescriptors.length; ++i) { |
| 263 moduleDescriptors[i].name = configuration[i]['name']; |
| 264 moduleDescriptors[i].condition = configuration[i]['condition']; |
| 265 moduleDescriptors[i].remote = configuration[i]['type'] === 'remote'; |
272 } | 266 } |
273 | 267 self.runtime = new Runtime(moduleDescriptors); |
274 return Promise.all(moduleJSONPromises).then(instantiateRuntime); | 268 if (coreModuleNames) |
275 | 269 return /** @type {!Promise<undefined>} */ (self.runtime._loadAutoStart
Modules(coreModuleNames)); |
276 /** | 270 return Promise.resolve(); |
277 * @param {!Array.<!Object>} moduleDescriptors | 271 } |
278 * @return {!Promise.<undefined>} | 272 } |
279 */ | 273 } |
280 function instantiateRuntime(moduleDescriptors) | 274 |
281 { | 275 /** |
282 for (var i = 0; i < moduleDescriptors.length; ++i) { | 276 * @param {string} appName |
283 moduleDescriptors[i].name = configuration[i]["name"]; | 277 * @return {!Promise.<undefined>} |
284 moduleDescriptors[i].condition = configuration[i]["condition"]; | 278 */ |
285 moduleDescriptors[i].remote = configuration[i]["type"] === "remo
te"; | 279 static startWorker(appName) { |
286 } | 280 return Runtime.startApplication(appName).then(sendWorkerReady); |
287 self.runtime = new Runtime(moduleDescriptors); | 281 |
288 if (coreModuleNames) | 282 function sendWorkerReady() { |
289 return /** @type {!Promise<undefined>} */ (self.runtime._loadAut
oStartModules(coreModuleNames)); | 283 self.postMessage('workerReady'); |
290 return Promise.resolve(); | 284 } |
291 } | 285 } |
292 } | 286 |
| 287 /** |
| 288 * @param {string} appName |
| 289 */ |
| 290 static startSharedWorker(appName) { |
| 291 var startPromise = Runtime.startApplication(appName); |
| 292 |
| 293 /** |
| 294 * @param {!MessageEvent} event |
| 295 */ |
| 296 self.onconnect = function(event) { |
| 297 var newPort = /** @type {!MessagePort} */ (event.ports[0]); |
| 298 startPromise.then(sendWorkerReadyAndContinue); |
| 299 |
| 300 function sendWorkerReadyAndContinue() { |
| 301 newPort.postMessage('workerReady'); |
| 302 if (Runtime._sharedWorkerNewPortCallback) |
| 303 Runtime._sharedWorkerNewPortCallback.call(null, newPort); |
| 304 else |
| 305 Runtime._sharedWorkerConnectedPorts.push(newPort); |
| 306 } |
| 307 }; |
| 308 } |
| 309 |
| 310 /** |
| 311 * @param {function(!MessagePort)} callback |
| 312 */ |
| 313 static setSharedWorkerNewPortCallback(callback) { |
| 314 Runtime._sharedWorkerNewPortCallback = callback; |
| 315 while (Runtime._sharedWorkerConnectedPorts.length) { |
| 316 var port = Runtime._sharedWorkerConnectedPorts.shift(); |
| 317 callback.call(null, port); |
| 318 } |
| 319 } |
| 320 |
| 321 /** |
| 322 * @param {string} name |
| 323 * @return {?string} |
| 324 */ |
| 325 static queryParam(name) { |
| 326 return Runtime._queryParamsObject[name] || null; |
| 327 } |
| 328 |
| 329 /** |
| 330 * @return {!Object} |
| 331 */ |
| 332 static _experimentsSetting() { |
| 333 try { |
| 334 return /** @type {!Object} */ ( |
| 335 JSON.parse(self.localStorage && self.localStorage['experiments'] ? sel
f.localStorage['experiments'] : '{}')); |
| 336 } catch (e) { |
| 337 console.error('Failed to parse localStorage[\'experiments\']'); |
| 338 return {}; |
| 339 } |
| 340 } |
| 341 |
| 342 static _assert(value, message) { |
| 343 if (value) |
| 344 return; |
| 345 Runtime._originalAssert.call(Runtime._console, value, message + ' ' + new Er
ror().stack); |
| 346 } |
| 347 |
| 348 /** |
| 349 * @param {string} platform |
| 350 */ |
| 351 static setPlatform(platform) { |
| 352 Runtime._platform = platform; |
| 353 } |
| 354 |
| 355 /** |
| 356 * @param {!Object} descriptor |
| 357 * @return {boolean} |
| 358 */ |
| 359 static _isDescriptorEnabled(descriptor) { |
| 360 var activatorExperiment = descriptor['experiment']; |
| 361 if (activatorExperiment === '*') |
| 362 return Runtime.experiments.supportEnabled(); |
| 363 if (activatorExperiment && activatorExperiment.startsWith('!') && |
| 364 Runtime.experiments.isEnabled(activatorExperiment.substring(1))) |
| 365 return false; |
| 366 if (activatorExperiment && !activatorExperiment.startsWith('!') && |
| 367 !Runtime.experiments.isEnabled(activatorExperiment)) |
| 368 return false; |
| 369 var condition = descriptor['condition']; |
| 370 if (condition && !condition.startsWith('!') && !Runtime.queryParam(condition
)) |
| 371 return false; |
| 372 if (condition && condition.startsWith('!') && Runtime.queryParam(condition.s
ubstring(1))) |
| 373 return false; |
| 374 return true; |
| 375 } |
| 376 |
| 377 /** |
| 378 * @param {string} path |
| 379 * @return {string} |
| 380 */ |
| 381 static resolveSourceURL(path) { |
| 382 var sourceURL = self.location.href; |
| 383 if (self.location.search) |
| 384 sourceURL = sourceURL.replace(self.location.search, ''); |
| 385 sourceURL = sourceURL.substring(0, sourceURL.lastIndexOf('/') + 1) + path; |
| 386 return '\n/*# sourceURL=' + sourceURL + ' */'; |
| 387 } |
| 388 |
| 389 useTestBase() { |
| 390 Runtime._remoteBase = 'http://localhost:8000/inspector-sources/'; |
| 391 if (Runtime.queryParam('debugFrontend')) |
| 392 Runtime._remoteBase += 'debug/'; |
| 393 } |
| 394 |
| 395 /** |
| 396 * @param {!Runtime.ModuleDescriptor} descriptor |
| 397 */ |
| 398 _registerModule(descriptor) { |
| 399 var module = new Runtime.Module(this, descriptor); |
| 400 this._modules.push(module); |
| 401 this._modulesMap[descriptor['name']] = module; |
| 402 } |
| 403 |
| 404 /** |
| 405 * @param {string} moduleName |
| 406 * @return {!Promise.<undefined>} |
| 407 */ |
| 408 loadModulePromise(moduleName) { |
| 409 return this._modulesMap[moduleName]._loadPromise(); |
| 410 } |
| 411 |
| 412 /** |
| 413 * @param {!Array.<string>} moduleNames |
| 414 * @return {!Promise.<!Array.<*>>} |
| 415 */ |
| 416 _loadAutoStartModules(moduleNames) { |
| 417 var promises = []; |
| 418 for (var i = 0; i < moduleNames.length; ++i) |
| 419 promises.push(this.loadModulePromise(moduleNames[i])); |
| 420 return Promise.all(promises); |
| 421 } |
| 422 |
| 423 /** |
| 424 * @param {!Runtime.Extension} extension |
| 425 * @param {?function(function(new:Object)):boolean} predicate |
| 426 * @return {boolean} |
| 427 */ |
| 428 _checkExtensionApplicability(extension, predicate) { |
| 429 if (!predicate) |
| 430 return false; |
| 431 var contextTypes = extension.descriptor().contextTypes; |
| 432 if (!contextTypes) |
| 433 return true; |
| 434 for (var i = 0; i < contextTypes.length; ++i) { |
| 435 var contextType = this._resolve(contextTypes[i]); |
| 436 var isMatching = !!contextType && predicate(contextType); |
| 437 if (isMatching) |
| 438 return true; |
| 439 } |
| 440 return false; |
| 441 } |
| 442 |
| 443 /** |
| 444 * @param {!Runtime.Extension} extension |
| 445 * @param {?Object} context |
| 446 * @return {boolean} |
| 447 */ |
| 448 isExtensionApplicableToContext(extension, context) { |
| 449 if (!context) |
| 450 return true; |
| 451 return this._checkExtensionApplicability(extension, isInstanceOf); |
| 452 |
| 453 /** |
| 454 * @param {!Function} targetType |
| 455 * @return {boolean} |
| 456 */ |
| 457 function isInstanceOf(targetType) { |
| 458 return context instanceof targetType; |
| 459 } |
| 460 } |
| 461 |
| 462 /** |
| 463 * @param {!Runtime.Extension} extension |
| 464 * @param {!Set.<!Function>=} currentContextTypes |
| 465 * @return {boolean} |
| 466 */ |
| 467 isExtensionApplicableToContextTypes(extension, currentContextTypes) { |
| 468 if (!extension.descriptor().contextTypes) |
| 469 return true; |
| 470 |
| 471 return this._checkExtensionApplicability(extension, currentContextTypes ? is
ContextTypeKnown : null); |
| 472 |
| 473 /** |
| 474 * @param {!Function} targetType |
| 475 * @return {boolean} |
| 476 */ |
| 477 function isContextTypeKnown(targetType) { |
| 478 return currentContextTypes.has(targetType); |
| 479 } |
| 480 } |
| 481 |
| 482 /** |
| 483 * @param {*} type |
| 484 * @param {?Object=} context |
| 485 * @param {boolean=} sortByTitle |
| 486 * @return {!Array.<!Runtime.Extension>} |
| 487 */ |
| 488 extensions(type, context, sortByTitle) { |
| 489 return this._extensions.filter(filter).sort(sortByTitle ? titleComparator :
orderComparator); |
| 490 |
| 491 /** |
| 492 * @param {!Runtime.Extension} extension |
| 493 * @return {boolean} |
| 494 */ |
| 495 function filter(extension) { |
| 496 if (extension._type !== type && extension._typeClass() !== type) |
| 497 return false; |
| 498 if (!extension.enabled()) |
| 499 return false; |
| 500 return !context || extension.isApplicable(context); |
| 501 } |
| 502 |
| 503 /** |
| 504 * @param {!Runtime.Extension} extension1 |
| 505 * @param {!Runtime.Extension} extension2 |
| 506 * @return {number} |
| 507 */ |
| 508 function orderComparator(extension1, extension2) { |
| 509 var order1 = extension1.descriptor()['order'] || 0; |
| 510 var order2 = extension2.descriptor()['order'] || 0; |
| 511 return order1 - order2; |
| 512 } |
| 513 |
| 514 /** |
| 515 * @param {!Runtime.Extension} extension1 |
| 516 * @param {!Runtime.Extension} extension2 |
| 517 * @return {number} |
| 518 */ |
| 519 function titleComparator(extension1, extension2) { |
| 520 var title1 = extension1.title() || ''; |
| 521 var title2 = extension2.title() || ''; |
| 522 return title1.localeCompare(title2); |
| 523 } |
| 524 } |
| 525 |
| 526 /** |
| 527 * @param {*} type |
| 528 * @param {?Object=} context |
| 529 * @return {?Runtime.Extension} |
| 530 */ |
| 531 extension(type, context) { |
| 532 return this.extensions(type, context)[0] || null; |
| 533 } |
| 534 |
| 535 /** |
| 536 * @param {*} type |
| 537 * @param {?Object=} context |
| 538 * @return {!Promise.<!Array.<!Object>>} |
| 539 */ |
| 540 allInstances(type, context) { |
| 541 return Promise.all(this.extensions(type, context).map(extension => extension
.instance())); |
| 542 } |
| 543 |
| 544 /** |
| 545 * @return {?function(new:Object)} |
| 546 */ |
| 547 _resolve(typeName) { |
| 548 if (!this._cachedTypeClasses[typeName]) { |
| 549 var path = typeName.split('.'); |
| 550 var object = self; |
| 551 for (var i = 0; object && (i < path.length); ++i) |
| 552 object = object[path[i]]; |
| 553 if (object) |
| 554 this._cachedTypeClasses[typeName] = /** @type function(new:Object) */ (o
bject); |
| 555 } |
| 556 return this._cachedTypeClasses[typeName] || null; |
| 557 } |
| 558 |
| 559 /** |
| 560 * @param {!Function} constructorFunction |
| 561 * @return {!Object} |
| 562 */ |
| 563 sharedInstance(constructorFunction) { |
| 564 if (Runtime._instanceSymbol in constructorFunction) |
| 565 return constructorFunction[Runtime._instanceSymbol]; |
| 566 var instance = new constructorFunction(); |
| 567 constructorFunction[Runtime._instanceSymbol] = instance; |
| 568 return instance; |
| 569 } |
| 570 } |
| 571 |
| 572 ; |
| 573 |
| 574 |
| 575 /** |
| 576 * @type {!Object.<string, string>} |
| 577 */ |
| 578 Runtime._queryParamsObject = { |
| 579 __proto__: null |
293 }; | 580 }; |
294 | 581 |
| 582 Runtime._instanceSymbol = Symbol('instance'); |
| 583 Runtime._extensionSymbol = Symbol('extension'); |
| 584 |
295 /** | 585 /** |
296 * @param {string} appName | 586 * @type {!Object.<string, string>} |
297 * @return {!Promise.<undefined>} | |
298 */ | 587 */ |
299 Runtime.startWorker = function(appName) | 588 Runtime.cachedResources = { |
300 { | 589 __proto__: null |
301 return Runtime.startApplication(appName).then(sendWorkerReady); | |
302 | |
303 function sendWorkerReady() | |
304 { | |
305 self.postMessage("workerReady"); | |
306 } | |
307 }; | 590 }; |
308 | 591 |
| 592 |
309 /** @type {?function(!MessagePort)} */ | 593 /** @type {?function(!MessagePort)} */ |
310 Runtime._sharedWorkerNewPortCallback = null; | 594 Runtime._sharedWorkerNewPortCallback = null; |
311 /** @type {!Array<!MessagePort>} */ | 595 /** @type {!Array<!MessagePort>} */ |
312 Runtime._sharedWorkerConnectedPorts = []; | 596 Runtime._sharedWorkerConnectedPorts = []; |
313 | 597 |
314 /** | |
315 * @param {string} appName | |
316 */ | |
317 Runtime.startSharedWorker = function(appName) | |
318 { | |
319 var startPromise = Runtime.startApplication(appName); | |
320 | |
321 /** | |
322 * @param {!MessageEvent} event | |
323 */ | |
324 self.onconnect = function(event) | |
325 { | |
326 var newPort = /** @type {!MessagePort} */ (event.ports[0]); | |
327 startPromise.then(sendWorkerReadyAndContinue); | |
328 | |
329 function sendWorkerReadyAndContinue() | |
330 { | |
331 newPort.postMessage("workerReady"); | |
332 if (Runtime._sharedWorkerNewPortCallback) | |
333 Runtime._sharedWorkerNewPortCallback.call(null, newPort); | |
334 else | |
335 Runtime._sharedWorkerConnectedPorts.push(newPort); | |
336 } | |
337 }; | |
338 }; | |
339 | |
340 /** | |
341 * @param {function(!MessagePort)} callback | |
342 */ | |
343 Runtime.setSharedWorkerNewPortCallback = function(callback) | |
344 { | |
345 Runtime._sharedWorkerNewPortCallback = callback; | |
346 while (Runtime._sharedWorkerConnectedPorts.length) { | |
347 var port = Runtime._sharedWorkerConnectedPorts.shift(); | |
348 callback.call(null, port); | |
349 } | |
350 }; | |
351 | |
352 /** | |
353 * @param {string} name | |
354 * @return {?string} | |
355 */ | |
356 Runtime.queryParam = function(name) | |
357 { | |
358 return Runtime._queryParamsObject[name] || null; | |
359 }; | |
360 | |
361 /** | |
362 * @return {!Object} | |
363 */ | |
364 Runtime._experimentsSetting = function() | |
365 { | |
366 try { | |
367 return /** @type {!Object} */ (JSON.parse(self.localStorage && self.loca
lStorage["experiments"] ? self.localStorage["experiments"] : "{}")); | |
368 } catch (e) { | |
369 console.error("Failed to parse localStorage['experiments']"); | |
370 return {}; | |
371 } | |
372 }; | |
373 | 598 |
374 Runtime._console = console; | 599 Runtime._console = console; |
375 Runtime._originalAssert = console.assert; | 600 Runtime._originalAssert = console.assert; |
376 Runtime._assert = function(value, message) | 601 |
377 { | 602 |
378 if (value) | 603 Runtime._platform = ''; |
379 return; | 604 |
380 Runtime._originalAssert.call(Runtime._console, value, message + " " + new Er
ror().stack); | |
381 }; | |
382 | |
383 Runtime._platform = ""; | |
384 | 605 |
385 /** | 606 /** |
386 * @param {string} platform | 607 * @unrestricted |
387 */ | 608 */ |
388 Runtime.setPlatform = function(platform) | 609 Runtime.ModuleDescriptor = class { |
389 { | 610 constructor() { |
390 Runtime._platform = platform; | |
391 }; | |
392 | |
393 Runtime.prototype = { | |
394 useTestBase: function() | |
395 { | |
396 Runtime._remoteBase = "http://localhost:8000/inspector-sources/"; | |
397 if (Runtime.queryParam("debugFrontend")) | |
398 Runtime._remoteBase += "debug/"; | |
399 }, | |
400 | |
401 /** | |
402 * @param {!Runtime.ModuleDescriptor} descriptor | |
403 */ | |
404 _registerModule: function(descriptor) | |
405 { | |
406 var module = new Runtime.Module(this, descriptor); | |
407 this._modules.push(module); | |
408 this._modulesMap[descriptor["name"]] = module; | |
409 }, | |
410 | |
411 /** | |
412 * @param {string} moduleName | |
413 * @return {!Promise.<undefined>} | |
414 */ | |
415 loadModulePromise: function(moduleName) | |
416 { | |
417 return this._modulesMap[moduleName]._loadPromise(); | |
418 }, | |
419 | |
420 /** | |
421 * @param {!Array.<string>} moduleNames | |
422 * @return {!Promise.<!Array.<*>>} | |
423 */ | |
424 _loadAutoStartModules: function(moduleNames) | |
425 { | |
426 var promises = []; | |
427 for (var i = 0; i < moduleNames.length; ++i) | |
428 promises.push(this.loadModulePromise(moduleNames[i])); | |
429 return Promise.all(promises); | |
430 }, | |
431 | |
432 /** | |
433 * @param {!Runtime.Extension} extension | |
434 * @param {?function(function(new:Object)):boolean} predicate | |
435 * @return {boolean} | |
436 */ | |
437 _checkExtensionApplicability: function(extension, predicate) | |
438 { | |
439 if (!predicate) | |
440 return false; | |
441 var contextTypes = extension.descriptor().contextTypes; | |
442 if (!contextTypes) | |
443 return true; | |
444 for (var i = 0; i < contextTypes.length; ++i) { | |
445 var contextType = this._resolve(contextTypes[i]); | |
446 var isMatching = !!contextType && predicate(contextType); | |
447 if (isMatching) | |
448 return true; | |
449 } | |
450 return false; | |
451 }, | |
452 | |
453 /** | |
454 * @param {!Runtime.Extension} extension | |
455 * @param {?Object} context | |
456 * @return {boolean} | |
457 */ | |
458 isExtensionApplicableToContext: function(extension, context) | |
459 { | |
460 if (!context) | |
461 return true; | |
462 return this._checkExtensionApplicability(extension, isInstanceOf); | |
463 | |
464 /** | |
465 * @param {!Function} targetType | |
466 * @return {boolean} | |
467 */ | |
468 function isInstanceOf(targetType) | |
469 { | |
470 return context instanceof targetType; | |
471 } | |
472 }, | |
473 | |
474 /** | |
475 * @param {!Runtime.Extension} extension | |
476 * @param {!Set.<!Function>=} currentContextTypes | |
477 * @return {boolean} | |
478 */ | |
479 isExtensionApplicableToContextTypes: function(extension, currentContextTypes
) | |
480 { | |
481 if (!extension.descriptor().contextTypes) | |
482 return true; | |
483 | |
484 return this._checkExtensionApplicability(extension, currentContextTypes
? isContextTypeKnown : null); | |
485 | |
486 /** | |
487 * @param {!Function} targetType | |
488 * @return {boolean} | |
489 */ | |
490 function isContextTypeKnown(targetType) | |
491 { | |
492 return currentContextTypes.has(targetType); | |
493 } | |
494 }, | |
495 | |
496 /** | |
497 * @param {*} type | |
498 * @param {?Object=} context | |
499 * @param {boolean=} sortByTitle | |
500 * @return {!Array.<!Runtime.Extension>} | |
501 */ | |
502 extensions: function(type, context, sortByTitle) | |
503 { | |
504 return this._extensions.filter(filter).sort(sortByTitle ? titleComparato
r : orderComparator); | |
505 | |
506 /** | |
507 * @param {!Runtime.Extension} extension | |
508 * @return {boolean} | |
509 */ | |
510 function filter(extension) | |
511 { | |
512 if (extension._type !== type && extension._typeClass() !== type) | |
513 return false; | |
514 if (!extension.enabled()) | |
515 return false; | |
516 return !context || extension.isApplicable(context); | |
517 } | |
518 | |
519 /** | |
520 * @param {!Runtime.Extension} extension1 | |
521 * @param {!Runtime.Extension} extension2 | |
522 * @return {number} | |
523 */ | |
524 function orderComparator(extension1, extension2) | |
525 { | |
526 var order1 = extension1.descriptor()["order"] || 0; | |
527 var order2 = extension2.descriptor()["order"] || 0; | |
528 return order1 - order2; | |
529 } | |
530 | |
531 /** | |
532 * @param {!Runtime.Extension} extension1 | |
533 * @param {!Runtime.Extension} extension2 | |
534 * @return {number} | |
535 */ | |
536 function titleComparator(extension1, extension2) | |
537 { | |
538 var title1 = extension1.title() || ""; | |
539 var title2 = extension2.title() || ""; | |
540 return title1.localeCompare(title2); | |
541 } | |
542 }, | |
543 | |
544 /** | |
545 * @param {*} type | |
546 * @param {?Object=} context | |
547 * @return {?Runtime.Extension} | |
548 */ | |
549 extension: function(type, context) | |
550 { | |
551 return this.extensions(type, context)[0] || null; | |
552 }, | |
553 | |
554 /** | |
555 * @param {*} type | |
556 * @param {?Object=} context | |
557 * @return {!Promise.<!Array.<!Object>>} | |
558 */ | |
559 allInstances: function(type, context) | |
560 { | |
561 return Promise.all(this.extensions(type, context).map(extension => exten
sion.instance())); | |
562 }, | |
563 | |
564 /** | |
565 * @return {?function(new:Object)} | |
566 */ | |
567 _resolve: function(typeName) | |
568 { | |
569 if (!this._cachedTypeClasses[typeName]) { | |
570 var path = typeName.split("."); | |
571 var object = self; | |
572 for (var i = 0; object && (i < path.length); ++i) | |
573 object = object[path[i]]; | |
574 if (object) | |
575 this._cachedTypeClasses[typeName] = /** @type function(new:Objec
t) */(object); | |
576 } | |
577 return this._cachedTypeClasses[typeName] || null; | |
578 }, | |
579 | |
580 /** | |
581 * @param {!Function} constructorFunction | |
582 * @return {!Object} | |
583 */ | |
584 sharedInstance: function(constructorFunction) | |
585 { | |
586 if (Runtime._instanceSymbol in constructorFunction) | |
587 return constructorFunction[Runtime._instanceSymbol]; | |
588 var instance = new constructorFunction(); | |
589 constructorFunction[Runtime._instanceSymbol] = instance; | |
590 return instance; | |
591 } | |
592 }; | |
593 | |
594 /** | |
595 * @constructor | |
596 */ | |
597 Runtime.ModuleDescriptor = function() | |
598 { | |
599 /** | 611 /** |
600 * @type {string} | 612 * @type {string} |
601 */ | 613 */ |
602 this.name; | 614 this.name; |
603 | 615 |
604 /** | 616 /** |
605 * @type {!Array.<!Runtime.ExtensionDescriptor>} | 617 * @type {!Array.<!Runtime.ExtensionDescriptor>} |
606 */ | 618 */ |
607 this.extensions; | 619 this.extensions; |
608 | 620 |
609 /** | 621 /** |
610 * @type {!Array.<string>|undefined} | 622 * @type {!Array.<string>|undefined} |
611 */ | 623 */ |
612 this.dependencies; | 624 this.dependencies; |
613 | 625 |
614 /** | 626 /** |
615 * @type {!Array.<string>} | 627 * @type {!Array.<string>} |
616 */ | 628 */ |
617 this.scripts; | 629 this.scripts; |
618 | 630 |
619 /** | 631 /** |
620 * @type {string|undefined} | 632 * @type {string|undefined} |
621 */ | 633 */ |
622 this.condition; | 634 this.condition; |
623 | 635 |
624 /** | 636 /** |
625 * @type {boolean|undefined} | 637 * @type {boolean|undefined} |
626 */ | 638 */ |
627 this.remote; | 639 this.remote; |
| 640 } |
628 }; | 641 }; |
629 | 642 |
630 /** | 643 /** |
631 * @constructor | 644 * @unrestricted |
632 */ | 645 */ |
633 Runtime.ExtensionDescriptor = function() | 646 Runtime.ExtensionDescriptor = class { |
634 { | 647 constructor() { |
635 /** | 648 /** |
636 * @type {string} | 649 * @type {string} |
637 */ | 650 */ |
638 this.type; | 651 this.type; |
639 | 652 |
640 /** | 653 /** |
641 * @type {string|undefined} | 654 * @type {string|undefined} |
642 */ | 655 */ |
643 this.className; | 656 this.className; |
644 | 657 |
645 /** | 658 /** |
646 * @type {string|undefined} | 659 * @type {string|undefined} |
647 */ | 660 */ |
648 this.factoryName; | 661 this.factoryName; |
649 | 662 |
650 /** | 663 /** |
651 * @type {!Array.<string>|undefined} | 664 * @type {!Array.<string>|undefined} |
652 */ | 665 */ |
653 this.contextTypes; | 666 this.contextTypes; |
| 667 } |
654 }; | 668 }; |
655 | 669 |
656 /** | 670 /** |
657 * @constructor | 671 * @unrestricted |
658 * @param {!Runtime} manager | |
659 * @param {!Runtime.ModuleDescriptor} descriptor | |
660 */ | 672 */ |
661 Runtime.Module = function(manager, descriptor) | 673 Runtime.Module = class { |
662 { | 674 /** |
| 675 * @param {!Runtime} manager |
| 676 * @param {!Runtime.ModuleDescriptor} descriptor |
| 677 */ |
| 678 constructor(manager, descriptor) { |
663 this._manager = manager; | 679 this._manager = manager; |
664 this._descriptor = descriptor; | 680 this._descriptor = descriptor; |
665 this._name = descriptor.name; | 681 this._name = descriptor.name; |
666 /** @type {!Array<!Runtime.Extension>} */ | 682 /** @type {!Array<!Runtime.Extension>} */ |
667 this._extensions = []; | 683 this._extensions = []; |
668 | 684 |
669 /** @type {!Map<string, !Array<!Runtime.Extension>>} */ | 685 /** @type {!Map<string, !Array<!Runtime.Extension>>} */ |
670 this._extensionsByClassName = new Map(); | 686 this._extensionsByClassName = new Map(); |
671 var extensions = /** @type {?Array.<!Runtime.ExtensionDescriptor>} */ (descr
iptor.extensions); | 687 var extensions = /** @type {?Array.<!Runtime.ExtensionDescriptor>} */ (descr
iptor.extensions); |
672 for (var i = 0; extensions && i < extensions.length; ++i) { | 688 for (var i = 0; extensions && i < extensions.length; ++i) { |
673 var extension = new Runtime.Extension(this, extensions[i]); | 689 var extension = new Runtime.Extension(this, extensions[i]); |
674 this._manager._extensions.push(extension); | 690 this._manager._extensions.push(extension); |
675 this._extensions.push(extension); | 691 this._extensions.push(extension); |
676 } | 692 } |
677 this._loadedForTest = false; | 693 this._loadedForTest = false; |
| 694 } |
| 695 |
| 696 /** |
| 697 * @return {string} |
| 698 */ |
| 699 name() { |
| 700 return this._name; |
| 701 } |
| 702 |
| 703 /** |
| 704 * @return {boolean} |
| 705 */ |
| 706 enabled() { |
| 707 return Runtime._isDescriptorEnabled(this._descriptor); |
| 708 } |
| 709 |
| 710 /** |
| 711 * @param {string} name |
| 712 * @return {string} |
| 713 */ |
| 714 resource(name) { |
| 715 var fullName = this._name + '/' + name; |
| 716 var content = Runtime.cachedResources[fullName]; |
| 717 if (!content) |
| 718 throw new Error(fullName + ' not preloaded. Check module.json'); |
| 719 return content; |
| 720 } |
| 721 |
| 722 /** |
| 723 * @return {!Promise.<undefined>} |
| 724 */ |
| 725 _loadPromise() { |
| 726 if (!this.enabled()) |
| 727 return Promise.reject(new Error('Module ' + this._name + ' is not enabled'
)); |
| 728 |
| 729 if (this._pendingLoadPromise) |
| 730 return this._pendingLoadPromise; |
| 731 |
| 732 var dependencies = this._descriptor.dependencies; |
| 733 var dependencyPromises = []; |
| 734 for (var i = 0; dependencies && i < dependencies.length; ++i) |
| 735 dependencyPromises.push(this._manager._modulesMap[dependencies[i]]._loadPr
omise()); |
| 736 |
| 737 this._pendingLoadPromise = Promise.all(dependencyPromises) |
| 738 .then(this._loadResources.bind(this)) |
| 739 .then(this._loadScripts.bind(this)) |
| 740 .then(() => this._loadedForTest = true); |
| 741 |
| 742 return this._pendingLoadPromise; |
| 743 } |
| 744 |
| 745 /** |
| 746 * @return {!Promise.<undefined>} |
| 747 * @this {Runtime.Module} |
| 748 */ |
| 749 _loadResources() { |
| 750 var resources = this._descriptor['resources']; |
| 751 if (!resources || !resources.length) |
| 752 return Promise.resolve(); |
| 753 var promises = []; |
| 754 for (var i = 0; i < resources.length; ++i) { |
| 755 var url = this._modularizeURL(resources[i]); |
| 756 promises.push(Runtime.loadResourceIntoCache(url, true)); |
| 757 } |
| 758 return Promise.all(promises).then(undefined); |
| 759 } |
| 760 |
| 761 /** |
| 762 * @return {!Promise.<undefined>} |
| 763 */ |
| 764 _loadScripts() { |
| 765 if (!this._descriptor.scripts || !this._descriptor.scripts.length) |
| 766 return Promise.resolve(); |
| 767 return Runtime._loadScriptsPromise(this._descriptor.scripts.map(this._modula
rizeURL, this), this._remoteBase()); |
| 768 } |
| 769 |
| 770 /** |
| 771 * @param {string} resourceName |
| 772 */ |
| 773 _modularizeURL(resourceName) { |
| 774 return Runtime.normalizePath(this._name + '/' + resourceName); |
| 775 } |
| 776 |
| 777 /** |
| 778 * @return {string|undefined} |
| 779 */ |
| 780 _remoteBase() { |
| 781 return !Runtime.queryParam('debugFrontend') && this._descriptor.remote && Ru
ntime._remoteBase || undefined; |
| 782 } |
| 783 |
| 784 /** |
| 785 * @param {string} value |
| 786 * @return {string} |
| 787 */ |
| 788 substituteURL(value) { |
| 789 var base = this._remoteBase() || ''; |
| 790 return value.replace(/@url\(([^\)]*?)\)/g, convertURL.bind(this)); |
| 791 |
| 792 function convertURL(match, url) { |
| 793 return base + this._modularizeURL(url); |
| 794 } |
| 795 } |
678 }; | 796 }; |
679 | 797 |
680 Runtime.Module.prototype = { | |
681 /** | |
682 * @return {string} | |
683 */ | |
684 name: function() | |
685 { | |
686 return this._name; | |
687 }, | |
688 | |
689 /** | |
690 * @return {boolean} | |
691 */ | |
692 enabled: function() | |
693 { | |
694 return Runtime._isDescriptorEnabled(this._descriptor); | |
695 }, | |
696 | |
697 /** | |
698 * @param {string} name | |
699 * @return {string} | |
700 */ | |
701 resource: function(name) | |
702 { | |
703 var fullName = this._name + "/" + name; | |
704 var content = Runtime.cachedResources[fullName]; | |
705 if (!content) | |
706 throw new Error(fullName + " not preloaded. Check module.json"); | |
707 return content; | |
708 }, | |
709 | |
710 /** | |
711 * @return {!Promise.<undefined>} | |
712 */ | |
713 _loadPromise: function() | |
714 { | |
715 if (!this.enabled()) | |
716 return Promise.reject(new Error("Module " + this._name + " is not en
abled")); | |
717 | |
718 if (this._pendingLoadPromise) | |
719 return this._pendingLoadPromise; | |
720 | |
721 var dependencies = this._descriptor.dependencies; | |
722 var dependencyPromises = []; | |
723 for (var i = 0; dependencies && i < dependencies.length; ++i) | |
724 dependencyPromises.push(this._manager._modulesMap[dependencies[i]]._
loadPromise()); | |
725 | |
726 this._pendingLoadPromise = Promise.all(dependencyPromises) | |
727 .then(this._loadResources.bind(this)) | |
728 .then(this._loadScripts.bind(this)) | |
729 .then(() => this._loadedForTest = true); | |
730 | |
731 return this._pendingLoadPromise; | |
732 }, | |
733 | |
734 /** | |
735 * @return {!Promise.<undefined>} | |
736 * @this {Runtime.Module} | |
737 */ | |
738 _loadResources: function() | |
739 { | |
740 var resources = this._descriptor["resources"]; | |
741 if (!resources || !resources.length) | |
742 return Promise.resolve(); | |
743 var promises = []; | |
744 for (var i = 0; i < resources.length; ++i) { | |
745 var url = this._modularizeURL(resources[i]); | |
746 promises.push(Runtime.loadResourceIntoCache(url, true)); | |
747 } | |
748 return Promise.all(promises).then(undefined); | |
749 }, | |
750 | |
751 /** | |
752 * @return {!Promise.<undefined>} | |
753 */ | |
754 _loadScripts: function() | |
755 { | |
756 if (!this._descriptor.scripts || !this._descriptor.scripts.length) | |
757 return Promise.resolve(); | |
758 return Runtime._loadScriptsPromise(this._descriptor.scripts.map(this._mo
dularizeURL, this), this._remoteBase()); | |
759 }, | |
760 | |
761 /** | |
762 * @param {string} resourceName | |
763 */ | |
764 _modularizeURL: function(resourceName) | |
765 { | |
766 return Runtime.normalizePath(this._name + "/" + resourceName); | |
767 }, | |
768 | |
769 /** | |
770 * @return {string|undefined} | |
771 */ | |
772 _remoteBase: function() | |
773 { | |
774 return !Runtime.queryParam("debugFrontend") && this._descriptor.remote &
& Runtime._remoteBase || undefined; | |
775 }, | |
776 | |
777 /** | |
778 * @param {string} value | |
779 * @return {string} | |
780 */ | |
781 substituteURL: function(value) | |
782 { | |
783 var base = this._remoteBase() || ""; | |
784 return value.replace(/@url\(([^\)]*?)\)/g, convertURL.bind(this)); | |
785 | |
786 function convertURL(match, url) | |
787 { | |
788 return base + this._modularizeURL(url); | |
789 } | |
790 } | |
791 }; | |
792 | 798 |
793 /** | 799 /** |
794 * @param {!Object} descriptor | 800 * @unrestricted |
795 * @return {boolean} | |
796 */ | 801 */ |
797 Runtime._isDescriptorEnabled = function(descriptor) | 802 Runtime.Extension = class { |
798 { | 803 /** |
799 var activatorExperiment = descriptor["experiment"]; | 804 * @param {!Runtime.Module} module |
800 if (activatorExperiment === "*") | 805 * @param {!Runtime.ExtensionDescriptor} descriptor |
801 return Runtime.experiments.supportEnabled(); | 806 */ |
802 if (activatorExperiment && activatorExperiment.startsWith("!") && Runtime.ex
periments.isEnabled(activatorExperiment.substring(1))) | 807 constructor(module, descriptor) { |
803 return false; | |
804 if (activatorExperiment && !activatorExperiment.startsWith("!") && !Runtime.
experiments.isEnabled(activatorExperiment)) | |
805 return false; | |
806 var condition = descriptor["condition"]; | |
807 if (condition && !condition.startsWith("!") && !Runtime.queryParam(condition
)) | |
808 return false; | |
809 if (condition && condition.startsWith("!") && Runtime.queryParam(condition.s
ubstring(1))) | |
810 return false; | |
811 return true; | |
812 }; | |
813 | |
814 /** | |
815 * @constructor | |
816 * @param {!Runtime.Module} module | |
817 * @param {!Runtime.ExtensionDescriptor} descriptor | |
818 */ | |
819 Runtime.Extension = function(module, descriptor) | |
820 { | |
821 this._module = module; | 808 this._module = module; |
822 this._descriptor = descriptor; | 809 this._descriptor = descriptor; |
823 | 810 |
824 this._type = descriptor.type; | 811 this._type = descriptor.type; |
825 this._hasTypeClass = this._type.charAt(0) === "@"; | 812 this._hasTypeClass = this._type.charAt(0) === '@'; |
826 | 813 |
827 /** | 814 /** |
828 * @type {?string} | 815 * @type {?string} |
829 */ | 816 */ |
830 this._className = descriptor.className || null; | 817 this._className = descriptor.className || null; |
831 this._factoryName = descriptor.factoryName || null; | 818 this._factoryName = descriptor.factoryName || null; |
| 819 } |
| 820 |
| 821 /** |
| 822 * @return {!Object} |
| 823 */ |
| 824 descriptor() { |
| 825 return this._descriptor; |
| 826 } |
| 827 |
| 828 /** |
| 829 * @return {!Runtime.Module} |
| 830 */ |
| 831 module() { |
| 832 return this._module; |
| 833 } |
| 834 |
| 835 /** |
| 836 * @return {boolean} |
| 837 */ |
| 838 enabled() { |
| 839 return this._module.enabled() && Runtime._isDescriptorEnabled(this.descripto
r()); |
| 840 } |
| 841 |
| 842 /** |
| 843 * @return {?function(new:Object)} |
| 844 */ |
| 845 _typeClass() { |
| 846 if (!this._hasTypeClass) |
| 847 return null; |
| 848 return this._module._manager._resolve(this._type.substring(1)); |
| 849 } |
| 850 |
| 851 /** |
| 852 * @param {?Object} context |
| 853 * @return {boolean} |
| 854 */ |
| 855 isApplicable(context) { |
| 856 return this._module._manager.isExtensionApplicableToContext(this, context); |
| 857 } |
| 858 |
| 859 /** |
| 860 * @return {!Promise.<!Object>} |
| 861 */ |
| 862 instance() { |
| 863 return this._module._loadPromise().then(this._createInstance.bind(this)); |
| 864 } |
| 865 |
| 866 /** |
| 867 * @return {!Object} |
| 868 */ |
| 869 _createInstance() { |
| 870 var className = this._className || this._factoryName; |
| 871 if (!className) |
| 872 throw new Error('Could not instantiate extension with no class'); |
| 873 var constructorFunction = self.eval(/** @type {string} */ (className)); |
| 874 if (!(constructorFunction instanceof Function)) |
| 875 throw new Error('Could not instantiate: ' + className); |
| 876 if (this._className) |
| 877 return this._module._manager.sharedInstance(constructorFunction); |
| 878 return new constructorFunction(this); |
| 879 } |
| 880 |
| 881 /** |
| 882 * @return {string} |
| 883 */ |
| 884 title() { |
| 885 // FIXME: should be WebInspector.UIString() but runtime is not l10n aware ye
t. |
| 886 return this._descriptor['title-' + Runtime._platform] || this._descriptor['t
itle']; |
| 887 } |
| 888 |
| 889 /** |
| 890 * @param {function(new:Object)} contextType |
| 891 * @return {boolean} |
| 892 */ |
| 893 hasContextType(contextType) { |
| 894 var contextTypes = this.descriptor().contextTypes; |
| 895 if (!contextTypes) |
| 896 return false; |
| 897 for (var i = 0; i < contextTypes.length; ++i) { |
| 898 if (contextType === this._module._manager._resolve(contextTypes[i])) |
| 899 return true; |
| 900 } |
| 901 return false; |
| 902 } |
832 }; | 903 }; |
833 | 904 |
834 Runtime.Extension.prototype = { | |
835 /** | |
836 * @return {!Object} | |
837 */ | |
838 descriptor: function() | |
839 { | |
840 return this._descriptor; | |
841 }, | |
842 | |
843 /** | |
844 * @return {!Runtime.Module} | |
845 */ | |
846 module: function() | |
847 { | |
848 return this._module; | |
849 }, | |
850 | |
851 /** | |
852 * @return {boolean} | |
853 */ | |
854 enabled: function() | |
855 { | |
856 return this._module.enabled() && Runtime._isDescriptorEnabled(this.descr
iptor()); | |
857 }, | |
858 | |
859 /** | |
860 * @return {?function(new:Object)} | |
861 */ | |
862 _typeClass: function() | |
863 { | |
864 if (!this._hasTypeClass) | |
865 return null; | |
866 return this._module._manager._resolve(this._type.substring(1)); | |
867 }, | |
868 | |
869 /** | |
870 * @param {?Object} context | |
871 * @return {boolean} | |
872 */ | |
873 isApplicable: function(context) | |
874 { | |
875 return this._module._manager.isExtensionApplicableToContext(this, contex
t); | |
876 }, | |
877 | |
878 /** | |
879 * @return {!Promise.<!Object>} | |
880 */ | |
881 instance: function() | |
882 { | |
883 return this._module._loadPromise().then(this._createInstance.bind(this))
; | |
884 }, | |
885 | |
886 /** | |
887 * @return {!Object} | |
888 */ | |
889 _createInstance: function() | |
890 { | |
891 var className = this._className || this._factoryName; | |
892 if (!className) | |
893 throw new Error("Could not instantiate extension with no class"); | |
894 var constructorFunction = self.eval(/** @type {string} */(className)); | |
895 if (!(constructorFunction instanceof Function)) | |
896 throw new Error("Could not instantiate: " + className); | |
897 if (this._className) | |
898 return this._module._manager.sharedInstance(constructorFunction); | |
899 return new constructorFunction(this); | |
900 }, | |
901 | |
902 /** | |
903 * @return {string} | |
904 */ | |
905 title: function() | |
906 { | |
907 // FIXME: should be WebInspector.UIString() but runtime is not l10n awar
e yet. | |
908 return this._descriptor["title-" + Runtime._platform] || this._descripto
r["title"]; | |
909 }, | |
910 | |
911 /** | |
912 * @param {function(new:Object)} contextType | |
913 * @return {boolean} | |
914 */ | |
915 hasContextType: function(contextType) | |
916 { | |
917 var contextTypes = this.descriptor().contextTypes; | |
918 if (!contextTypes) | |
919 return false; | |
920 for (var i = 0; i < contextTypes.length; ++i) { | |
921 if (contextType === this._module._manager._resolve(contextTypes[i])) | |
922 return true; | |
923 } | |
924 return false; | |
925 } | |
926 }; | |
927 | |
928 /** | 905 /** |
929 * @constructor | 906 * @unrestricted |
930 */ | 907 */ |
931 Runtime.ExperimentsSupport = function() | 908 Runtime.ExperimentsSupport = class { |
932 { | 909 constructor() { |
933 this._supportEnabled = Runtime.queryParam("experiments") !== null; | 910 this._supportEnabled = Runtime.queryParam('experiments') !== null; |
934 this._experiments = []; | 911 this._experiments = []; |
935 this._experimentNames = {}; | 912 this._experimentNames = {}; |
936 this._enabledTransiently = {}; | 913 this._enabledTransiently = {}; |
| 914 } |
| 915 |
| 916 /** |
| 917 * @return {!Array.<!Runtime.Experiment>} |
| 918 */ |
| 919 allConfigurableExperiments() { |
| 920 var result = []; |
| 921 for (var i = 0; i < this._experiments.length; i++) { |
| 922 var experiment = this._experiments[i]; |
| 923 if (!this._enabledTransiently[experiment.name]) |
| 924 result.push(experiment); |
| 925 } |
| 926 return result; |
| 927 } |
| 928 |
| 929 /** |
| 930 * @return {boolean} |
| 931 */ |
| 932 supportEnabled() { |
| 933 return this._supportEnabled; |
| 934 } |
| 935 |
| 936 /** |
| 937 * @param {!Object} value |
| 938 */ |
| 939 _setExperimentsSetting(value) { |
| 940 if (!self.localStorage) |
| 941 return; |
| 942 self.localStorage['experiments'] = JSON.stringify(value); |
| 943 } |
| 944 |
| 945 /** |
| 946 * @param {string} experimentName |
| 947 * @param {string} experimentTitle |
| 948 * @param {boolean=} hidden |
| 949 */ |
| 950 register(experimentName, experimentTitle, hidden) { |
| 951 Runtime._assert(!this._experimentNames[experimentName], 'Duplicate registrat
ion of experiment ' + experimentName); |
| 952 this._experimentNames[experimentName] = true; |
| 953 this._experiments.push(new Runtime.Experiment(this, experimentName, experime
ntTitle, !!hidden)); |
| 954 } |
| 955 |
| 956 /** |
| 957 * @param {string} experimentName |
| 958 * @return {boolean} |
| 959 */ |
| 960 isEnabled(experimentName) { |
| 961 this._checkExperiment(experimentName); |
| 962 |
| 963 if (this._enabledTransiently[experimentName]) |
| 964 return true; |
| 965 if (!this.supportEnabled()) |
| 966 return false; |
| 967 |
| 968 return !!Runtime._experimentsSetting()[experimentName]; |
| 969 } |
| 970 |
| 971 /** |
| 972 * @param {string} experimentName |
| 973 * @param {boolean} enabled |
| 974 */ |
| 975 setEnabled(experimentName, enabled) { |
| 976 this._checkExperiment(experimentName); |
| 977 var experimentsSetting = Runtime._experimentsSetting(); |
| 978 experimentsSetting[experimentName] = enabled; |
| 979 this._setExperimentsSetting(experimentsSetting); |
| 980 } |
| 981 |
| 982 /** |
| 983 * @param {!Array.<string>} experimentNames |
| 984 */ |
| 985 setDefaultExperiments(experimentNames) { |
| 986 for (var i = 0; i < experimentNames.length; ++i) { |
| 987 this._checkExperiment(experimentNames[i]); |
| 988 this._enabledTransiently[experimentNames[i]] = true; |
| 989 } |
| 990 } |
| 991 |
| 992 /** |
| 993 * @param {string} experimentName |
| 994 */ |
| 995 enableForTest(experimentName) { |
| 996 this._checkExperiment(experimentName); |
| 997 this._enabledTransiently[experimentName] = true; |
| 998 } |
| 999 |
| 1000 clearForTest() { |
| 1001 this._experiments = []; |
| 1002 this._experimentNames = {}; |
| 1003 this._enabledTransiently = {}; |
| 1004 } |
| 1005 |
| 1006 cleanUpStaleExperiments() { |
| 1007 var experimentsSetting = Runtime._experimentsSetting(); |
| 1008 var cleanedUpExperimentSetting = {}; |
| 1009 for (var i = 0; i < this._experiments.length; ++i) { |
| 1010 var experimentName = this._experiments[i].name; |
| 1011 if (experimentsSetting[experimentName]) |
| 1012 cleanedUpExperimentSetting[experimentName] = true; |
| 1013 } |
| 1014 this._setExperimentsSetting(cleanedUpExperimentSetting); |
| 1015 } |
| 1016 |
| 1017 /** |
| 1018 * @param {string} experimentName |
| 1019 */ |
| 1020 _checkExperiment(experimentName) { |
| 1021 Runtime._assert(this._experimentNames[experimentName], 'Unknown experiment '
+ experimentName); |
| 1022 } |
937 }; | 1023 }; |
938 | 1024 |
939 Runtime.ExperimentsSupport.prototype = { | |
940 /** | |
941 * @return {!Array.<!Runtime.Experiment>} | |
942 */ | |
943 allConfigurableExperiments: function() | |
944 { | |
945 var result = []; | |
946 for (var i = 0; i < this._experiments.length; i++) { | |
947 var experiment = this._experiments[i]; | |
948 if (!this._enabledTransiently[experiment.name]) | |
949 result.push(experiment); | |
950 } | |
951 return result; | |
952 }, | |
953 | |
954 /** | |
955 * @return {boolean} | |
956 */ | |
957 supportEnabled: function() | |
958 { | |
959 return this._supportEnabled; | |
960 }, | |
961 | |
962 /** | |
963 * @param {!Object} value | |
964 */ | |
965 _setExperimentsSetting: function(value) | |
966 { | |
967 if (!self.localStorage) | |
968 return; | |
969 self.localStorage["experiments"] = JSON.stringify(value); | |
970 }, | |
971 | |
972 /** | |
973 * @param {string} experimentName | |
974 * @param {string} experimentTitle | |
975 * @param {boolean=} hidden | |
976 */ | |
977 register: function(experimentName, experimentTitle, hidden) | |
978 { | |
979 Runtime._assert(!this._experimentNames[experimentName], "Duplicate regis
tration of experiment " + experimentName); | |
980 this._experimentNames[experimentName] = true; | |
981 this._experiments.push(new Runtime.Experiment(this, experimentName, expe
rimentTitle, !!hidden)); | |
982 }, | |
983 | |
984 /** | |
985 * @param {string} experimentName | |
986 * @return {boolean} | |
987 */ | |
988 isEnabled: function(experimentName) | |
989 { | |
990 this._checkExperiment(experimentName); | |
991 | |
992 if (this._enabledTransiently[experimentName]) | |
993 return true; | |
994 if (!this.supportEnabled()) | |
995 return false; | |
996 | |
997 return !!Runtime._experimentsSetting()[experimentName]; | |
998 }, | |
999 | |
1000 /** | |
1001 * @param {string} experimentName | |
1002 * @param {boolean} enabled | |
1003 */ | |
1004 setEnabled: function(experimentName, enabled) | |
1005 { | |
1006 this._checkExperiment(experimentName); | |
1007 var experimentsSetting = Runtime._experimentsSetting(); | |
1008 experimentsSetting[experimentName] = enabled; | |
1009 this._setExperimentsSetting(experimentsSetting); | |
1010 }, | |
1011 | |
1012 /** | |
1013 * @param {!Array.<string>} experimentNames | |
1014 */ | |
1015 setDefaultExperiments: function(experimentNames) | |
1016 { | |
1017 for (var i = 0; i < experimentNames.length; ++i) { | |
1018 this._checkExperiment(experimentNames[i]); | |
1019 this._enabledTransiently[experimentNames[i]] = true; | |
1020 } | |
1021 }, | |
1022 | |
1023 /** | |
1024 * @param {string} experimentName | |
1025 */ | |
1026 enableForTest: function(experimentName) | |
1027 { | |
1028 this._checkExperiment(experimentName); | |
1029 this._enabledTransiently[experimentName] = true; | |
1030 }, | |
1031 | |
1032 clearForTest: function() | |
1033 { | |
1034 this._experiments = []; | |
1035 this._experimentNames = {}; | |
1036 this._enabledTransiently = {}; | |
1037 }, | |
1038 | |
1039 cleanUpStaleExperiments: function() | |
1040 { | |
1041 var experimentsSetting = Runtime._experimentsSetting(); | |
1042 var cleanedUpExperimentSetting = {}; | |
1043 for (var i = 0; i < this._experiments.length; ++i) { | |
1044 var experimentName = this._experiments[i].name; | |
1045 if (experimentsSetting[experimentName]) | |
1046 cleanedUpExperimentSetting[experimentName] = true; | |
1047 } | |
1048 this._setExperimentsSetting(cleanedUpExperimentSetting); | |
1049 }, | |
1050 | |
1051 /** | |
1052 * @param {string} experimentName | |
1053 */ | |
1054 _checkExperiment: function(experimentName) | |
1055 { | |
1056 Runtime._assert(this._experimentNames[experimentName], "Unknown experime
nt " + experimentName); | |
1057 } | |
1058 }; | |
1059 | |
1060 /** | 1025 /** |
1061 * @constructor | 1026 * @unrestricted |
1062 * @param {!Runtime.ExperimentsSupport} experiments | |
1063 * @param {string} name | |
1064 * @param {string} title | |
1065 * @param {boolean} hidden | |
1066 */ | 1027 */ |
1067 Runtime.Experiment = function(experiments, name, title, hidden) | 1028 Runtime.Experiment = class { |
1068 { | 1029 /** |
| 1030 * @param {!Runtime.ExperimentsSupport} experiments |
| 1031 * @param {string} name |
| 1032 * @param {string} title |
| 1033 * @param {boolean} hidden |
| 1034 */ |
| 1035 constructor(experiments, name, title, hidden) { |
1069 this.name = name; | 1036 this.name = name; |
1070 this.title = title; | 1037 this.title = title; |
1071 this.hidden = hidden; | 1038 this.hidden = hidden; |
1072 this._experiments = experiments; | 1039 this._experiments = experiments; |
| 1040 } |
| 1041 |
| 1042 /** |
| 1043 * @return {boolean} |
| 1044 */ |
| 1045 isEnabled() { |
| 1046 return this._experiments.isEnabled(this.name); |
| 1047 } |
| 1048 |
| 1049 /** |
| 1050 * @param {boolean} enabled |
| 1051 */ |
| 1052 setEnabled(enabled) { |
| 1053 this._experiments.setEnabled(this.name, enabled); |
| 1054 } |
1073 }; | 1055 }; |
1074 | 1056 |
1075 Runtime.Experiment.prototype = { | |
1076 /** | |
1077 * @return {boolean} | |
1078 */ | |
1079 isEnabled: function() | |
1080 { | |
1081 return this._experiments.isEnabled(this.name); | |
1082 }, | |
1083 | |
1084 /** | |
1085 * @param {boolean} enabled | |
1086 */ | |
1087 setEnabled: function(enabled) | |
1088 { | |
1089 this._experiments.setEnabled(this.name, enabled); | |
1090 } | |
1091 }; | |
1092 | |
1093 {(function parseQueryParameters() | |
1094 { | 1057 { |
| 1058 (function parseQueryParameters() { |
1095 var queryParams = location.search; | 1059 var queryParams = location.search; |
1096 if (!queryParams) | 1060 if (!queryParams) |
1097 return; | 1061 return; |
1098 var params = queryParams.substring(1).split("&"); | 1062 var params = queryParams.substring(1).split('&'); |
1099 for (var i = 0; i < params.length; ++i) { | 1063 for (var i = 0; i < params.length; ++i) { |
1100 var pair = params[i].split("="); | 1064 var pair = params[i].split('='); |
1101 var name = pair.shift(); | 1065 var name = pair.shift(); |
1102 Runtime._queryParamsObject[name] = pair.join("="); | 1066 Runtime._queryParamsObject[name] = pair.join('='); |
1103 } | 1067 } |
1104 })();} | 1068 })(); |
1105 | 1069 } |
1106 | 1070 |
1107 // This must be constructed after the query parameters have been parsed. | 1071 // This must be constructed after the query parameters have been parsed. |
1108 Runtime.experiments = new Runtime.ExperimentsSupport(); | 1072 Runtime.experiments = new Runtime.ExperimentsSupport(); |
1109 | 1073 |
1110 /** | 1074 /** |
1111 * @type {?string} | 1075 * @type {?string} |
1112 */ | 1076 */ |
1113 Runtime._remoteBase = Runtime.queryParam("remoteBase"); | 1077 Runtime._remoteBase = Runtime.queryParam('remoteBase'); |
1114 {(function validateRemoteBase() | |
1115 { | 1078 { |
| 1079 (function validateRemoteBase() { |
1116 var remoteBaseRegexp = /^https:\/\/chrome-devtools-frontend\.appspot\.com\/s
erve_file\/@[0-9a-zA-Z]+\/?$/; | 1080 var remoteBaseRegexp = /^https:\/\/chrome-devtools-frontend\.appspot\.com\/s
erve_file\/@[0-9a-zA-Z]+\/?$/; |
1117 if (Runtime._remoteBase && !remoteBaseRegexp.test(Runtime._remoteBase)) | 1081 if (Runtime._remoteBase && !remoteBaseRegexp.test(Runtime._remoteBase)) |
1118 Runtime._remoteBase = null; | 1082 Runtime._remoteBase = null; |
1119 })();} | 1083 })(); |
| 1084 } |
1120 | 1085 |
1121 /** | |
1122 * @param {string} path | |
1123 * @return {string} | |
1124 */ | |
1125 Runtime.resolveSourceURL = function(path) | |
1126 { | |
1127 var sourceURL = self.location.href; | |
1128 if (self.location.search) | |
1129 sourceURL = sourceURL.replace(self.location.search, ""); | |
1130 sourceURL = sourceURL.substring(0, sourceURL.lastIndexOf("/") + 1) + path; | |
1131 return "\n/*# sourceURL=" + sourceURL + " */"; | |
1132 }; | |
1133 | 1086 |
1134 /** | 1087 /** |
1135 * @interface | 1088 * @interface |
1136 */ | 1089 */ |
1137 function ServicePort() { } | 1090 function ServicePort() { |
| 1091 } |
1138 | 1092 |
1139 ServicePort.prototype = { | 1093 ServicePort.prototype = { |
1140 /** | 1094 /** |
1141 * @param {function(string)} messageHandler | 1095 * @param {function(string)} messageHandler |
1142 * @param {function(string)} closeHandler | 1096 * @param {function(string)} closeHandler |
1143 */ | 1097 */ |
1144 setHandlers: function(messageHandler, closeHandler) { }, | 1098 setHandlers: function(messageHandler, closeHandler) {}, |
1145 | 1099 |
1146 /** | 1100 /** |
1147 * @param {string} message | 1101 * @param {string} message |
1148 * @return {!Promise<boolean>} | 1102 * @return {!Promise<boolean>} |
1149 */ | 1103 */ |
1150 send: function(message) { }, | 1104 send: function(message) {}, |
1151 | 1105 |
1152 /** | 1106 /** |
1153 * @return {!Promise<boolean>} | 1107 * @return {!Promise<boolean>} |
1154 */ | 1108 */ |
1155 close: function() { } | 1109 close: function() {} |
1156 }; | 1110 }; |
1157 | 1111 |
1158 /** @type {!Runtime} */ | 1112 /** @type {!Runtime} */ |
1159 var runtime; | 1113 var runtime; |
OLD | NEW |