blob: 95def83d8bccb227975f4d68eb0deae6ada1a824 [file] [log] [blame]
// Copyright 2014 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.
cr.define('extensions', function() {
'use strict';
/**
* Construct an ExtensionLoadError around the given |div|.
* @param {HTMLDivElement} div The HTML div for the extension load error.
* @constructor
* @extends {HTMLDivElement}
*/
function ExtensionLoadError(div) {
div.__proto__ = ExtensionLoadError.prototype;
div.init();
return div;
}
/**
* Construct a Failure.
* @param {string} filePath The path to the unpacked extension.
* @param {string} error The reason the extension failed to load.
* @param {ExtensionHighlight} manifest Three 'highlight' strings in
* |manifest| represent three portions of the file's content to display -
* the portion which is most relevant and should be emphasized
* (highlight), and the parts both before and after this portion. These
* may be empty.
* @param {HTMLLIElement} listElement The HTML element used for displaying the
* failure path for the additional failures UI.
* @constructor
* @extends {HTMLDivElement}
*/
function Failure(filePath, error, manifest, listElement) {
this.path = filePath;
this.error = error;
this.manifest = manifest;
this.listElement = listElement;
}
ExtensionLoadError.prototype = {
__proto__: HTMLDivElement.prototype,
/**
* Initialize the ExtensionLoadError div.
*/
init: function() {
/**
* The element which displays the path of the extension.
* @type {HTMLElement}
* @private
*/
this.path_ = /** @type {HTMLElement} */(
this.querySelector('#extension-load-error-path'));
/**
* The element which displays the reason the extension failed to load.
* @type {HTMLElement}
* @private
*/
this.reason_ = /** @type {HTMLElement} */(
this.querySelector('#extension-load-error-reason'));
/**
* The element which displays the manifest code.
* @type {extensions.ExtensionCode}
* @private
*/
this.manifest_ = new extensions.ExtensionCode(
this.querySelector('#extension-load-error-manifest'));
/**
* The element which displays information about additional errors.
* @type {HTMLElement}
* @private
*/
this.additional_ = /** @type {HTMLUListElement} */(
this.querySelector('#extension-load-error-additional'));
this.additional_.list = this.additional_.getElementsByTagName('ul')[0];
/**
* An array of Failures for keeping track of multiple active failures.
* @type {Array<Failure>}
* @private
*/
this.failures_ = [];
this.querySelector('#extension-load-error-retry-button').addEventListener(
'click', function(e) {
chrome.send('extensionLoaderRetry');
this.remove_();
}.bind(this));
this.querySelector('#extension-load-error-give-up-button').
addEventListener('click', function(e) {
chrome.send('extensionLoaderIgnoreFailure');
this.remove_();
}.bind(this));
chrome.send('extensionLoaderDisplayFailures');
},
/**
* Add a failure to failures_ array. If there is already a displayed
* failure, display the additional failures element.
* @param {Array<Object>} failures Array of failures containing paths,
* errors, and manifests.
* @private
*/
add_: function(failures) {
// If a failure is already being displayed, unhide the last item.
if (this.failures_.length > 0)
this.failures_[this.failures_.length - 1].listElement.hidden = false;
failures.forEach(function(failure) {
var listItem = /** @type {HTMLLIElement} */(
document.createElement('li'));
listItem.textContent = failure.path;
this.additional_.list.appendChild(listItem);
this.failures_.push(new Failure(failure.path,
failure.error,
failure.manifest,
listItem));
}.bind(this));
// Hide the last item because the UI is displaying its information.
this.failures_[this.failures_.length - 1].listElement.hidden = true;
this.show_();
},
/**
* Remove a failure from |failures_| array. If this was the last failure,
* hide the error UI. If this was the last additional failure, hide
* the additional failures UI.
* @private
*/
remove_: function() {
this.additional_.list.removeChild(
this.failures_[this.failures_.length - 1].listElement);
this.failures_.pop();
if (this.failures_.length > 0) {
this.failures_[this.failures_.length - 1].listElement.hidden = true;
this.show_();
} else {
this.hidden = true;
}
},
/**
* Display the load error to the user. The last failure gets its manifest
* and error displayed, while additional failures have their path names
* displayed in the additional failures element.
* @private
*/
show_: function() {
assert(this.failures_.length >= 1);
var failure = this.failures_[this.failures_.length - 1];
this.path_.textContent = failure.path;
this.reason_.textContent = failure.error;
failure.manifest.message = failure.error;
this.manifest_.populate(
failure.manifest,
loadTimeData.getString('extensionLoadCouldNotLoadManifest'));
this.hidden = false;
this.manifest_.scrollToError();
this.additional_.hidden = this.failures_.length == 1;
}
};
/**
* The ExtensionLoader is the class in charge of loading unpacked extensions.
* @constructor
*/
function ExtensionLoader() {
/**
* The ExtensionLoadError to show any errors from loading an unpacked
* extension.
* @type {ExtensionLoadError}
* @private
*/
this.loadError_ = new ExtensionLoadError(
/** @type {HTMLDivElement} */($('extension-load-error')));
}
cr.addSingletonGetter(ExtensionLoader);
ExtensionLoader.prototype = {
/**
* Whether or not we are currently loading an unpacked extension.
* @private {boolean}
*/
isLoading_: false,
/**
* Begin the sequence of loading an unpacked extension. If an error is
* encountered, this object will get notified via notifyFailed().
*/
loadUnpacked: function() {
if (this.isLoading_) // Only one running load at a time.
return;
this.isLoading_ = true;
chrome.developerPrivate.loadUnpacked({failQuietly: true}, function() {
// Check lastError to avoid the log, but don't do anything with it -
// error-handling is done on the C++ side.
var lastError = chrome.runtime.lastError;
this.isLoading_ = false;
}.bind(this));
},
/**
* Notify the ExtensionLoader that loading an unpacked extension failed.
* Add the failure to failures_ and show the ExtensionLoadError.
* @param {Array<Object>} failures Array of failures containing paths,
* errors, and manifests.
*/
notifyFailed: function(failures) {
this.loadError_.add_(failures);
},
};
/**
* A static forwarding function for ExtensionLoader.notifyFailed.
* @param {Array<Object>} failures Array of failures containing paths,
* errors, and manifests.
* @see ExtensionLoader.notifyFailed
*/
ExtensionLoader.notifyLoadFailed = function(failures) {
ExtensionLoader.getInstance().notifyFailed(failures);
};
return {
ExtensionLoader: ExtensionLoader
};
});