blob: 9b812a7744b8da0d6f9ce6e6767728f96c3f92e6 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/** @typedef {chrome.developerPrivate.ManifestError} */
var ManifestError;
/** @typedef {chrome.developerPrivate.RuntimeError} */
var RuntimeError;
cr.define('extensions', function() {
'use strict';
/** @interface */
var ErrorPageDelegate = function() {};
ErrorPageDelegate.prototype = {
/**
* @param {string} extensionId
* @param {!Array<number>=} opt_errorIds
* @param {chrome.developerPrivate.ErrorType=} opt_type
*/
deleteErrors: assertNotReached,
/**
* @param {chrome.developerPrivate.RequestFileSourceProperties} args
* @return {!Promise<!chrome.developerPrivate.RequestFileSourceResponse>}
*/
requestFileSource: assertNotReached,
};
var ErrorPage = Polymer({
is: 'extensions-error-page',
behaviors: [Polymer.NeonAnimatableBehavior],
properties: {
/** @type {!chrome.developerPrivate.ExtensionInfo|undefined} */
data: Object,
/** @type {!extensions.ErrorPageDelegate|undefined} */
delegate: Object,
/** @private {?(ManifestError|RuntimeError)} */
selectedError_: Object,
},
observers: [
'observeDataChanges_(data)',
'onSelectedErrorChanged_(selectedError_)',
],
ready: function() {
/** @type {!extensions.AnimationHelper} */
this.animationHelper = new extensions.AnimationHelper(this, this.$.main);
this.animationHelper.setEntryAnimation(extensions.Animation.FADE_IN);
this.animationHelper.setExitAnimation(extensions.Animation.SCALE_DOWN);
this.sharedElements = {hero: this.$.main};
},
/**
* Watches for changes to |data| in order to fetch the corresponding
* file source.
* @private
*/
observeDataChanges_: function() {
assert(this.data);
var e = this.data.manifestErrors[0] || this.data.runtimeErrors[0];
if (e)
this.selectedError_ = e;
},
/**
* @return {!Array<!(ManifestError|RuntimeError)>}
* @private
*/
calculateShownItems_: function() {
return this.data.manifestErrors.concat(this.data.runtimeErrors);
},
/** @private */
onCloseButtonTap_: function() {
this.fire('close');
},
/**
* @param {!ManifestError|!RuntimeError} error
* @return {string}
* @private
*/
computeErrorIconClass_: function(error) {
if (error.type == chrome.developerPrivate.ErrorType.RUNTIME) {
switch (error.severity) {
case chrome.developerPrivate.ErrorLevel.LOG:
return 'icon-severity-info';
case chrome.developerPrivate.ErrorLevel.WARN:
return 'icon-severity-warning';
case chrome.developerPrivate.ErrorLevel.ERROR:
return 'icon-severity-fatal';
}
assertNotReached();
}
assert(error.type == chrome.developerPrivate.ErrorType.MANIFEST);
return 'icon-severity-warning';
},
/**
* @param {!Event} event
* @private
*/
onDeleteErrorTap_: function(event) {
// TODO(devlin): It would be cleaner if we could cast this to a
// PolymerDomRepeatEvent-type thing, but that doesn't exist yet.
var e = /** @type {!{model:Object}} */(event);
this.delegate.deleteErrors(this.data.id, [e.model.item.id]);
},
/**
* Fetches the source for the selected error and populates the code section.
* @private
*/
onSelectedErrorChanged_: function() {
var error = this.selectedError_;
var args = {
extensionId: error.extensionId,
message: error.message,
};
switch (error.type) {
case chrome.developerPrivate.ErrorType.MANIFEST:
args.pathSuffix = error.source;
args.manifestKey = error.manifestKey;
args.manifestSpecific = error.manifestSpecific;
break;
case chrome.developerPrivate.ErrorType.RUNTIME:
// slice(1) because pathname starts with a /.
args.pathSuffix = new URL(error.source).pathname.slice(1);
args.lineNumber = error.stackTrace && error.stackTrace[0] ?
error.stackTrace[0].lineNumber : 0;
break;
}
this.delegate.requestFileSource(args).then(function(code) {
this.$['code-section'].code = code;
}.bind(this));
},
/**
* Computes the class name for the error item depending on whether its
* the currently selected error.
* @param {!RuntimeError|!ManifestError} selectedError
* @param {!RuntimeError|!ManifestError} error
* @return {string}
* @private
*/
computeErrorClass_: function(selectedError, error) {
return selectedError == error ?
'error-item selected' : 'error-item';
},
/**
* Causes the given error to become the currently-selected error.
* @param {!RuntimeError|!ManifestError} error
* @private
*/
selectError_: function(error) {
this.selectedError_ = error;
},
/**
* @param {!{model: !{item: (!RuntimeError|!ManifestError)}}} e
* @private
*/
onErrorItemTap_: function(e) {
this.selectError_(e.model.item);
},
/**
* @param {!{model: !{item: (!RuntimeError|!ManifestError)}}} e
* @private
*/
onErrorItemKeydown_: function(e) {
if (e.key == ' ' || e.key == 'Enter')
this.selectError_(e.model.item);
},
});
return {
ErrorPage: ErrorPage,
ErrorPageDelegate: ErrorPageDelegate,
};
});