Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: chrome/browser/resources/extensions/extension_error.js

Issue 916243002: Enable keyboard shortcuts for chrome://extensions (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix license comment and Rebase Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 cr.define('extensions', function() { 5 cr.define('extensions', function() {
6 'use strict'; 6 'use strict';
7 7
8 /** 8 /**
9 * Clone a template within the extension error template collection. 9 * Clone a template within the extension error template collection.
10 * @param {string} templateName The class name of the template to clone. 10 * @param {string} templateName The class name of the template to clone.
(...skipping 10 matching lines...) Expand all
21 * @param {string} id The Extension ID to test. 21 * @param {string} id The Extension ID to test.
22 * @return {boolean} Whether or not the ID is valid. 22 * @return {boolean} Whether or not the ID is valid.
23 */ 23 */
24 function idIsValid(id) { 24 function idIsValid(id) {
25 return /^[a-p]{32}$/.test(id); 25 return /^[a-p]{32}$/.test(id);
26 } 26 }
27 27
28 /** 28 /**
29 * Creates a new ExtensionError HTMLElement; this is used to show a 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. 30 * notification to the user when an error is caused by an extension.
31 * @param {Object} error The error the element should represent. 31 * @param {RuntimeError} error The error the element should represent.
32 * @param {Element} boundary The boundary for the focus grid.
32 * @constructor 33 * @constructor
33 * @extends {HTMLDivElement} 34 * @extends {cr.ui.FocusRow}
34 */ 35 */
35 function ExtensionError(error) { 36 function ExtensionError(error, boundary) {
36 var div = cloneTemplate('extension-error-metadata'); 37 var div = cloneTemplate('extension-error-metadata');
37 div.__proto__ = ExtensionError.prototype; 38 div.__proto__ = ExtensionError.prototype;
38 div.decorate(error); 39 div.decorate(error, boundary);
39 return div; 40 return div;
40 } 41 }
41 42
42 ExtensionError.prototype = { 43 ExtensionError.prototype = {
43 __proto__: HTMLDivElement.prototype, 44 __proto__: cr.ui.FocusRow.prototype,
45
46 /** @override */
47 getEquivalentElement: function(element) {
48 return assert(this.querySelector('.extension-error-view-details'));
49 },
44 50
45 /** 51 /**
46 * @param {RuntimeError} error 52 * @param {RuntimeError} error The error the element should represent
53 * @param {Element} boundary The boundary for the FocusGrid.
54 * @override
47 */ 55 */
48 decorate: function(error) { 56 decorate: function(error, boundary) {
57 cr.ui.FocusRow.prototype.decorate.call(this, boundary);
58
49 // Add an additional class for the severity level. 59 // Add an additional class for the severity level.
50 if (error.level == 0) 60 if (error.level == 0)
51 this.classList.add('extension-error-severity-info'); 61 this.classList.add('extension-error-severity-info');
52 else if (error.level == 1) 62 else if (error.level == 1)
53 this.classList.add('extension-error-severity-warning'); 63 this.classList.add('extension-error-severity-warning');
54 else 64 else
55 this.classList.add('extension-error-severity-fatal'); 65 this.classList.add('extension-error-severity-fatal');
56 66
57 var iconNode = document.createElement('img'); 67 var iconNode = document.createElement('img');
58 iconNode.className = 'extension-error-icon'; 68 iconNode.className = 'extension-error-icon';
69 // TODO(hcarmona): Populate alt text with a proper description since this
70 // icon conveys the severity of the error. (info, warning, fatal).
71 iconNode.alt = '';
59 this.insertBefore(iconNode, this.firstChild); 72 this.insertBefore(iconNode, this.firstChild);
60 73
61 var messageSpan = this.querySelector('.extension-error-message'); 74 var messageSpan = this.querySelector('.extension-error-message');
62 messageSpan.textContent = error.message; 75 messageSpan.textContent = error.message;
63 messageSpan.title = error.message; 76 messageSpan.title = error.message;
64 77
65 var extensionUrl = 'chrome-extension://' + error.extensionId + '/'; 78 var extensionUrl = 'chrome-extension://' + error.extensionId + '/';
66 var viewDetailsLink = this.querySelector('.extension-error-view-details'); 79 var viewDetailsLink = this.querySelector('.extension-error-view-details');
67 80
68 // If we cannot open the file source and there are no external frames in 81 // If we cannot open the file source and there are no external frames in
69 // the stack, then there are no details to display. 82 // the stack, then there are no details to display.
70 if (!extensions.ExtensionErrorOverlay.canShowOverlayForError( 83 if (!extensions.ExtensionErrorOverlay.canShowOverlayForError(
71 error, extensionUrl)) { 84 error, extensionUrl)) {
72 viewDetailsLink.hidden = true; 85 viewDetailsLink.hidden = true;
73 } else { 86 } else {
74 var stringId = extensionUrl.toLowerCase() == 'manifest.json' ? 87 var stringId = extensionUrl.toLowerCase() == 'manifest.json' ?
75 'extensionErrorViewManifest' : 'extensionErrorViewDetails'; 88 'extensionErrorViewManifest' : 'extensionErrorViewDetails';
76 viewDetailsLink.textContent = loadTimeData.getString(stringId); 89 viewDetailsLink.textContent = loadTimeData.getString(stringId);
77 90
78 viewDetailsLink.addEventListener('click', function(e) { 91 viewDetailsLink.addEventListener('click', function(e) {
79 extensions.ExtensionErrorOverlay.getInstance().setErrorAndShowOverlay( 92 extensions.ExtensionErrorOverlay.getInstance().setErrorAndShowOverlay(
80 error, extensionUrl); 93 error, extensionUrl);
81 }); 94 });
95
96 this.addFocusableElement(viewDetailsLink);
82 } 97 }
83 }, 98 },
84 }; 99 };
85 100
86 /** 101 /**
87 * A variable length list of runtime or manifest errors for a given extension. 102 * 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 103 * @param {Array<Object>} errors The list of extension errors with which
89 * to populate the list. 104 * to populate the list.
90 * @constructor 105 * @constructor
91 * @extends {HTMLDivElement} 106 * @extends {HTMLDivElement}
(...skipping 10 matching lines...) Expand all
102 * @private 117 * @private
103 * @const 118 * @const
104 * @type {number} 119 * @type {number}
105 */ 120 */
106 ExtensionErrorList.MAX_ERRORS_TO_SHOW_ = 3; 121 ExtensionErrorList.MAX_ERRORS_TO_SHOW_ = 3;
107 122
108 ExtensionErrorList.prototype = { 123 ExtensionErrorList.prototype = {
109 __proto__: HTMLDivElement.prototype, 124 __proto__: HTMLDivElement.prototype,
110 125
111 decorate: function() { 126 decorate: function() {
112 this.contents_ = this.querySelector('.extension-error-list-contents'); 127 this.focusGrid_ = new cr.ui.FocusGrid();
128 this.gridBoundary_ = this.querySelector('.extension-error-list-contents');
129 this.gridBoundary_.addEventListener('focus', this.onFocus_.bind(this));
130 this.gridBoundary_.addEventListener('focusin',
131 this.onFocusin_.bind(this));
113 this.errors_.forEach(function(error) { 132 this.errors_.forEach(function(error) {
114 if (idIsValid(error.extensionId)) { 133 if (idIsValid(error.extensionId)) {
115 this.contents_.appendChild(document.createElement('li')).appendChild( 134 var focusRow = new ExtensionError(error, this.gridBoundary_);
116 new ExtensionError(error)); 135 this.gridBoundary_.appendChild(
136 document.createElement('li')).appendChild(focusRow);
137 this.focusGrid_.addRow(focusRow);
117 } 138 }
118 }, this); 139 }, this);
119 140
120 var numShowing = this.contents_.children.length; 141 var numShowing = this.focusGrid_.rows.length;
121 if (numShowing > ExtensionErrorList.MAX_ERRORS_TO_SHOW_) 142 if (numShowing > ExtensionErrorList.MAX_ERRORS_TO_SHOW_)
122 this.initShowMoreLink_(); 143 this.initShowMoreLink_();
123 }, 144 },
124 145
125 /** 146 /**
147 * @return {?Element} The element that toggles between show more and show
148 * less, or null if it's hidden. Button will be hidden if there are less
149 * errors than |MAX_ERRORS_TO_SHOW_|.
150 */
151 getToggleElement: function() {
152 return this.querySelector(
153 '.extension-error-list-show-more [is="action-link"]:not([hidden])');
154 },
155
156 /** @return {!Element} The element containing the list of errors. */
157 getErrorListElement: function() {
158 return this.gridBoundary_;
159 },
160
161 /**
162 * The grid should not be focusable once it or an element inside it is
163 * focused. This is necessary to allow tabbing out of the grid in reverse.
164 * @private
165 */
166 onFocusin_: function() {
167 this.gridBoundary_.tabIndex = -1;
168 },
169
170 /**
171 * Focus the first focusable row when tabbing into the grid for the
172 * first time.
173 * @private
174 */
175 onFocus_: function() {
176 var activeRow = this.gridBoundary_.querySelector('.focus-row-active');
177 var toggleButton = this.getToggleElement();
178
179 if (toggleButton && !toggleButton.isShowingAll) {
180 var rows = this.focusGrid_.rows;
181 assert(rows.length > ExtensionErrorList.MAX_ERRORS_TO_SHOW_);
182
183 var firstVisible = rows.length - ExtensionErrorList.MAX_ERRORS_TO_SHOW_;
184 if (rows.indexOf(activeRow) < firstVisible)
185 activeRow = rows[firstVisible];
186 } else if (!activeRow) {
187 activeRow = this.focusGrid_.rows[0];
188 }
189
190 activeRow.getEquivalentElement(null).focus();
191 },
192
193 /**
126 * Initialize the "Show More" link for the error list. If there are more 194 * Initialize the "Show More" link for the error list. If there are more
127 * than |MAX_ERRORS_TO_SHOW_| errors in the list. 195 * than |MAX_ERRORS_TO_SHOW_| errors in the list.
128 * @private 196 * @private
129 */ 197 */
130 initShowMoreLink_: function() { 198 initShowMoreLink_: function() {
131 var link = this.querySelector( 199 var link = this.querySelector(
132 '.extension-error-list-show-more [is="action-link"]'); 200 '.extension-error-list-show-more [is="action-link"]');
133 link.hidden = false; 201 link.hidden = false;
134 link.isShowingAll = false; 202 link.isShowingAll = false;
135 203
136 var listContents = this.querySelector('.extension-error-list-contents'); 204 var listContents = this.querySelector('.extension-error-list-contents');
137 205
138 // TODO(dbeam/kalman): trade all this transition voodoo for .animate()? 206 // TODO(dbeam/kalman): trade all this transition voodoo for .animate()?
139 listContents.addEventListener('webkitTransitionEnd', function(e) { 207 listContents.addEventListener('webkitTransitionEnd', function(e) {
140 if (listContents.classList.contains('deactivating')) 208 if (listContents.classList.contains('deactivating'))
141 listContents.classList.remove('deactivating', 'active'); 209 listContents.classList.remove('deactivating', 'active');
142 else 210 else
143 listContents.classList.add('scrollable'); 211 listContents.classList.add('scrollable');
144 }); 212 });
145 213
146 link.addEventListener('click', function(e) { 214 link.addEventListener('click', function(e) {
215 // Needs to be enabled in case the focused row is now hidden.
216 this.gridBoundary_.tabIndex = 0;
217
147 link.isShowingAll = !link.isShowingAll; 218 link.isShowingAll = !link.isShowingAll;
148 219
149 var message = link.isShowingAll ? 'extensionErrorsShowFewer' : 220 var message = link.isShowingAll ? 'extensionErrorsShowFewer' :
150 'extensionErrorsShowMore'; 221 'extensionErrorsShowMore';
151 link.textContent = loadTimeData.getString(message); 222 link.textContent = loadTimeData.getString(message);
152 223
153 // Disable scrolling while transitioning. If the element is active, 224 // Disable scrolling while transitioning. If the element is active,
154 // scrolling is enabled when the transition ends. 225 // scrolling is enabled when the transition ends.
155 listContents.classList.remove('scrollable'); 226 listContents.classList.remove('scrollable');
156 227
157 if (link.isShowingAll) { 228 if (link.isShowingAll) {
158 listContents.classList.add('active'); 229 listContents.classList.add('active');
159 listContents.classList.remove('deactivating'); 230 listContents.classList.remove('deactivating');
160 } else { 231 } else {
161 listContents.classList.add('deactivating'); 232 listContents.classList.add('deactivating');
162 } 233 }
163 }.bind(this)); 234 }.bind(this));
164 } 235 }
165 }; 236 };
166 237
167 return { 238 return {
168 ExtensionErrorList: ExtensionErrorList 239 ExtensionErrorList: ExtensionErrorList
169 }; 240 };
170 }); 241 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698