extension_error.js revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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.
4
5<include src="extension_error_overlay.js"></include>
6
7cr.define('extensions', function() {
8  'use strict';
9
10  /**
11   * Clone a template within the extension error template collection.
12   * @param {string} templateName The class name of the template to clone.
13   * @return {HTMLElement} The clone of the template.
14   */
15  function cloneTemplate(templateName) {
16    return $('template-collection-extension-error').
17        querySelector('.' + templateName).cloneNode(true);
18  }
19
20  /**
21   * Checks that an Extension ID follows the proper format (i.e., is 32
22   * characters long, is lowercase, and contains letters in the range [a, p]).
23   * @param {string} id The Extension ID to test.
24   * @return {boolean} Whether or not the ID is valid.
25   */
26  function idIsValid(id) {
27    return /^[a-p]{32}$/.test(id);
28  }
29
30  /**
31   * Creates a new ExtensionError HTMLElement; this is used to show a
32   * notification to the user when an error is caused by an extension.
33   * @param {Object} error The error the element should represent.
34   * @constructor
35   * @extends {HTMLDivElement}
36   */
37  function ExtensionError(error) {
38    var div = cloneTemplate('extension-error-metadata');
39    div.__proto__ = ExtensionError.prototype;
40    div.decorate(error);
41    return div;
42  }
43
44  ExtensionError.prototype = {
45    __proto__: HTMLDivElement.prototype,
46
47    /** @override */
48    decorate: function(error) {
49      // Add an additional class for the severity level.
50      if (error.level == 0)
51        this.classList.add('extension-error-severity-info');
52      else if (error.level == 1)
53        this.classList.add('extension-error-severity-warning');
54      else
55        this.classList.add('extension-error-severity-fatal');
56
57      var iconNode = document.createElement('img');
58      iconNode.className = 'extension-error-icon';
59      this.insertBefore(iconNode, this.firstChild);
60
61      var messageSpan = this.querySelector('.extension-error-message');
62      messageSpan.textContent = error.message;
63      messageSpan.title = error.message;
64
65      var extensionUrl = 'chrome-extension://' + error.extensionId + '/';
66      var viewDetailsLink = this.querySelector('.extension-error-view-details');
67
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;
73      } else {
74        var stringId = extensionUrl.toLowerCase() == 'manifest.json' ?
75            'extensionErrorViewManifest' : 'extensionErrorViewDetails';
76        viewDetailsLink.textContent = loadTimeData.getString(stringId);
77
78        viewDetailsLink.addEventListener('click', function(e) {
79          extensions.ExtensionErrorOverlay.getInstance().setErrorAndShowOverlay(
80              error, extensionUrl);
81        });
82      }
83    },
84  };
85
86  /**
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.
90   * @constructor
91   * @extends {HTMLDivElement}
92   */
93  function ExtensionErrorList(errors) {
94    var div = cloneTemplate('extension-error-list');
95    div.__proto__ = ExtensionErrorList.prototype;
96    div.errors_ = errors;
97    div.decorate();
98    return div;
99  }
100
101  ExtensionErrorList.prototype = {
102    __proto__: HTMLDivElement.prototype,
103
104    /**
105     * @private
106     * @const
107     * @type {number}
108     */
109    MAX_ERRORS_TO_SHOW_: 3,
110
111    /** @override */
112    decorate: function() {
113      this.contents_ = this.querySelector('.extension-error-list-contents');
114      this.errors_.forEach(function(error) {
115        if (idIsValid(error.extensionId)) {
116          this.contents_.appendChild(document.createElement('li')).appendChild(
117              new ExtensionError(error));
118        }
119      }, this);
120
121      if (this.contents_.children.length > this.MAX_ERRORS_TO_SHOW_) {
122        for (var i = this.MAX_ERRORS_TO_SHOW_;
123             i < this.contents_.children.length; ++i) {
124          this.contents_.children[i].hidden = true;
125        }
126        this.initShowMoreButton_();
127      }
128    },
129
130    /**
131     * Initialize the "Show More" button for the error list. If there are more
132     * than |MAX_ERRORS_TO_SHOW_| errors in the list.
133     * @private
134     */
135    initShowMoreButton_: function() {
136      var button = this.querySelector('.extension-error-list-show-more a');
137      button.hidden = false;
138      button.isShowingAll = false;
139      button.addEventListener('click', function(e) {
140        for (var i = this.MAX_ERRORS_TO_SHOW_;
141             i < this.contents_.children.length; ++i) {
142          this.contents_.children[i].hidden = button.isShowingAll;
143        }
144        var message = button.isShowingAll ? 'extensionErrorsShowMore' :
145                                            'extensionErrorsShowFewer';
146        button.textContent = loadTimeData.getString(message);
147        button.isShowingAll = !button.isShowingAll;
148      }.bind(this));
149    }
150  };
151
152  return {
153    ExtensionErrorList: ExtensionErrorList
154  };
155});
156