Home | History | Annotate | Download | only in extensions
      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 
      7 cr.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         this.initShowMoreButton_();
    123     },
    124 
    125     /**
    126      * Initialize the "Show More" button for the error list. If there are more
    127      * than |MAX_ERRORS_TO_SHOW_| errors in the list.
    128      * @private
    129      */
    130     initShowMoreButton_: function() {
    131       var button = this.querySelector('.extension-error-list-show-more button');
    132       button.hidden = false;
    133       button.isShowingAll = false;
    134       var listContents = this.querySelector('.extension-error-list-contents');
    135       listContents.addEventListener('webkitTransitionEnd', function(e) {
    136         if (listContents.classList.contains('active'))
    137           listContents.classList.add('scrollable');
    138       });
    139       button.addEventListener('click', function(e) {
    140         // Disable scrolling while transitioning. If the element is active,
    141         // scrolling is enabled when the transition ends.
    142         listContents.classList.toggle('active');
    143         listContents.classList.remove('scrollable');
    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