OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 cr.define('extensions', function() { | 5 cr.define('extensions', function() { |
6 'use strict'; | 6 'use strict'; |
7 | 7 |
8 /** | 8 /** |
9 * Clear all the content of a given element. | 9 * Clear all the content of a given element. |
10 * @param {HTMLElement} element The element to be cleared. | 10 * @param {HTMLElement} element The element to be cleared. |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
109 assert(this.contextUrl_); | 109 assert(this.contextUrl_); |
110 }, | 110 }, |
111 | 111 |
112 /** | 112 /** |
113 * Sets the error for the content. | 113 * Sets the error for the content. |
114 * @param {(RuntimeError|ManifestError)} error The error whose content | 114 * @param {(RuntimeError|ManifestError)} error The error whose content |
115 * should be displayed. | 115 * should be displayed. |
116 * @param {string} extensionUrl The URL associated with this extension. | 116 * @param {string} extensionUrl The URL associated with this extension. |
117 */ | 117 */ |
118 setError: function(error, extensionUrl) { | 118 setError: function(error, extensionUrl) { |
119 if (this.error_) | |
120 this.clearError(); | |
121 | |
119 this.error_ = error; | 122 this.error_ = error; |
120 this.extensionUrl_ = extensionUrl; | 123 this.extensionUrl_ = extensionUrl; |
121 this.contextUrl_.textContent = error.contextUrl ? | 124 this.contextUrl_.textContent = error.contextUrl ? |
122 getRelativeUrl(error.contextUrl, this.extensionUrl_) : | 125 getRelativeUrl(error.contextUrl, this.extensionUrl_) : |
123 loadTimeData.getString('extensionErrorOverlayContextUnknown'); | 126 loadTimeData.getString('extensionErrorOverlayContextUnknown'); |
124 this.initStackTrace_(); | 127 this.initStackTrace_(); |
125 }, | 128 }, |
126 | 129 |
127 /** | 130 /** |
128 * Wipe content associated with a specific error. | 131 * Wipe content associated with a specific error. |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
239 /** | 242 /** |
240 * The content section for runtime errors; this is re-used for all | 243 * The content section for runtime errors; this is re-used for all |
241 * runtime errors and attached/detached from the overlay as needed. | 244 * runtime errors and attached/detached from the overlay as needed. |
242 * @type {RuntimeErrorContent} | 245 * @type {RuntimeErrorContent} |
243 * @private | 246 * @private |
244 */ | 247 */ |
245 this.runtimeErrorContent_ = new RuntimeErrorContent(); | 248 this.runtimeErrorContent_ = new RuntimeErrorContent(); |
246 } | 249 } |
247 | 250 |
248 /** | 251 /** |
249 * Value of ExtensionError::RUNTIME_ERROR enum. | |
250 * @see extensions/browser/extension_error.h | |
251 * @type {number} | |
252 * @const | |
253 * @private | |
254 */ | |
255 ExtensionErrorOverlay.RUNTIME_ERROR_TYPE_ = 1; | |
256 | |
257 /** | |
258 * The manifest filename. | 252 * The manifest filename. |
259 * @type {string} | 253 * @type {string} |
260 * @const | 254 * @const |
261 * @private | 255 * @private |
262 */ | 256 */ |
263 ExtensionErrorOverlay.MANIFEST_FILENAME_ = 'manifest.json'; | 257 ExtensionErrorOverlay.MANIFEST_FILENAME_ = 'manifest.json'; |
264 | 258 |
265 /** | 259 /** |
266 * Determine whether or not chrome can load the source for a given file; this | 260 * Determine whether or not chrome can load the source for a given file; this |
267 * can only be done if the file belongs to the extension. | 261 * can only be done if the file belongs to the extension. |
268 * @param {string} file The file to load. | 262 * @param {string} file The file to load. |
269 * @param {string} extensionUrl The url for the extension, in the form | 263 * @param {string} extensionUrl The url for the extension, in the form |
270 * chrome-extension://<extension-id>/. | 264 * chrome-extension://<extension-id>/. |
271 * @return {boolean} True if the file can be loaded, false otherwise. | 265 * @return {boolean} True if the file can be loaded, false otherwise. |
272 * @private | 266 * @private |
273 */ | 267 */ |
274 ExtensionErrorOverlay.canLoadFileSource = function(file, extensionUrl) { | 268 ExtensionErrorOverlay.canLoadFileSource = function(file, extensionUrl) { |
275 return file.substr(0, extensionUrl.length) == extensionUrl || | 269 return file.substr(0, extensionUrl.length) == extensionUrl || |
276 file.toLowerCase() == ExtensionErrorOverlay.MANIFEST_FILENAME_; | 270 file.toLowerCase() == ExtensionErrorOverlay.MANIFEST_FILENAME_; |
277 }; | 271 }; |
278 | 272 |
279 /** | |
280 * Determine whether or not we can show an overlay with more details for | |
281 * the given extension error. | |
282 * @param {Object} error The extension error. | |
283 * @param {string} extensionUrl The url for the extension, in the form | |
284 * "chrome-extension://<extension-id>/". | |
285 * @return {boolean} True if we can show an overlay for the error, | |
286 * false otherwise. | |
287 */ | |
288 ExtensionErrorOverlay.canShowOverlayForError = function(error, extensionUrl) { | |
289 if (ExtensionErrorOverlay.canLoadFileSource(error.source, extensionUrl)) | |
290 return true; | |
291 | |
292 if (error.stackTrace) { | |
293 for (var i = 0; i < error.stackTrace.length; ++i) { | |
294 if (RuntimeErrorContent.shouldDisplayForUrl(error.stackTrace[i].url)) | |
295 return true; | |
296 } | |
297 } | |
298 | |
299 return false; | |
300 }; | |
301 | |
302 cr.addSingletonGetter(ExtensionErrorOverlay); | 273 cr.addSingletonGetter(ExtensionErrorOverlay); |
303 | 274 |
304 ExtensionErrorOverlay.prototype = { | 275 ExtensionErrorOverlay.prototype = { |
305 /** | 276 /** |
306 * The underlying error whose details are being displayed. | 277 * The underlying error whose details are being displayed. |
307 * @type {?(RuntimeError|ManifestError)} | 278 * @type {?(RuntimeError|ManifestError)} |
308 * @private | 279 * @private |
309 */ | 280 */ |
310 error_: null, | 281 selectedError_: null, |
311 | 282 |
312 /** | 283 /** |
313 * Initialize the page. | 284 * Initialize the page. |
314 * @param {function(HTMLDivElement)} showOverlay The function to show or | 285 * @param {function(HTMLDivElement)} showOverlay The function to show or |
315 * hide the ExtensionErrorOverlay; this should take a single parameter | 286 * hide the ExtensionErrorOverlay; this should take a single parameter |
316 * which is either the overlay Div if the overlay should be displayed, | 287 * which is either the overlay Div if the overlay should be displayed, |
317 * or null if the overlay should be hidden. | 288 * or null if the overlay should be hidden. |
318 */ | 289 */ |
319 initializePage: function(showOverlay) { | 290 initializePage: function(showOverlay) { |
320 var overlay = $('overlay'); | 291 var overlay = $('overlay'); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
369 * Handles a click on the dismiss ("OK" or close) buttons. | 340 * Handles a click on the dismiss ("OK" or close) buttons. |
370 * @param {Event} e The click event. | 341 * @param {Event} e The click event. |
371 * @private | 342 * @private |
372 */ | 343 */ |
373 handleDismiss_: function(e) { | 344 handleDismiss_: function(e) { |
374 this.setVisible(false); | 345 this.setVisible(false); |
375 | 346 |
376 // There's a chance that the overlay receives multiple dismiss events; in | 347 // There's a chance that the overlay receives multiple dismiss events; in |
377 // this case, handle it gracefully and return (since all necessary work | 348 // this case, handle it gracefully and return (since all necessary work |
378 // will already have been done). | 349 // will already have been done). |
379 if (!this.error_) | 350 if (!this.selectedError_) |
380 return; | 351 return; |
381 | 352 |
382 // Remove all previous content. | 353 // Remove all previous content. |
383 this.codeDiv_.clear(); | 354 this.codeDiv_.clear(); |
384 | 355 |
385 this.openDevtoolsButton_.hidden = true; | 356 // Note: We don't use ExtensionErrorList.clear() here because that would |
357 // delete the errors on the backend, too. | |
358 clearElement(/** @type {HTMLElement} */(this.overlayDiv_.querySelector( | |
359 '.extension-error-list'))); | |
386 | 360 |
387 if (this.error_.type == ExtensionErrorOverlay.RUNTIME_ERROR_TYPE_) { | 361 this.clearRuntimeContent_(); |
388 this.overlayDiv_.querySelector('.content-area').removeChild( | 362 |
363 this.selectedError_ = null; | |
364 }, | |
365 | |
366 clearRuntimeContent_: function() { | |
367 if (this.runtimeErrorContent_.parentNode) { | |
368 this.runtimeErrorContent_.parentNode.removeChild( | |
389 this.runtimeErrorContent_); | 369 this.runtimeErrorContent_); |
390 this.runtimeErrorContent_.clearError(); | 370 this.runtimeErrorContent_.clearError(); |
391 } | 371 } |
392 | 372 this.openDevtoolsButton_.hidden = true; |
393 this.error_ = null; | |
394 }, | 373 }, |
395 | 374 |
Dan Beam
2015/03/31 00:33:50
nit: /** @private */ at least
Devlin
2015/03/31 16:17:51
Whoops! Added jsdocs.
| |
396 /** | 375 setActiveError_: function(error) { |
397 * Associate an error with the overlay. This will set the error for the | 376 this.selectedError_ = error; |
398 * overlay, and, if possible, will populate the code section of the overlay | |
399 * with the relevant file, load the stack trace, and generate links for | |
400 * opening devtools (the latter two only happen for runtime errors). | |
401 * @param {(RuntimeError|ManifestError)} error The error to show in the | |
402 * overlay. | |
403 * @param {string} extensionUrl The URL of the extension, in the form | |
404 * "chrome-extension://<extension_id>". | |
405 */ | |
406 setErrorAndShowOverlay: function(error, extensionUrl) { | |
407 this.error_ = error; | |
408 | 377 |
409 if (this.error_.type == ExtensionErrorOverlay.RUNTIME_ERROR_TYPE_) { | 378 // If there is no error (this can happen if, e.g., the user deleted all |
410 this.runtimeErrorContent_.setError(this.error_, extensionUrl); | 379 // the errors), then clear the content. |
380 if (!error) { | |
381 this.codeDiv_.populate( | |
382 null, loadTimeData.getString('extensionErrorNoErrorsCodeMessage')); | |
383 this.clearRuntimeContent_(); | |
384 return; | |
385 } | |
386 | |
387 var extensionUrl = 'chrome-extension://' + error.extensionId + '/'; | |
388 // Set or hide runtime content. | |
389 if (error.type == chrome.developerPrivate.ErrorType.RUNTIME) { | |
390 this.runtimeErrorContent_.setError(error, extensionUrl); | |
411 this.overlayDiv_.querySelector('.content-area').insertBefore( | 391 this.overlayDiv_.querySelector('.content-area').insertBefore( |
412 this.runtimeErrorContent_, | 392 this.runtimeErrorContent_, |
413 this.codeDiv_.nextSibling); | 393 this.codeDiv_.nextSibling); |
414 this.openDevtoolsButton_.hidden = false; | 394 this.openDevtoolsButton_.hidden = false; |
415 this.openDevtoolsButton_.disabled = !error.canInspect; | 395 this.openDevtoolsButton_.disabled = !error.canInspect; |
396 } else { | |
397 this.clearRuntimeContent_(); | |
416 } | 398 } |
417 | 399 |
400 // Read the file source to populate the code section, or set it to null if | |
401 // the file is unreadable. | |
418 if (ExtensionErrorOverlay.canLoadFileSource(error.source, extensionUrl)) { | 402 if (ExtensionErrorOverlay.canLoadFileSource(error.source, extensionUrl)) { |
419 var relativeUrl = getRelativeUrl(error.source, extensionUrl); | 403 var relativeUrl = getRelativeUrl(error.source, extensionUrl); |
420 | 404 |
421 var requestFileSourceArgs = {extensionId: error.extensionId, | 405 var requestFileSourceArgs = {extensionId: error.extensionId, |
422 message: error.message, | 406 message: error.message, |
423 pathSuffix: relativeUrl}; | 407 pathSuffix: relativeUrl}; |
424 | 408 switch (error.type) { |
425 if (relativeUrl.toLowerCase() == | 409 case chrome.developerPrivate.ErrorType.MANIFEST: |
426 ExtensionErrorOverlay.MANIFEST_FILENAME_) { | 410 requestFileSourceArgs.manifestKey = error.manifestKey; |
427 requestFileSourceArgs.manifestKey = error.manifestKey; | 411 requestFileSourceArgs.manifestSpecific = error.manifestSpecific; |
428 requestFileSourceArgs.manifestSpecific = error.manifestSpecific; | 412 break; |
429 } else { | 413 case chrome.developerPrivate.ErrorType.RUNTIME: |
430 requestFileSourceArgs.lineNumber = | 414 requestFileSourceArgs.lineNumber = |
431 error.stackTrace && error.stackTrace[0] ? | 415 error.stackTrace && error.stackTrace[0] ? |
432 error.stackTrace[0].lineNumber : 0; | 416 error.stackTrace[0].lineNumber : 0; |
417 break; | |
418 default: | |
419 assertNotReached(); | |
433 } | 420 } |
434 this.requestFileSource(requestFileSourceArgs); | 421 this.requestFileSource(requestFileSourceArgs); |
435 } else { | 422 } else { |
436 this.onFileSourceResponse_(null); | 423 this.onFileSourceResponse_(null); |
437 } | 424 } |
438 }, | 425 }, |
439 | 426 |
440 /** | 427 /** |
428 * Associate an error with the overlay. This will set the error for the | |
429 * overlay, and, if possible, will populate the code section of the overlay | |
430 * with the relevant file, load the stack trace, and generate links for | |
431 * opening devtools (the latter two only happen for runtime errors). | |
432 * @param {Array<(RuntimeError|ManifestError)>} errors The error to show in | |
433 * the overlay. | |
434 * @param {string} extensionId The id of the extension. | |
435 * @param {string} extensionName The name of the extension. | |
436 */ | |
437 setErrorsAndShowOverlay: function(errors, extensionId, extensionName) { | |
438 document.querySelector( | |
439 '#extension-error-overlay .extension-error-overlay-title'). | |
440 textContent = extensionName; | |
441 var errorsDiv = this.overlayDiv_.querySelector('.extension-error-list'); | |
442 var extensionErrors = | |
443 new extensions.ExtensionErrorList(errors, extensionId); | |
444 errorsDiv.parentNode.replaceChild(extensionErrors, errorsDiv); | |
445 extensionErrors.addEventListener('activeExtensionErrorChanged', | |
446 function(e) { | |
447 this.setActiveError_(e.detail); | |
448 }.bind(this)); | |
449 | |
450 if (errors.length > 0) | |
451 this.setActiveError_(errors[0]); | |
452 this.setVisible(true); | |
453 }, | |
454 | |
455 /** | |
441 * Requests a file's source. | 456 * Requests a file's source. |
442 * @param {RequestFileSourceProperties} args The arguments for the call. | 457 * @param {RequestFileSourceProperties} args The arguments for the call. |
443 */ | 458 */ |
444 requestFileSource: function(args) { | 459 requestFileSource: function(args) { |
445 chrome.developerPrivate.requestFileSource( | 460 chrome.developerPrivate.requestFileSource( |
446 args, this.onFileSourceResponse_.bind(this)); | 461 args, this.onFileSourceResponse_.bind(this)); |
447 }, | 462 }, |
448 | 463 |
449 /** | 464 /** |
450 * Set the code to be displayed in the code portion of the overlay. | 465 * Set the code to be displayed in the code portion of the overlay. |
451 * @see ExtensionErrorOverlay.requestFileSourceResponse(). | 466 * @see ExtensionErrorOverlay.requestFileSourceResponse(). |
452 * @param {?RequestFileSourceResponse} response The response from the | 467 * @param {?RequestFileSourceResponse} response The response from the |
453 * request file source call, which will be shown as code. If |response| | 468 * request file source call, which will be shown as code. If |response| |
454 * is null, then a "Could not display code" message will be displayed | 469 * is null, then a "Could not display code" message will be displayed |
455 * instead. | 470 * instead. |
456 */ | 471 */ |
457 onFileSourceResponse_: function(response) { | 472 onFileSourceResponse_: function(response) { |
458 if (response) { | |
459 document.querySelector( | |
460 '#extension-error-overlay .extension-error-overlay-title'). | |
461 textContent = response.title; | |
462 } | |
463 this.codeDiv_.populate( | 473 this.codeDiv_.populate( |
464 response, // ExtensionCode can handle a null response. | 474 response, // ExtensionCode can handle a null response. |
465 loadTimeData.getString('extensionErrorOverlayNoCodeToDisplay')); | 475 loadTimeData.getString('extensionErrorOverlayNoCodeToDisplay')); |
466 this.setVisible(true); | 476 this.setVisible(true); |
467 }, | 477 }, |
468 }; | 478 }; |
469 | 479 |
470 // Export | 480 // Export |
471 return { | 481 return { |
472 ExtensionErrorOverlay: ExtensionErrorOverlay | 482 ExtensionErrorOverlay: ExtensionErrorOverlay |
473 }; | 483 }; |
474 }); | 484 }); |
OLD | NEW |