OLD | NEW |
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 /** |
| 6 * The type of the stack trace object. The definition is based on |
| 7 * extensions/browser/extension_error.cc:RuntimeError::ToValue(). |
| 8 * @typedef {{columnNumber: number, |
| 9 * functionName: string, |
| 10 * lineNumber: number, |
| 11 * url: string}} |
| 12 */ |
| 13 var StackTrace; |
| 14 |
| 15 /** |
| 16 * The type of the extension error trace object. The definition is based on |
| 17 * extensions/browser/extension_error.cc:RuntimeError::ToValue(). |
| 18 * @typedef {{canInspect: (boolean|undefined), |
| 19 * contextUrl: (string|undefined), |
| 20 * extensionId: string, |
| 21 * fromIncognito: boolean, |
| 22 * level: number, |
| 23 * manifestKey: string, |
| 24 * manifestSpecific: string, |
| 25 * message: string, |
| 26 * renderProcessId: (number|undefined), |
| 27 * renderViewId: (number|undefined), |
| 28 * source: string, |
| 29 * stackTrace: (Array.<StackTrace>|undefined), |
| 30 * type: number}} |
| 31 */ |
| 32 var RuntimeError; |
| 33 |
5 cr.define('extensions', function() { | 34 cr.define('extensions', function() { |
6 'use strict'; | 35 'use strict'; |
7 | 36 |
8 /** | 37 /** |
9 * Clear all the content of a given element. | 38 * Clear all the content of a given element. |
10 * @param {HTMLElement} element The element to be cleared. | 39 * @param {HTMLElement} element The element to be cleared. |
11 */ | 40 */ |
12 function clearElement(element) { | 41 function clearElement(element) { |
13 while (element.firstChild) | 42 while (element.firstChild) |
14 element.removeChild(element.firstChild); | 43 element.removeChild(element.firstChild); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 chrome.developerPrivate.openDevTools(args); | 107 chrome.developerPrivate.openDevTools(args); |
79 else | 108 else |
80 assertNotReached('Cannot call either openDevTools function.'); | 109 assertNotReached('Cannot call either openDevTools function.'); |
81 }; | 110 }; |
82 | 111 |
83 RuntimeErrorContent.prototype = { | 112 RuntimeErrorContent.prototype = { |
84 __proto__: HTMLDivElement.prototype, | 113 __proto__: HTMLDivElement.prototype, |
85 | 114 |
86 /** | 115 /** |
87 * The underlying error whose details are being displayed. | 116 * The underlying error whose details are being displayed. |
88 * @type {Object} | 117 * @type {?RuntimeError} |
89 * @private | 118 * @private |
90 */ | 119 */ |
91 error_: undefined, | 120 error_: null, |
92 | 121 |
93 /** | 122 /** |
94 * The URL associated with this extension, i.e. chrome-extension://<id>/. | 123 * The URL associated with this extension, i.e. chrome-extension://<id>/. |
95 * @type {string} | 124 * @type {?string} |
96 * @private | 125 * @private |
97 */ | 126 */ |
98 extensionUrl_: undefined, | 127 extensionUrl_: null, |
99 | 128 |
100 /** | 129 /** |
101 * The node of the stack trace which is currently active. | 130 * The node of the stack trace which is currently active. |
102 * @type {HTMLElement} | 131 * @type {?HTMLElement} |
103 * @private | 132 * @private |
104 */ | 133 */ |
105 currentFrameNode_: undefined, | 134 currentFrameNode_: null, |
106 | 135 |
107 /** | 136 /** |
108 * Initialize the RuntimeErrorContent for the first time. | 137 * Initialize the RuntimeErrorContent for the first time. |
109 */ | 138 */ |
110 init: function() { | 139 init: function() { |
111 /** | 140 /** |
112 * The stack trace element in the overlay. | 141 * The stack trace element in the overlay. |
113 * @type {HTMLElement} | 142 * @type {HTMLElement} |
114 * @private | 143 * @private |
115 */ | 144 */ |
116 this.stackTrace_ = | 145 this.stackTrace_ = /** @type {HTMLElement} */( |
117 this.querySelector('.extension-error-overlay-stack-trace-list'); | 146 this.querySelector('.extension-error-overlay-stack-trace-list')); |
118 assert(this.stackTrace_); | 147 assert(this.stackTrace_); |
119 | 148 |
120 /** | 149 /** |
121 * The context URL element in the overlay. | 150 * The context URL element in the overlay. |
122 * @type {HTMLElement} | 151 * @type {HTMLElement} |
123 * @private | 152 * @private |
124 */ | 153 */ |
125 this.contextUrl_ = | 154 this.contextUrl_ = /** @type {HTMLElement} */( |
126 this.querySelector('.extension-error-overlay-context-url'); | 155 this.querySelector('.extension-error-overlay-context-url')); |
127 assert(this.contextUrl_); | 156 assert(this.contextUrl_); |
128 }, | 157 }, |
129 | 158 |
130 /** | 159 /** |
131 * Sets the error for the content. | 160 * Sets the error for the content. |
132 * @param {Object} error The error whose content should be displayed. | 161 * @param {RuntimeError} error The error whose content should |
| 162 * be displayed. |
133 * @param {string} extensionUrl The URL associated with this extension. | 163 * @param {string} extensionUrl The URL associated with this extension. |
134 */ | 164 */ |
135 setError: function(error, extensionUrl) { | 165 setError: function(error, extensionUrl) { |
136 this.error_ = error; | 166 this.error_ = error; |
137 this.extensionUrl_ = extensionUrl; | 167 this.extensionUrl_ = extensionUrl; |
138 this.contextUrl_.textContent = error.contextUrl ? | 168 this.contextUrl_.textContent = error.contextUrl ? |
139 getRelativeUrl(error.contextUrl, this.extensionUrl_) : | 169 getRelativeUrl(error.contextUrl, this.extensionUrl_) : |
140 loadTimeData.getString('extensionErrorOverlayContextUnknown'); | 170 loadTimeData.getString('extensionErrorOverlayContextUnknown'); |
141 this.initStackTrace_(); | 171 this.initStackTrace_(); |
142 }, | 172 }, |
143 | 173 |
144 /** | 174 /** |
145 * Wipe content associated with a specific error. | 175 * Wipe content associated with a specific error. |
146 */ | 176 */ |
147 clearError: function() { | 177 clearError: function() { |
148 this.error_ = undefined; | 178 this.error_ = null; |
149 this.extensionUrl_ = undefined; | 179 this.extensionUrl_ = null; |
150 this.currentFrameNode_ = undefined; | 180 this.currentFrameNode_ = null; |
151 clearElement(this.stackTrace_); | 181 clearElement(this.stackTrace_); |
152 this.stackTrace_.hidden = true; | 182 this.stackTrace_.hidden = true; |
153 }, | 183 }, |
154 | 184 |
155 /** | 185 /** |
156 * Makes |frame| active and deactivates the previously active frame (if | 186 * Makes |frame| active and deactivates the previously active frame (if |
157 * there was one). | 187 * there was one). |
158 * @param {HTMLElement} frame The frame to activate. | 188 * @param {HTMLElement} frameNode The frame to activate. |
159 * @private | 189 * @private |
160 */ | 190 */ |
161 setActiveFrame_: function(frameNode) { | 191 setActiveFrame_: function(frameNode) { |
162 if (this.currentFrameNode_) { | 192 if (this.currentFrameNode_) { |
163 this.currentFrameNode_.classList.remove( | 193 this.currentFrameNode_.classList.remove( |
164 RuntimeErrorContent.ACTIVE_CLASS_NAME); | 194 RuntimeErrorContent.ACTIVE_CLASS_NAME); |
165 } | 195 } |
166 | 196 |
167 this.currentFrameNode_ = frameNode; | 197 this.currentFrameNode_ = frameNode; |
168 this.currentFrameNode_.classList.add( | 198 this.currentFrameNode_.classList.add( |
(...skipping 13 matching lines...) Expand all Loading... |
182 continue; | 212 continue; |
183 | 213 |
184 var frameNode = document.createElement('li'); | 214 var frameNode = document.createElement('li'); |
185 // Attach the index of the frame to which this node refers (since we | 215 // Attach the index of the frame to which this node refers (since we |
186 // may skip some, this isn't a 1-to-1 match). | 216 // may skip some, this isn't a 1-to-1 match). |
187 frameNode.indexIntoTrace = i; | 217 frameNode.indexIntoTrace = i; |
188 | 218 |
189 // The description is a human-readable summation of the frame, in the | 219 // The description is a human-readable summation of the frame, in the |
190 // form "<relative_url>:<line_number> (function)", e.g. | 220 // form "<relative_url>:<line_number> (function)", e.g. |
191 // "myfile.js:25 (myFunction)". | 221 // "myfile.js:25 (myFunction)". |
192 var description = getRelativeUrl(frame.url, this.extensionUrl_) + | 222 var description = getRelativeUrl(frame.url, |
193 ':' + frame.lineNumber; | 223 assert(this.extensionUrl_)) + ':' + frame.lineNumber; |
194 if (frame.functionName) { | 224 if (frame.functionName) { |
195 var functionName = frame.functionName == '(anonymous function)' ? | 225 var functionName = frame.functionName == '(anonymous function)' ? |
196 loadTimeData.getString('extensionErrorOverlayAnonymousFunction') : | 226 loadTimeData.getString('extensionErrorOverlayAnonymousFunction') : |
197 frame.functionName; | 227 frame.functionName; |
198 description += ' (' + functionName + ')'; | 228 description += ' (' + functionName + ')'; |
199 } | 229 } |
200 frameNode.textContent = description; | 230 frameNode.textContent = description; |
201 | 231 |
202 // When the user clicks on a frame in the stack trace, we should | 232 // When the user clicks on a frame in the stack trace, we should |
203 // highlight that overlay in the list, display the appropriate source | 233 // highlight that overlay in the list, display the appropriate source |
204 // code with the line highlighted, and link the "Open DevTools" button | 234 // code with the line highlighted, and link the "Open DevTools" button |
205 // with that frame. | 235 // with that frame. |
206 frameNode.addEventListener('click', function(frame, frameNode, e) { | 236 frameNode.addEventListener('click', function(frame, frameNode, e) { |
207 if (this.currStackFrame_ == frameNode) | |
208 return; | |
209 | |
210 this.setActiveFrame_(frameNode); | 237 this.setActiveFrame_(frameNode); |
211 | 238 |
212 // Request the file source with the section highlighted; this will | 239 // Request the file source with the section highlighted; this will |
213 // call ExtensionErrorOverlay.requestFileSourceResponse() when | 240 // call ExtensionErrorOverlay.requestFileSourceResponse() when |
214 // completed, which in turn calls setCode(). | 241 // completed, which in turn calls setCode(). |
215 ExtensionErrorOverlay.requestFileSource( | 242 ExtensionErrorOverlay.requestFileSource( |
216 {extensionId: this.error_.extensionId, | 243 {extensionId: this.error_.extensionId, |
217 message: this.error_.message, | 244 message: this.error_.message, |
218 pathSuffix: getRelativeUrl(frame.url, this.extensionUrl_), | 245 pathSuffix: getRelativeUrl(frame.url, this.extensionUrl_), |
219 lineNumber: frame.lineNumber}); | 246 lineNumber: frame.lineNumber}); |
220 }.bind(this, frame, frameNode)); | 247 }.bind(this, frame, frameNode)); |
221 | 248 |
222 this.stackTrace_.appendChild(frameNode); | 249 this.stackTrace_.appendChild(frameNode); |
223 } | 250 } |
224 | 251 |
225 // Set the current stack frame to the first stack frame and show the | 252 // Set the current stack frame to the first stack frame and show the |
226 // trace, if one exists. (We can't just check error.stackTrace, because | 253 // trace, if one exists. (We can't just check error.stackTrace, because |
227 // it's possible the trace was purely internal, and we don't show | 254 // it's possible the trace was purely internal, and we don't show |
228 // internal frames.) | 255 // internal frames.) |
229 if (this.stackTrace_.children.length > 0) { | 256 if (this.stackTrace_.children.length > 0) { |
230 this.stackTrace_.hidden = false; | 257 this.stackTrace_.hidden = false; |
231 this.setActiveFrame_(this.stackTrace_.firstChild); | 258 this.setActiveFrame_(assertInstanceof(this.stackTrace_.firstChild, |
| 259 HTMLElement)); |
232 } | 260 } |
233 }, | 261 }, |
234 | 262 |
235 /** | 263 /** |
236 * Open the developer tools for the active stack frame. | 264 * Open the developer tools for the active stack frame. |
237 */ | 265 */ |
238 openDevtools: function() { | 266 openDevtools: function() { |
239 var stackFrame = | 267 var stackFrame = |
240 this.error_.stackTrace[this.currentFrameNode_.indexIntoTrace]; | 268 this.error_.stackTrace[this.currentFrameNode_.indexIntoTrace]; |
241 | 269 |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 } else { | 365 } else { |
338 assertNotReached('Cannot call either requestFileSource function.'); | 366 assertNotReached('Cannot call either requestFileSource function.'); |
339 } | 367 } |
340 }; | 368 }; |
341 | 369 |
342 cr.addSingletonGetter(ExtensionErrorOverlay); | 370 cr.addSingletonGetter(ExtensionErrorOverlay); |
343 | 371 |
344 ExtensionErrorOverlay.prototype = { | 372 ExtensionErrorOverlay.prototype = { |
345 /** | 373 /** |
346 * The underlying error whose details are being displayed. | 374 * The underlying error whose details are being displayed. |
347 * @type {Object} | 375 * @type {?RuntimeError} |
348 * @private | 376 * @private |
349 */ | 377 */ |
350 error_: undefined, | 378 error_: null, |
351 | 379 |
352 /** | 380 /** |
353 * Initialize the page. | 381 * Initialize the page. |
354 * @param {function(HTMLDivElement)} showOverlay The function to show or | 382 * @param {function(HTMLDivElement)} showOverlay The function to show or |
355 * hide the ExtensionErrorOverlay; this should take a single parameter | 383 * hide the ExtensionErrorOverlay; this should take a single parameter |
356 * which is either the overlay Div if the overlay should be displayed, | 384 * which is either the overlay Div if the overlay should be displayed, |
357 * or null if the overlay should be hidden. | 385 * or null if the overlay should be hidden. |
358 */ | 386 */ |
359 initializePage: function(showOverlay) { | 387 initializePage: function(showOverlay) { |
360 var overlay = $('overlay'); | 388 var overlay = $('overlay'); |
361 cr.ui.overlay.setupOverlay(overlay); | 389 cr.ui.overlay.setupOverlay(overlay); |
362 cr.ui.overlay.globalInitialization(); | 390 cr.ui.overlay.globalInitialization(); |
363 overlay.addEventListener('cancelOverlay', this.handleDismiss_.bind(this)); | 391 overlay.addEventListener('cancelOverlay', this.handleDismiss_.bind(this)); |
364 | 392 |
365 $('extension-error-overlay-dismiss').addEventListener( | 393 $('extension-error-overlay-dismiss').addEventListener( |
366 'click', this.handleDismiss_.bind(this)); | 394 'click', this.handleDismiss_.bind(this)); |
367 | 395 |
368 /** | 396 /** |
369 * The element of the full overlay. | 397 * The element of the full overlay. |
370 * @type {HTMLDivElement} | 398 * @type {HTMLDivElement} |
371 * @private | 399 * @private |
372 */ | 400 */ |
373 this.overlayDiv_ = $('extension-error-overlay'); | 401 this.overlayDiv_ = /** @type {HTMLDivElement} */( |
| 402 $('extension-error-overlay')); |
374 | 403 |
375 /** | 404 /** |
376 * The portion of the overlay which shows the code relating to the error | 405 * The portion of the overlay which shows the code relating to the error |
377 * and the corresponding line numbers. | 406 * and the corresponding line numbers. |
378 * @type {ExtensionCode} | 407 * @type {extensions.ExtensionCode} |
379 * @private | 408 * @private |
380 */ | 409 */ |
381 this.codeDiv_ = | 410 this.codeDiv_ = |
382 new extensions.ExtensionCode($('extension-error-overlay-code')); | 411 new extensions.ExtensionCode($('extension-error-overlay-code')); |
383 | 412 |
384 /** | 413 /** |
385 * The function to show or hide the ExtensionErrorOverlay. | 414 * The function to show or hide the ExtensionErrorOverlay. |
386 * @type {function} | |
387 * @param {boolean} isVisible Whether the overlay should be visible. | 415 * @param {boolean} isVisible Whether the overlay should be visible. |
388 */ | 416 */ |
389 this.setVisible = function(isVisible) { | 417 this.setVisible = function(isVisible) { |
390 showOverlay(isVisible ? this.overlayDiv_ : null); | 418 showOverlay(isVisible ? this.overlayDiv_ : null); |
391 if (isVisible) | 419 if (isVisible) |
392 this.codeDiv_.scrollToError(); | 420 this.codeDiv_.scrollToError(); |
393 }; | 421 }; |
394 | 422 |
395 /** | 423 /** |
396 * The button to open the developer tools (only available for runtime | 424 * The button to open the developer tools (only available for runtime |
397 * errors). | 425 * errors). |
398 * @type {HTMLButtonElement} | 426 * @type {HTMLButtonElement} |
399 * @private | 427 * @private |
400 */ | 428 */ |
401 this.openDevtoolsButton_ = $('extension-error-overlay-devtools-button'); | 429 this.openDevtoolsButton_ = /** @type {HTMLButtonElement} */( |
| 430 $('extension-error-overlay-devtools-button')); |
402 this.openDevtoolsButton_.addEventListener('click', function() { | 431 this.openDevtoolsButton_.addEventListener('click', function() { |
403 this.runtimeErrorContent_.openDevtools(); | 432 this.runtimeErrorContent_.openDevtools(); |
404 }.bind(this)); | 433 }.bind(this)); |
405 }, | 434 }, |
406 | 435 |
407 /** | 436 /** |
408 * Handles a click on the dismiss ("OK" or close) buttons. | 437 * Handles a click on the dismiss ("OK" or close) buttons. |
409 * @param {Event} e The click event. | 438 * @param {Event} e The click event. |
410 * @private | 439 * @private |
411 */ | 440 */ |
(...skipping 10 matching lines...) Expand all Loading... |
422 this.codeDiv_.clear(); | 451 this.codeDiv_.clear(); |
423 | 452 |
424 this.openDevtoolsButton_.hidden = true; | 453 this.openDevtoolsButton_.hidden = true; |
425 | 454 |
426 if (this.error_.type == ExtensionErrorOverlay.RUNTIME_ERROR_TYPE_) { | 455 if (this.error_.type == ExtensionErrorOverlay.RUNTIME_ERROR_TYPE_) { |
427 this.overlayDiv_.querySelector('.content-area').removeChild( | 456 this.overlayDiv_.querySelector('.content-area').removeChild( |
428 this.runtimeErrorContent_); | 457 this.runtimeErrorContent_); |
429 this.runtimeErrorContent_.clearError(); | 458 this.runtimeErrorContent_.clearError(); |
430 } | 459 } |
431 | 460 |
432 this.error_ = undefined; | 461 this.error_ = null; |
433 }, | 462 }, |
434 | 463 |
435 /** | 464 /** |
436 * Associate an error with the overlay. This will set the error for the | 465 * Associate an error with the overlay. This will set the error for the |
437 * overlay, and, if possible, will populate the code section of the overlay | 466 * overlay, and, if possible, will populate the code section of the overlay |
438 * with the relevant file, load the stack trace, and generate links for | 467 * with the relevant file, load the stack trace, and generate links for |
439 * opening devtools (the latter two only happen for runtime errors). | 468 * opening devtools (the latter two only happen for runtime errors). |
440 * @param {Object} error The error to show in the overlay. | 469 * @param {RuntimeError} error The error to show in the overlay. |
441 * @param {string} extensionUrl The URL of the extension, in the form | 470 * @param {string} extensionUrl The URL of the extension, in the form |
442 * "chrome-extension://<extension_id>". | 471 * "chrome-extension://<extension_id>". |
443 */ | 472 */ |
444 setErrorAndShowOverlay: function(error, extensionUrl) { | 473 setErrorAndShowOverlay: function(error, extensionUrl) { |
445 this.error_ = error; | 474 this.error_ = error; |
446 | 475 |
447 if (this.error_.type == ExtensionErrorOverlay.RUNTIME_ERROR_TYPE_) { | 476 if (this.error_.type == ExtensionErrorOverlay.RUNTIME_ERROR_TYPE_) { |
448 this.runtimeErrorContent_.setError(this.error_, extensionUrl); | 477 this.runtimeErrorContent_.setError(this.error_, extensionUrl); |
449 this.overlayDiv_.querySelector('.content-area').insertBefore( | 478 this.overlayDiv_.querySelector('.content-area').insertBefore( |
450 this.runtimeErrorContent_, | 479 this.runtimeErrorContent_, |
(...skipping 17 matching lines...) Expand all Loading... |
468 requestFileSourceArgs.lineNumber = | 497 requestFileSourceArgs.lineNumber = |
469 error.stackTrace && error.stackTrace[0] ? | 498 error.stackTrace && error.stackTrace[0] ? |
470 error.stackTrace[0].lineNumber : 0; | 499 error.stackTrace[0].lineNumber : 0; |
471 } | 500 } |
472 ExtensionErrorOverlay.requestFileSource(requestFileSourceArgs); | 501 ExtensionErrorOverlay.requestFileSource(requestFileSourceArgs); |
473 } else { | 502 } else { |
474 ExtensionErrorOverlay.requestFileSourceResponse(null); | 503 ExtensionErrorOverlay.requestFileSourceResponse(null); |
475 } | 504 } |
476 }, | 505 }, |
477 | 506 |
| 507 |
478 /** | 508 /** |
479 * Set the code to be displayed in the code portion of the overlay. | 509 * Set the code to be displayed in the code portion of the overlay. |
480 * @see ExtensionErrorOverlay.requestFileSourceResponse(). | 510 * @see ExtensionErrorOverlay.requestFileSourceResponse(). |
481 * @param {?Object} code The code to be displayed. If |code| is null, then | 511 * @param {?ExtensionHighlight} code The code to be displayed. If |code| is |
| 512 * null, then |
482 * a "Could not display code" message will be displayed instead. | 513 * a "Could not display code" message will be displayed instead. |
483 */ | 514 */ |
484 setCode: function(code) { | 515 setCode: function(code) { |
485 document.querySelector( | 516 document.querySelector( |
486 '#extension-error-overlay .extension-error-overlay-title'). | 517 '#extension-error-overlay .extension-error-overlay-title'). |
487 textContent = code.title; | 518 textContent = code.title; |
488 | 519 |
489 this.codeDiv_.populate( | 520 this.codeDiv_.populate( |
490 code, | 521 code, |
491 loadTimeData.getString('extensionErrorOverlayNoCodeToDisplay')); | 522 loadTimeData.getString('extensionErrorOverlayNoCodeToDisplay')); |
492 }, | 523 }, |
493 }; | 524 }; |
494 | 525 |
495 /** | 526 /** |
496 * Called by the ExtensionErrorHandler responding to the request for a file's | 527 * Called by the ExtensionErrorHandler responding to the request for a file's |
497 * source. Populate the content area of the overlay and display the overlay. | 528 * source. Populate the content area of the overlay and display the overlay. |
498 * @param {Object?} result An object with four strings - the title, | 529 * @param {?ExtensionHighlight} result The three 'highlight' strings represent |
499 * beforeHighlight, afterHighlight, and highlight. The three 'highlight' | 530 * three portions of the file's content to display - the portion which is |
500 * strings represent three portions of the file's content to display - the | 531 * most relevant and should be emphasized (highlight), and the parts both |
501 * portion which is most relevant and should be emphasized (highlight), | 532 * before and after this portion. These may be empty. |
502 * and the parts both before and after this portion. These may be empty. | |
503 */ | 533 */ |
504 ExtensionErrorOverlay.requestFileSourceResponse = function(result) { | 534 ExtensionErrorOverlay.requestFileSourceResponse = function(result) { |
505 var overlay = extensions.ExtensionErrorOverlay.getInstance(); | 535 var overlay = extensions.ExtensionErrorOverlay.getInstance(); |
506 overlay.setCode(result); | 536 overlay.setCode(result); |
507 overlay.setVisible(true); | 537 overlay.setVisible(true); |
508 }; | 538 }; |
509 | 539 |
510 // Export | 540 // Export |
511 return { | 541 return { |
512 ExtensionErrorOverlay: ExtensionErrorOverlay | 542 ExtensionErrorOverlay: ExtensionErrorOverlay |
513 }; | 543 }; |
514 }); | 544 }); |
OLD | NEW |