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
3 // found in the LICENSE file.
5 cr.define('extensions', function() {
9 * Clone a template within the extension error template collection.
10 * @param {string} templateName The class name of the template to clone.
11 * @return {HTMLElement} The clone of the template.
13 function cloneTemplate(templateName) {
14 return /** @type {HTMLElement} */($('template-collection-extension-error').
15 querySelector('.' + templateName).cloneNode(true));
19 * Checks that an Extension ID follows the proper format (i.e., is 32
20 * characters long, is lowercase, and contains letters in the range [a, p]).
21 * @param {string} id The Extension ID to test.
22 * @return {boolean} Whether or not the ID is valid.
24 function idIsValid(id) {
25 return /^[a-p]{32}$/.test(id);
29 * Creates a new ExtensionError HTMLElement; this is used to show a
30 * notification to the user when an error is caused by an extension.
31 * @param {Object} error The error the element should represent.
33 * @extends {HTMLDivElement}
35 function ExtensionError(error) {
36 var div = cloneTemplate('extension-error-metadata');
37 div.__proto__ = ExtensionError.prototype;
42 ExtensionError.prototype = {
43 __proto__: HTMLDivElement.prototype,
46 * @param {RuntimeError} error
48 decorate: function(error) {
49 // Add an additional class for the severity level.
51 this.classList.add('extension-error-severity-info');
52 else if (error.level == 1)
53 this.classList.add('extension-error-severity-warning');
55 this.classList.add('extension-error-severity-fatal');
57 var iconNode = document.createElement('img');
58 iconNode.className = 'extension-error-icon';
59 this.insertBefore(iconNode, this.firstChild);
61 var messageSpan = this.querySelector('.extension-error-message');
62 messageSpan.textContent = error.message;
63 messageSpan.title = error.message;
65 var extensionUrl = 'chrome-extension://' + error.extensionId + '/';
66 var viewDetailsLink = this.querySelector('.extension-error-view-details');
68 // If we cannot open the file source and there are no external frames in
69 // the stack, then there are no details to display.
70 if (!extensions.ExtensionErrorOverlay.canShowOverlayForError(
71 error, extensionUrl)) {
72 viewDetailsLink.hidden = true;
74 var stringId = extensionUrl.toLowerCase() == 'manifest.json' ?
75 'extensionErrorViewManifest' : 'extensionErrorViewDetails';
76 viewDetailsLink.textContent = loadTimeData.getString(stringId);
78 viewDetailsLink.addEventListener('click', function(e) {
79 extensions.ExtensionErrorOverlay.getInstance().setErrorAndShowOverlay(
87 * A variable length list of runtime or manifest errors for a given extension.
88 * @param {Array.<Object>} errors The list of extension errors with which
89 * to populate the list.
91 * @extends {HTMLDivElement}
93 function ExtensionErrorList(errors) {
94 var div = cloneTemplate('extension-error-list');
95 div.__proto__ = ExtensionErrorList.prototype;
106 ExtensionErrorList.MAX_ERRORS_TO_SHOW_ = 3;
108 ExtensionErrorList.prototype = {
109 __proto__: HTMLDivElement.prototype,
111 decorate: function() {
112 this.contents_ = this.querySelector('.extension-error-list-contents');
113 this.errors_.forEach(function(error) {
114 if (idIsValid(error.extensionId)) {
115 this.contents_.appendChild(document.createElement('li')).appendChild(
116 new ExtensionError(error));
120 var numShowing = this.contents_.children.length;
121 if (numShowing > ExtensionErrorList.MAX_ERRORS_TO_SHOW_)
122 this.initShowMoreLink_();
126 * Initialize the "Show More" link for the error list. If there are more
127 * than |MAX_ERRORS_TO_SHOW_| errors in the list.
130 initShowMoreLink_: function() {
131 var link = this.querySelector(
132 '.extension-error-list-show-more [is="action-link"]');
134 link.isShowingAll = false;
136 var listContents = this.querySelector('.extension-error-list-contents');
138 // TODO(dbeam/kalman): trade all this transition voodoo for .animate()?
139 listContents.addEventListener('webkitTransitionEnd', function(e) {
140 if (listContents.classList.contains('deactivating'))
141 listContents.classList.remove('deactivating', 'active');
143 listContents.classList.add('scrollable');
146 link.addEventListener('click', function(e) {
147 link.isShowingAll = !link.isShowingAll;
149 var message = link.isShowingAll ? 'extensionErrorsShowFewer' :
150 'extensionErrorsShowMore';
151 link.textContent = loadTimeData.getString(message);
153 // Disable scrolling while transitioning. If the element is active,
154 // scrolling is enabled when the transition ends.
155 listContents.classList.remove('scrollable');
157 if (link.isShowingAll) {
158 listContents.classList.add('active');
159 listContents.classList.remove('deactivating');
161 listContents.classList.add('deactivating');
168 ExtensionErrorList: ExtensionErrorList