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

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

Issue 23624002: Add UI for RuntimeErrors in the ErrorConsole (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@dc_ec_merge
Patch Set: Created 7 years, 3 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 * Returns whether or not a given |url| is associated with an extension. 9 * Returns whether or not a given |url| is associated with an extension.
10 * @param {string} url The url to examine. 10 * @param {string} url The url to examine.
(...skipping 27 matching lines...) Expand all
38 } 38 }
39 39
40 /** 40 /**
41 * Creates a new ExtensionError HTMLElement; this is used to show a 41 * Creates a new ExtensionError HTMLElement; this is used to show a
42 * notification to the user when an error is caused by an extension. 42 * notification to the user when an error is caused by an extension.
43 * @param {Object} error The error the element should represent. 43 * @param {Object} error The error the element should represent.
44 * @constructor 44 * @constructor
45 * @extends {HTMLDivElement} 45 * @extends {HTMLDivElement}
46 */ 46 */
47 function ExtensionError(error) { 47 function ExtensionError(error) {
48 var div = document.createElement('div'); 48 if (error.stackTrace || error.contextUrl) {
not at google - send to devlin 2013/09/05 00:37:16 A system that I think would make more sense here i
Devlin 2013/09/05 17:53:55 Helps a bit, but we still have to check for where
49 var div = cloneTemplate('extension-error-detailed-wrapper');
50 div.isDetailed = true;
51 } else {
52 var div = document.createElement('div');
53 div.className = 'extension-error-simple-wrapper';
54 div.isDetailed = false;
55 }
56
49 div.__proto__ = ExtensionError.prototype; 57 div.__proto__ = ExtensionError.prototype;
50 div.className = 'extension-error-simple-wrapper';
51 div.error_ = error; 58 div.error_ = error;
52 div.decorate(); 59 div.decorate();
53 return div; 60 return div;
54 } 61 }
55 62
56 ExtensionError.prototype = { 63 ExtensionError.prototype = {
57 __proto__: HTMLDivElement.prototype, 64 __proto__: HTMLDivElement.prototype,
58 65
59 /** @override */ 66 /** @override */
60 decorate: function() { 67 decorate: function() {
(...skipping 16 matching lines...) Expand all
77 this.extensionUrl_ = 84 this.extensionUrl_ =
78 'chrome-extension://' + this.error_.extensionId + '/'; 85 'chrome-extension://' + this.error_.extensionId + '/';
79 86
80 metadata.querySelector('.extension-error-message').innerText = 87 metadata.querySelector('.extension-error-message').innerText =
81 this.error_.message; 88 this.error_.message;
82 89
83 metadata.appendChild(this.getViewSourceOrPlain_( 90 metadata.appendChild(this.getViewSourceOrPlain_(
84 getRelativeUrl(this.error_.source, this.extensionUrl_), 91 getRelativeUrl(this.error_.source, this.extensionUrl_),
85 this.error_.source)); 92 this.error_.source));
86 93
87 this.appendChild(metadata); 94 if (this.isDetailed) {
95 var summary = this.querySelector('summary');
96 summary.appendChild(metadata);
97
98 var detailsNode = this.querySelector('.extension-error-details');
99 if (this.error_.contextUrl)
100 detailsNode.appendChild(this.getContextNode_());
101 if (this.error_.stackTrace)
102 detailsNode.appendChild(this.getStackNode_());
103 } else {
104 this.appendChild(metadata);
105 }
88 }, 106 },
89 107
90 /** 108 /**
91 * Return a div with text |description|. If it's possible to view the source 109 * Return a div with text |description|. If it's possible to view the source
92 * for |url|, linkify the div to do so. 110 * for |url|, linkify the div to do so.
93 * @param {string} description a human-friendly description the location 111 * @param {string} description a human-friendly description the location
94 * (e.g., filename, line). 112 * (e.g., filename, line).
95 * @param {string} url The url of the resource to view. 113 * @param {string} url The url of the resource to view.
114 * @param {?number} line An optional line number of the resource.
not at google - send to devlin 2013/09/05 00:37:16 s/number/line
Devlin 2013/09/05 17:53:55 I thought it was supposed to follow @param {type}
not at google - send to devlin 2013/09/06 17:05:19 Oops I totally misread that.
96 * @return {HTMLElement} The created node, either a link or plaintext. 115 * @return {HTMLElement} The created node, either a link or plaintext.
97 * @private 116 * @private
98 */ 117 */
99 getViewSourceOrPlain_: function(description, url) { 118 getViewSourceOrPlain_: function(description, url, line) {
100 if (this.canViewSource_(url)) 119 if (this.canViewSource_(url))
101 var node = this.getViewSourceLink_(url); 120 var node = this.getViewSourceLink_(url, line);
102 else 121 else
103 var node = document.createElement('div'); 122 var node = document.createElement('div');
104 node.className = 'extension-error-view-source'; 123 node.className = 'extension-error-view-source';
105 node.innerText = description; 124 node.innerText = description;
106 return node; 125 return node;
107 }, 126 },
108 127
109 /** 128 /**
110 * Determine whether we can view the source of a given url. 129 * Determine whether we can view the source of a given url.
111 * @param {string} url The url of the resource to view. 130 * @param {string} url The url of the resource to view.
112 * @return {boolean} Whether or not we can view the source for the url. 131 * @return {boolean} Whether or not we can view the source for the url.
113 * @private 132 * @private
114 */ 133 */
115 canViewSource_: function(url) { 134 canViewSource_: function(url) {
116 return isExtensionUrl(url, this.extensionUrl_) || url == 'manifest.json'; 135 return isExtensionUrl(url, this.extensionUrl_) || url == 'manifest.json';
117 }, 136 },
118 137
119 /** 138 /**
120 * Create a clickable node to view the source for the given url. 139 * Create a clickable node to view the source for the given url.
121 * @param {string} url The url to the resource to view. 140 * @param {string} url The url to the resource to view.
122 * @return {HTMLElement} The clickable node to view the source. 141 * @return {HTMLElement} The clickable node to view the source.
123 * @private 142 * @private
124 */ 143 */
125 getViewSourceLink_: function(url) { 144 getViewSourceLink_: function(url, line) {
126 var node = document.createElement('a'); 145 var node = document.createElement('a');
127 var relativeUrl = getRelativeUrl(url, this.extensionUrl_); 146 var relativeUrl = getRelativeUrl(url, this.extensionUrl_);
147 var dictionary = { 'extensionId': this.error_.extensionId,
148 'message': this.error_.message,
149 'pathSuffix': relativeUrl };
150 if (relativeUrl === 'manifest.json') {
151 dictionary.fileType = 'manifest';
152 dictionary.manifestKey = this.error_.manifestKey;
153 dictionary.manifestSpecific = this.error_.manifestSpecific;
154 } else {
155 dictionary.fileType = 'source';
156 // If we specify a line in the function call, use that. Otherwise, use
157 // the line of the last stack frame, or 0 if we don't have a stack (0
158 // results in no highlighting).
159 dictionary.lineNumber =
160 line ? line : this.error_.stackTrace ?
161 this.error_.stackTrace[0].lineNumber : 0;
162 }
128 163
129 node.addEventListener('click', function(e) { 164 node.addEventListener('click', function(e) {
130 chrome.send('extensionErrorRequestFileSource', 165 chrome.send('extensionErrorRequestFileSource', [dictionary]);
131 [{'extensionId': this.error_.extensionId, 166 });
132 'message': this.error_.message, 167 node.title = loadTimeData.getString('extensionErrorViewSource');
133 'fileType': 'manifest', 168 return node;
134 'pathSuffix': relativeUrl, 169 },
135 'manifestKey': this.error_.manifestKey, 170
136 'manifestSpecific': this.error_.manifestSpecific}]); 171 /**
137 }.bind(this)); 172 * Get the context node for this error. This will attempt to link to the
173 * context in which the error occurred, and can be either an extension page
174 * or an external page.
175 * @return {HTMLDivElement} The context node for the error, including the
176 * label and a link to the context.
177 * @private
178 */
179 getContextNode_: function() {
180 var node = cloneTemplate('extension-error-context-wrapper');
181 var linkNode = node.querySelector('a');
182 if (isExtensionUrl(this.error_.contextUrl, this.extensionUrl_)) {
183 linkNode.innerText = getRelativeUrl(this.error_.contextUrl,
184 this.extensionUrl_);
185 } else {
186 linkNode.innerText = this.error_.contextUrl;
187 linkNode.href = this.error_.contextUrl;
188 linkNode.target = '_blank';
189 }
190 return node;
191 },
192
193 /**
194 * Get a node for the stack trace for this error. Each stack frame will
195 * include a resource url, line number, and function name (possibly
196 * anonymous). If possible, these frames will also be linked for viewing the
197 * source.
198 * @return {HTMLDetailsElement} The stack trace node for this error, with
199 * all stack frames nested in a details-summary object.
200 * @private
201 */
202 getStackNode_: function() {
203 var node = cloneTemplate('extension-error-stack-trace');
204 var listNode = node.querySelector('.extension-error-stack-trace-list');
205 this.error_.stackTrace.forEach(function(frame) {
206 var frameNode = document.createElement('div');
207 var description = getRelativeUrl(frame.url, this.extensionUrl_) +
208 ':' + frame.lineNumber;
209 if (frame.functionName) {
210 var functionName = frame.functionName == '(anonymous function)' ?
211 loadTimeData.getString('extensionErrorAnonymousFunction') :
212 frame.functionName;
213 description += ' (' + functionName + ')';
214 }
215 frameNode.appendChild(this.getViewSourceOrPlain_(
216 description, frame.url, frame.lineNumber));
217 listNode.appendChild(
218 document.createElement('li')).appendChild(frameNode);
219 }, this);
220
138 return node; 221 return node;
139 }, 222 },
140 }; 223 };
141 224
142 /** 225 /**
143 * A variable length list of runtime or manifest errors for a given extension. 226 * A variable length list of runtime or manifest errors for a given extension.
227 * @param {Array.<Object>} errors The list of extension errors with which
228 * to populate the list.
229 * @param {string} type The type of errors, either 'manifest' or 'runtime'.
144 * @constructor 230 * @constructor
145 * @extends {HTMLDivElement} 231 * @extends {HTMLDivElement}
146 */ 232 */
147 function ExtensionErrorList(errors) { 233 function ExtensionErrorList(errors, type) {
148 var div = cloneTemplate('extension-error-list'); 234 var div = cloneTemplate('extension-error-list');
149 div.__proto__ = ExtensionErrorList.prototype; 235 div.__proto__ = ExtensionErrorList.prototype;
150 div.errors_ = errors; 236 div.errors_ = errors;
237 div.type_ = type;
151 div.decorate(); 238 div.decorate();
152 return div; 239 return div;
153 } 240 }
154 241
155 ExtensionErrorList.prototype = { 242 ExtensionErrorList.prototype = {
156 __proto__: HTMLDivElement.prototype, 243 __proto__: HTMLDivElement.prototype,
157 244
158 /** 245 /**
159 * @private 246 * @private
160 * @const 247 * @const
161 * @type {number} 248 * @type {number}
162 */ 249 */
163 MAX_ERRORS_TO_SHOW_: 3, 250 MAX_ERRORS_TO_SHOW_: 3,
164 251
165 /** @override */ 252 /** @override */
166 decorate: function() { 253 decorate: function() {
254 var title = this.type_ == 'manifest' ? 'extensionErrorsManifestErrors' :
255 'extensionErrorsRuntimeErrors';
256 this.querySelector('.extension-error-list-title').innerText =
257 loadTimeData.getString(title);
258
167 this.contents_ = this.querySelector('.extension-error-list-contents'); 259 this.contents_ = this.querySelector('.extension-error-list-contents');
168 this.errors_.forEach(function(error) { 260 this.errors_.forEach(function(error) {
169 this.contents_.appendChild(document.createElement('li')).appendChild( 261 this.contents_.appendChild(document.createElement('li')).appendChild(
170 new ExtensionError(error)); 262 new ExtensionError(error));
171 }, this); 263 }, this);
172 264
173 if (this.contents_.children.length > this.MAX_ERRORS_TO_SHOW_) { 265 if (this.contents_.children.length > this.MAX_ERRORS_TO_SHOW_) {
174 for (var i = this.MAX_ERRORS_TO_SHOW_; 266 for (var i = this.MAX_ERRORS_TO_SHOW_;
175 i < this.contents_.children.length; ++i) { 267 i < this.contents_.children.length; ++i) {
176 this.contents_.children[i].hidden = true; 268 this.contents_.children[i].hidden = true;
(...skipping 21 matching lines...) Expand all
198 button.innerText = loadTimeData.getString(message); 290 button.innerText = loadTimeData.getString(message);
199 button.isShowingAll = !button.isShowingAll; 291 button.isShowingAll = !button.isShowingAll;
200 }.bind(this)); 292 }.bind(this));
201 } 293 }
202 }; 294 };
203 295
204 return { 296 return {
205 ExtensionErrorList: ExtensionErrorList 297 ExtensionErrorList: ExtensionErrorList
206 }; 298 };
207 }); 299 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698