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

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js

Issue 2466123002: DevTools: reformat front-end code to match chromium style. (Closed)
Patch Set: all done Created 4 years, 1 month 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 /* 1 /*
2 * Copyright (C) 2011 Google Inc. All rights reserved. 2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer 11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the 12 * in the documentation and/or other materials provided with the
13 * distribution. 13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its 14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from 15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission. 16 * this software without specific prior written permission.
17 * 17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30
31 /** 30 /**
32 * @constructor 31 * @unrestricted
33 * @extends {WebInspector.UISourceCodeFrame}
34 * @param {!WebInspector.UISourceCode} uiSourceCode
35 */ 32 */
36 WebInspector.JavaScriptSourceFrame = function(uiSourceCode) 33 WebInspector.JavaScriptSourceFrame = class extends WebInspector.UISourceCodeFram e {
37 { 34 /**
38 WebInspector.UISourceCodeFrame.call(this, uiSourceCode); 35 * @param {!WebInspector.UISourceCode} uiSourceCode
36 */
37 constructor(uiSourceCode) {
38 super(uiSourceCode);
39 39
40 this._scriptsPanel = WebInspector.SourcesPanel.instance(); 40 this._scriptsPanel = WebInspector.SourcesPanel.instance();
41 this._breakpointManager = WebInspector.breakpointManager; 41 this._breakpointManager = WebInspector.breakpointManager;
42 if (uiSourceCode.project().type() === WebInspector.projectTypes.Debugger) 42 if (uiSourceCode.project().type() === WebInspector.projectTypes.Debugger)
43 this.element.classList.add("source-frame-debugger-script"); 43 this.element.classList.add('source-frame-debugger-script');
44 44
45 this._popoverHelper = new WebInspector.ObjectPopoverHelper(this._scriptsPane l.element, 45 this._popoverHelper = new WebInspector.ObjectPopoverHelper(
46 this._getPopoverAnchor.bind(this), this._resolveObjectForPopover.bind(th is), this._onHidePopover.bind(this), true); 46 this._scriptsPanel.element, this._getPopoverAnchor.bind(this), this._res olveObjectForPopover.bind(this),
47 this._onHidePopover.bind(this), true);
47 this._popoverHelper.setTimeout(250, 250); 48 this._popoverHelper.setTimeout(250, 250);
48 49
49 this.textEditor.element.addEventListener("keydown", this._onKeyDown.bind(thi s), true); 50 this.textEditor.element.addEventListener('keydown', this._onKeyDown.bind(thi s), true);
50 51
51 this.textEditor.addEventListener(WebInspector.SourcesTextEditor.Events.Gutte rClick, this._handleGutterClick.bind(this), this); 52 this.textEditor.addEventListener(
52 53 WebInspector.SourcesTextEditor.Events.GutterClick, this._handleGutterCli ck.bind(this), this);
53 this._breakpointManager.addEventListener(WebInspector.BreakpointManager.Even ts.BreakpointAdded, this._breakpointAdded, this); 54
54 this._breakpointManager.addEventListener(WebInspector.BreakpointManager.Even ts.BreakpointRemoved, this._breakpointRemoved, this); 55 this._breakpointManager.addEventListener(
55 56 WebInspector.BreakpointManager.Events.BreakpointAdded, this._breakpointA dded, this);
56 this.uiSourceCode().addEventListener(WebInspector.UISourceCode.Events.Source MappingChanged, this._onSourceMappingChanged, this); 57 this._breakpointManager.addEventListener(
57 this.uiSourceCode().addEventListener(WebInspector.UISourceCode.Events.Workin gCopyChanged, this._workingCopyChanged, this); 58 WebInspector.BreakpointManager.Events.BreakpointRemoved, this._breakpoin tRemoved, this);
58 this.uiSourceCode().addEventListener(WebInspector.UISourceCode.Events.Workin gCopyCommitted, this._workingCopyCommitted, this); 59
59 this.uiSourceCode().addEventListener(WebInspector.UISourceCode.Events.TitleC hanged, this._showBlackboxInfobarIfNeeded, this); 60 this.uiSourceCode().addEventListener(
61 WebInspector.UISourceCode.Events.SourceMappingChanged, this._onSourceMap pingChanged, this);
62 this.uiSourceCode().addEventListener(
63 WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyCh anged, this);
64 this.uiSourceCode().addEventListener(
65 WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._workingCopy Committed, this);
66 this.uiSourceCode().addEventListener(
67 WebInspector.UISourceCode.Events.TitleChanged, this._showBlackboxInfobar IfNeeded, this);
60 68
61 /** @type {!Map.<!WebInspector.Target, !WebInspector.ResourceScriptFile>}*/ 69 /** @type {!Map.<!WebInspector.Target, !WebInspector.ResourceScriptFile>}*/
62 this._scriptFileForTarget = new Map(); 70 this._scriptFileForTarget = new Map();
63 var targets = WebInspector.targetManager.targets(); 71 var targets = WebInspector.targetManager.targets();
64 for (var i = 0; i < targets.length; ++i) { 72 for (var i = 0; i < targets.length; ++i) {
65 var scriptFile = WebInspector.debuggerWorkspaceBinding.scriptFile(uiSour ceCode, targets[i]); 73 var scriptFile = WebInspector.debuggerWorkspaceBinding.scriptFile(uiSource Code, targets[i]);
66 if (scriptFile) 74 if (scriptFile)
67 this._updateScriptFile(targets[i]); 75 this._updateScriptFile(targets[i]);
68 } 76 }
69 77
70 if (this._scriptFileForTarget.size || uiSourceCode.extension() === "js" || u iSourceCode.project().type() === WebInspector.projectTypes.Snippets) 78 if (this._scriptFileForTarget.size || uiSourceCode.extension() === 'js' ||
71 this._compiler = new WebInspector.JavaScriptCompiler(this); 79 uiSourceCode.project().type() === WebInspector.projectTypes.Snippets)
72 80 this._compiler = new WebInspector.JavaScriptCompiler(this);
73 WebInspector.moduleSetting("skipStackFramesPattern").addChangeListener(this. _showBlackboxInfobarIfNeeded, this); 81
74 WebInspector.moduleSetting("skipContentScripts").addChangeListener(this._sho wBlackboxInfobarIfNeeded, this); 82 WebInspector.moduleSetting('skipStackFramesPattern').addChangeListener(this. _showBlackboxInfobarIfNeeded, this);
83 WebInspector.moduleSetting('skipContentScripts').addChangeListener(this._sho wBlackboxInfobarIfNeeded, this);
75 this._showBlackboxInfobarIfNeeded(); 84 this._showBlackboxInfobarIfNeeded();
76 /** @type {!Map.<number, !Element>} */ 85 /** @type {!Map.<number, !Element>} */
77 this._valueWidgets = new Map(); 86 this._valueWidgets = new Map();
78 }; 87 }
79 88
80 WebInspector.JavaScriptSourceFrame.prototype = { 89 /**
90 * @override
91 * @return {!Array<!WebInspector.ToolbarItem>}
92 */
93 syncToolbarItems() {
94 var result = super.syncToolbarItems();
95 var originURL = WebInspector.CompilerScriptMapping.uiSourceCodeOrigin(this.u iSourceCode());
96 if (originURL) {
97 var parsedURL = originURL.asParsedURL();
98 if (parsedURL)
99 result.push(
100 new WebInspector.ToolbarText(WebInspector.UIString('(source mapped f rom %s)', parsedURL.displayName)));
101 }
102 return result;
103 }
104
105 _updateInfobars() {
106 this.attachInfobars([this._blackboxInfobar, this._divergedInfobar]);
107 }
108
109 _showDivergedInfobar() {
110 if (!this.uiSourceCode().contentType().isScript())
111 return;
112
113 if (this._divergedInfobar)
114 this._divergedInfobar.dispose();
115
116 var infobar = new WebInspector.Infobar(
117 WebInspector.Infobar.Type.Warning, WebInspector.UIString('Workspace mapp ing mismatch'));
118 this._divergedInfobar = infobar;
119
120 var fileURL = this.uiSourceCode().url();
121 infobar.createDetailsRowMessage(WebInspector.UIString('The content of this f ile on the file system:\u00a0'))
122 .appendChild(WebInspector.linkifyURLAsNode(fileURL, fileURL, 'source-fra me-infobar-details-url', true));
123
124 var scriptURL = this.uiSourceCode().url();
125 infobar.createDetailsRowMessage(WebInspector.UIString('does not match the lo aded script:\u00a0'))
126 .appendChild(WebInspector.linkifyURLAsNode(scriptURL, scriptURL, 'source -frame-infobar-details-url', true));
127
128 infobar.createDetailsRowMessage();
129 infobar.createDetailsRowMessage(WebInspector.UIString('Possible solutions ar e:'));
130
131 if (WebInspector.moduleSetting('cacheDisabled').get())
132 infobar.createDetailsRowMessage(' - ').createTextChild(WebInspector.UIStri ng('Reload inspected page'));
133 else
134 infobar.createDetailsRowMessage(' - ').createTextChild(WebInspector.UIStri ng(
135 'Check "Disable cache" in settings and reload inspected page (recommen ded setup for authoring and debugging)'));
136 infobar.createDetailsRowMessage(' - ').createTextChild(WebInspector.UIString (
137 'Check that your file and script are both loaded from the correct source and their contents match'));
138
139 this._updateInfobars();
140 }
141
142 _hideDivergedInfobar() {
143 if (!this._divergedInfobar)
144 return;
145 this._divergedInfobar.dispose();
146 delete this._divergedInfobar;
147 }
148
149 _showBlackboxInfobarIfNeeded() {
150 var uiSourceCode = this.uiSourceCode();
151 if (!uiSourceCode.contentType().hasScripts())
152 return;
153 var projectType = uiSourceCode.project().type();
154 if (projectType === WebInspector.projectTypes.Snippets)
155 return;
156 if (!WebInspector.blackboxManager.isBlackboxedUISourceCode(uiSourceCode)) {
157 this._hideBlackboxInfobar();
158 return;
159 }
160
161 if (this._blackboxInfobar)
162 this._blackboxInfobar.dispose();
163
164 var infobar = new WebInspector.Infobar(
165 WebInspector.Infobar.Type.Warning, WebInspector.UIString('This script is blackboxed in debugger'));
166 this._blackboxInfobar = infobar;
167
168 infobar.createDetailsRowMessage(
169 WebInspector.UIString('Debugger will skip stepping through this script, and will not stop on exceptions'));
170
171 var scriptFile = this._scriptFileForTarget.size ? this._scriptFileForTarget. valuesArray()[0] : null;
172 if (scriptFile && scriptFile.hasSourceMapURL())
173 infobar.createDetailsRowMessage(WebInspector.UIString('Source map found, b ut ignored for blackboxed file.'));
174 infobar.createDetailsRowMessage();
175 infobar.createDetailsRowMessage(WebInspector.UIString('Possible ways to canc el this behavior are:'));
176
177 infobar.createDetailsRowMessage(' - ').createTextChild(
178 WebInspector.UIString('Go to "%s" tab in settings', WebInspector.UIStrin g('Blackboxing')));
179 var unblackboxLink = infobar.createDetailsRowMessage(' - ').createChild('spa n', 'link');
180 unblackboxLink.textContent = WebInspector.UIString('Unblackbox this script') ;
181 unblackboxLink.addEventListener('click', unblackbox, false);
182
183 function unblackbox() {
184 WebInspector.blackboxManager.unblackboxUISourceCode(uiSourceCode);
185 if (projectType === WebInspector.projectTypes.ContentScripts)
186 WebInspector.blackboxManager.unblackboxContentScripts();
187 }
188
189 this._updateInfobars();
190 }
191
192 _hideBlackboxInfobar() {
193 if (!this._blackboxInfobar)
194 return;
195 this._blackboxInfobar.dispose();
196 delete this._blackboxInfobar;
197 }
198
199 /**
200 * @override
201 */
202 wasShown() {
203 super.wasShown();
204 if (this._executionLocation && this.loaded) {
205 // We need SourcesTextEditor to be initialized prior to this call. @see cr bug.com/499889
206 setImmediate(this._generateValuesInSource.bind(this));
207 }
208 }
209
210 /**
211 * @override
212 */
213 willHide() {
214 super.willHide();
215 this._popoverHelper.hidePopover();
216 }
217
218 /**
219 * @override
220 */
221 onUISourceCodeContentChanged() {
222 this._removeAllBreakpoints();
223 super.onUISourceCodeContentChanged();
224 }
225
226 /**
227 * @override
228 */
229 onTextChanged(oldRange, newRange) {
230 this._scriptsPanel.updateLastModificationTime();
231 super.onTextChanged(oldRange, newRange);
232 if (this._compiler)
233 this._compiler.scheduleCompile();
234 }
235
236 /**
237 * @override
238 * @return {!Promise}
239 */
240 populateLineGutterContextMenu(contextMenu, lineNumber) {
81 /** 241 /**
82 * @override 242 * @this {WebInspector.JavaScriptSourceFrame}
83 * @return {!Array<!WebInspector.ToolbarItem>}
84 */ 243 */
85 syncToolbarItems: function() 244 function populate(resolve, reject) {
86 { 245 var uiLocation = new WebInspector.UILocation(this.uiSourceCode(), lineNumb er, 0);
87 var result = WebInspector.UISourceCodeFrame.prototype.syncToolbarItems.c all(this); 246 this._scriptsPanel.appendUILocationItems(contextMenu, uiLocation);
88 var originURL = WebInspector.CompilerScriptMapping.uiSourceCodeOrigin(th is.uiSourceCode()); 247 var breakpoint = this._breakpointManager.findBreakpointOnLine(this.uiSourc eCode(), lineNumber);
89 if (originURL) { 248 if (!breakpoint) {
90 var parsedURL = originURL.asParsedURL(); 249 // This row doesn't have a breakpoint: We want to show Add Breakpoint an d Add and Edit Breakpoint.
91 if (parsedURL) 250 contextMenu.appendItem(
92 result.push(new WebInspector.ToolbarText(WebInspector.UIString(" (source mapped from %s)", parsedURL.displayName))); 251 WebInspector.UIString('Add breakpoint'), this._createNewBreakpoint.b ind(this, lineNumber, 0, '', true));
252 contextMenu.appendItem(
253 WebInspector.UIString('Add conditional breakpoint…'), this._editBrea kpointCondition.bind(this, lineNumber));
254 contextMenu.appendItem(
255 WebInspector.UIString('Never pause here'),
256 this._createNewBreakpoint.bind(this, lineNumber, 0, 'false', true));
257 } else {
258 // This row has a breakpoint, we want to show edit and remove breakpoint , and either disable or enable.
259 contextMenu.appendItem(WebInspector.UIString('Remove breakpoint'), break point.remove.bind(breakpoint));
260 contextMenu.appendItem(
261 WebInspector.UIString('Edit breakpoint…'),
262 this._editBreakpointCondition.bind(this, lineNumber, breakpoint));
263 if (breakpoint.enabled())
264 contextMenu.appendItem(
265 WebInspector.UIString('Disable breakpoint'), breakpoint.setEnabled .bind(breakpoint, false));
266 else
267 contextMenu.appendItem(
268 WebInspector.UIString('Enable breakpoint'), breakpoint.setEnabled. bind(breakpoint, true));
269 }
270 resolve();
271 }
272 return new Promise(populate.bind(this));
273 }
274
275 /**
276 * @override
277 * @return {!Promise}
278 */
279 populateTextAreaContextMenu(contextMenu, lineNumber, columnNumber) {
280 /**
281 * @param {!WebInspector.ResourceScriptFile} scriptFile
282 */
283 function addSourceMapURL(scriptFile) {
284 WebInspector.AddSourceMapURLDialog.show(addSourceMapURLDialogCallback.bind (null, scriptFile));
285 }
286
287 /**
288 * @param {!WebInspector.ResourceScriptFile} scriptFile
289 * @param {string} url
290 */
291 function addSourceMapURLDialogCallback(scriptFile, url) {
292 if (!url)
293 return;
294 scriptFile.addSourceMapURL(url);
295 }
296
297 /**
298 * @this {WebInspector.JavaScriptSourceFrame}
299 */
300 function populateSourceMapMembers() {
301 if (this.uiSourceCode().project().type() === WebInspector.projectTypes.Net work &&
302 WebInspector.moduleSetting('jsSourceMapsEnabled').get() &&
303 !WebInspector.blackboxManager.isBlackboxedUISourceCode(this.uiSourceCo de())) {
304 if (this._scriptFileForTarget.size) {
305 var scriptFile = this._scriptFileForTarget.valuesArray()[0];
306 var addSourceMapURLLabel = WebInspector.UIString.capitalize('Add ^sour ce ^map\u2026');
307 contextMenu.appendItem(addSourceMapURLLabel, addSourceMapURL.bind(null , scriptFile));
308 contextMenu.appendSeparator();
93 } 309 }
94 return result; 310 }
95 }, 311 }
96 312
97 _updateInfobars: function() 313 return super.populateTextAreaContextMenu(contextMenu, lineNumber, columnNumb er)
98 { 314 .then(populateSourceMapMembers.bind(this));
99 this.attachInfobars([this._blackboxInfobar, this._divergedInfobar]); 315 }
100 }, 316
101 317 _workingCopyChanged(event) {
102 _showDivergedInfobar: function() 318 if (this._supportsEnabledBreakpointsWhileEditing() || this._scriptFileForTar get.size)
103 { 319 return;
104 if (!this.uiSourceCode().contentType().isScript()) 320
105 return; 321 if (this.uiSourceCode().isDirty())
106 322 this._muteBreakpointsWhileEditing();
107 if (this._divergedInfobar) 323 else
108 this._divergedInfobar.dispose(); 324 this._restoreBreakpointsAfterEditing();
109 325 }
110 var infobar = new WebInspector.Infobar(WebInspector.Infobar.Type.Warning , WebInspector.UIString("Workspace mapping mismatch")); 326
111 this._divergedInfobar = infobar; 327 _workingCopyCommitted(event) {
112 328 this._scriptsPanel.updateLastModificationTime();
113 var fileURL = this.uiSourceCode().url(); 329 if (this._supportsEnabledBreakpointsWhileEditing())
114 infobar.createDetailsRowMessage(WebInspector.UIString("The content of th is file on the file system:\u00a0")).appendChild( 330 return;
115 WebInspector.linkifyURLAsNode(fileURL, fileURL, "source-frame-infoba r-details-url", true)); 331
116 332 if (!this._scriptFileForTarget.size)
117 var scriptURL = this.uiSourceCode().url(); 333 this._restoreBreakpointsAfterEditing();
118 infobar.createDetailsRowMessage(WebInspector.UIString("does not match th e loaded script:\u00a0")).appendChild( 334 }
119 WebInspector.linkifyURLAsNode(scriptURL, scriptURL, "source-frame-in fobar-details-url", true)); 335
120 336 _didMergeToVM() {
121 infobar.createDetailsRowMessage(); 337 if (this._supportsEnabledBreakpointsWhileEditing())
122 infobar.createDetailsRowMessage(WebInspector.UIString("Possible solution s are:")); 338 return;
123 339 this._updateDivergedInfobar();
124 if (WebInspector.moduleSetting("cacheDisabled").get()) 340 this._restoreBreakpointsIfConsistentScripts();
125 infobar.createDetailsRowMessage(" - ").createTextChild(WebInspector. UIString("Reload inspected page")); 341 }
126 else 342
127 infobar.createDetailsRowMessage(" - ").createTextChild(WebInspector. UIString("Check \"Disable cache\" in settings and reload inspected page (recomme nded setup for authoring and debugging)")); 343 _didDivergeFromVM() {
128 infobar.createDetailsRowMessage(" - ").createTextChild(WebInspector.UISt ring("Check that your file and script are both loaded from the correct source an d their contents match")); 344 if (this._supportsEnabledBreakpointsWhileEditing())
129 345 return;
130 this._updateInfobars(); 346 this._updateDivergedInfobar();
131 }, 347 this._muteBreakpointsWhileEditing();
132 348 }
133 _hideDivergedInfobar: function() 349
134 { 350 _muteBreakpointsWhileEditing() {
135 if (!this._divergedInfobar) 351 if (this._muted)
136 return; 352 return;
137 this._divergedInfobar.dispose(); 353 for (var lineNumber = 0; lineNumber < this._textEditor.linesCount; ++lineNum ber) {
138 delete this._divergedInfobar; 354 var breakpointDecoration = this._textEditor.getAttribute(lineNumber, 'brea kpoint');
139 }, 355 if (!breakpointDecoration)
140 356 continue;
141 _showBlackboxInfobarIfNeeded: function() 357 this._removeBreakpointDecoration(lineNumber);
142 { 358 this._addBreakpointDecoration(
143 var uiSourceCode = this.uiSourceCode(); 359 lineNumber, breakpointDecoration.columnNumber, breakpointDecoration.co ndition, breakpointDecoration.enabled,
144 if (!uiSourceCode.contentType().hasScripts()) 360 true);
145 return; 361 }
146 var projectType = uiSourceCode.project().type(); 362 this._muted = true;
147 if (projectType === WebInspector.projectTypes.Snippets) 363 }
148 return; 364
149 if (!WebInspector.blackboxManager.isBlackboxedUISourceCode(uiSourceCode) ) { 365 _updateDivergedInfobar() {
150 this._hideBlackboxInfobar(); 366 if (this.uiSourceCode().project().type() !== WebInspector.projectTypes.FileS ystem) {
151 return; 367 this._hideDivergedInfobar();
368 return;
369 }
370
371 var scriptFiles = this._scriptFileForTarget.valuesArray();
372 var hasDivergedScript = false;
373 for (var i = 0; i < scriptFiles.length; ++i)
374 hasDivergedScript = hasDivergedScript || scriptFiles[i].hasDivergedFromVM( );
375
376 if (this._divergedInfobar) {
377 if (!hasDivergedScript)
378 this._hideDivergedInfobar();
379 } else {
380 if (hasDivergedScript && !this.uiSourceCode().isDirty())
381 this._showDivergedInfobar();
382 }
383 }
384
385 _supportsEnabledBreakpointsWhileEditing() {
386 return this.uiSourceCode().project().type() === WebInspector.projectTypes.Sn ippets;
387 }
388
389 _restoreBreakpointsIfConsistentScripts() {
390 var scriptFiles = this._scriptFileForTarget.valuesArray();
391 for (var i = 0; i < scriptFiles.length; ++i)
392 if (scriptFiles[i].hasDivergedFromVM() || scriptFiles[i].isMergingToVM())
393 return;
394
395 this._restoreBreakpointsAfterEditing();
396 }
397
398 _restoreBreakpointsAfterEditing() {
399 delete this._muted;
400 var breakpoints = {};
401 // Save and remove muted breakpoint decorations.
402 for (var lineNumber = 0; lineNumber < this._textEditor.linesCount; ++lineNum ber) {
403 var breakpointDecoration = this._textEditor.getAttribute(lineNumber, 'brea kpoint');
404 if (breakpointDecoration) {
405 breakpoints[lineNumber] = breakpointDecoration;
406 this._removeBreakpointDecoration(lineNumber);
407 }
408 }
409
410 // Remove all breakpoints.
411 this._removeAllBreakpoints();
412
413 // Restore all breakpoints from saved decorations.
414 for (var lineNumberString in breakpoints) {
415 var lineNumber = parseInt(lineNumberString, 10);
416 if (isNaN(lineNumber))
417 continue;
418 var breakpointDecoration = breakpoints[lineNumberString];
419 this._setBreakpoint(
420 lineNumber, breakpointDecoration.columnNumber, breakpointDecoration.co ndition, breakpointDecoration.enabled);
421 }
422 }
423
424 _removeAllBreakpoints() {
425 var breakpoints = this._breakpointManager.breakpointsForUISourceCode(this.ui SourceCode());
426 for (var i = 0; i < breakpoints.length; ++i)
427 breakpoints[i].remove();
428 }
429
430 /**
431 * @param {string} tokenType
432 * @return {boolean}
433 */
434 _isIdentifier(tokenType) {
435 return tokenType.startsWith('js-variable') || tokenType.startsWith('js-prope rty') || tokenType === 'js-def';
436 }
437
438 _getPopoverAnchor(element, event) {
439 var target = WebInspector.context.flavor(WebInspector.Target);
440 var debuggerModel = WebInspector.DebuggerModel.fromTarget(target);
441 if (!debuggerModel || !debuggerModel.isPaused())
442 return;
443
444 var textPosition = this.textEditor.coordinatesToCursorPosition(event.x, even t.y);
445 if (!textPosition)
446 return;
447 var mouseLine = textPosition.startLine;
448 var mouseColumn = textPosition.startColumn;
449 var textSelection = this.textEditor.selection().normalize();
450 if (textSelection && !textSelection.isEmpty()) {
451 if (textSelection.startLine !== textSelection.endLine || textSelection.sta rtLine !== mouseLine ||
452 mouseColumn < textSelection.startColumn || mouseColumn > textSelection .endColumn)
453 return;
454
455 var leftCorner = this.textEditor.cursorPositionToCoordinates(textSelection .startLine, textSelection.startColumn);
456 var rightCorner = this.textEditor.cursorPositionToCoordinates(textSelectio n.endLine, textSelection.endColumn);
457 var anchorBox = new AnchorBox(leftCorner.x, leftCorner.y, rightCorner.x - leftCorner.x, leftCorner.height);
458 anchorBox.highlight = {
459 lineNumber: textSelection.startLine,
460 startColumn: textSelection.startColumn,
461 endColumn: textSelection.endColumn - 1
462 };
463 anchorBox.forSelection = true;
464 return anchorBox;
465 }
466
467 var token = this.textEditor.tokenAtTextPosition(textPosition.startLine, text Position.startColumn);
468 if (!token || !token.type)
469 return;
470 var lineNumber = textPosition.startLine;
471 var line = this.textEditor.line(lineNumber);
472 var tokenContent = line.substring(token.startColumn, token.endColumn);
473
474 var isIdentifier = this._isIdentifier(token.type);
475 if (!isIdentifier && (token.type !== 'js-keyword' || tokenContent !== 'this' ))
476 return;
477
478 var leftCorner = this.textEditor.cursorPositionToCoordinates(lineNumber, tok en.startColumn);
479 var rightCorner = this.textEditor.cursorPositionToCoordinates(lineNumber, to ken.endColumn - 1);
480 var anchorBox = new AnchorBox(leftCorner.x, leftCorner.y, rightCorner.x - le ftCorner.x, leftCorner.height);
481
482 anchorBox.highlight = {lineNumber: lineNumber, startColumn: token.startColum n, endColumn: token.endColumn - 1};
483
484 return anchorBox;
485 }
486
487 _resolveObjectForPopover(anchorBox, showCallback, objectGroupName) {
488 var target = WebInspector.context.flavor(WebInspector.Target);
489 var selectedCallFrame = WebInspector.context.flavor(WebInspector.DebuggerMod el.CallFrame);
490 if (!selectedCallFrame) {
491 this._popoverHelper.hidePopover();
492 return;
493 }
494 var lineNumber = anchorBox.highlight.lineNumber;
495 var startHighlight = anchorBox.highlight.startColumn;
496 var endHighlight = anchorBox.highlight.endColumn;
497 var line = this.textEditor.line(lineNumber);
498 if (!anchorBox.forSelection) {
499 while (startHighlight > 1 && line.charAt(startHighlight - 1) === '.') {
500 var token = this.textEditor.tokenAtTextPosition(lineNumber, startHighlig ht - 2);
501 if (!token || !token.type) {
502 this._popoverHelper.hidePopover();
503 return;
152 } 504 }
153 505 startHighlight = token.startColumn;
154 if (this._blackboxInfobar) 506 }
155 this._blackboxInfobar.dispose(); 507 }
156 508 var evaluationText = line.substring(startHighlight, endHighlight + 1);
157 var infobar = new WebInspector.Infobar(WebInspector.Infobar.Type.Warning , WebInspector.UIString("This script is blackboxed in debugger")); 509 WebInspector.SourceMapNamesResolver
158 this._blackboxInfobar = infobar; 510 .resolveExpression(
159 511 selectedCallFrame, evaluationText, this.uiSourceCode(), lineNumber, startHighlight, endHighlight)
160 infobar.createDetailsRowMessage(WebInspector.UIString("Debugger will ski p stepping through this script, and will not stop on exceptions")); 512 .then(onResolve.bind(this));
161
162 var scriptFile = this._scriptFileForTarget.size ? this._scriptFileForTar get.valuesArray()[0] : null;
163 if (scriptFile && scriptFile.hasSourceMapURL())
164 infobar.createDetailsRowMessage(WebInspector.UIString("Source map fo und, but ignored for blackboxed file."));
165 infobar.createDetailsRowMessage();
166 infobar.createDetailsRowMessage(WebInspector.UIString("Possible ways to cancel this behavior are:"));
167
168 infobar.createDetailsRowMessage(" - ").createTextChild(WebInspector.UISt ring("Go to \"%s\" tab in settings", WebInspector.UIString("Blackboxing")));
169 var unblackboxLink = infobar.createDetailsRowMessage(" - ").createChild( "span", "link");
170 unblackboxLink.textContent = WebInspector.UIString("Unblackbox this scri pt");
171 unblackboxLink.addEventListener("click", unblackbox, false);
172
173 function unblackbox()
174 {
175 WebInspector.blackboxManager.unblackboxUISourceCode(uiSourceCode);
176 if (projectType === WebInspector.projectTypes.ContentScripts)
177 WebInspector.blackboxManager.unblackboxContentScripts();
178 }
179
180 this._updateInfobars();
181 },
182
183 _hideBlackboxInfobar: function()
184 {
185 if (!this._blackboxInfobar)
186 return;
187 this._blackboxInfobar.dispose();
188 delete this._blackboxInfobar;
189 },
190 513
191 /** 514 /**
192 * @override 515 * @param {?string=} text
516 * @this {WebInspector.JavaScriptSourceFrame}
193 */ 517 */
194 wasShown: function() 518 function onResolve(text) {
195 { 519 selectedCallFrame.evaluate(
196 WebInspector.UISourceCodeFrame.prototype.wasShown.call(this); 520 text || evaluationText, objectGroupName, false, true, false, false, sh owObjectPopover.bind(this));
197 if (this._executionLocation && this.loaded) { 521 }
198 // We need SourcesTextEditor to be initialized prior to this call. @ see crbug.com/499889
199 setImmediate(this._generateValuesInSource.bind(this));
200 }
201 },
202 522
203 /** 523 /**
204 * @override 524 * @param {?RuntimeAgent.RemoteObject} result
525 * @param {!RuntimeAgent.ExceptionDetails=} exceptionDetails
526 * @this {WebInspector.JavaScriptSourceFrame}
205 */ 527 */
206 willHide: function() 528 function showObjectPopover(result, exceptionDetails) {
207 { 529 var target = WebInspector.context.flavor(WebInspector.Target);
208 WebInspector.UISourceCodeFrame.prototype.willHide.call(this); 530 var potentiallyUpdatedCallFrame = WebInspector.context.flavor(WebInspector .DebuggerModel.CallFrame);
531 if (selectedCallFrame !== potentiallyUpdatedCallFrame || !result) {
209 this._popoverHelper.hidePopover(); 532 this._popoverHelper.hidePopover();
210 }, 533 return;
211 534 }
212 onUISourceCodeContentChanged: function() 535 this._popoverAnchorBox = anchorBox;
213 { 536 showCallback(target.runtimeModel.createRemoteObject(result), !!exceptionDe tails, this._popoverAnchorBox);
214 this._removeAllBreakpoints(); 537 // Popover may have been removed by showCallback().
215 WebInspector.UISourceCodeFrame.prototype.onUISourceCodeContentChanged.ca ll(this); 538 if (this._popoverAnchorBox) {
216 }, 539 var highlightRange = new WebInspector.TextRange(lineNumber, startHighlig ht, lineNumber, endHighlight);
540 this._popoverAnchorBox._highlightDescriptor =
541 this.textEditor.highlightRange(highlightRange, 'source-frame-eval-ex pression');
542 }
543 }
544 }
545
546 _onHidePopover() {
547 if (!this._popoverAnchorBox)
548 return;
549 if (this._popoverAnchorBox._highlightDescriptor)
550 this.textEditor.removeHighlight(this._popoverAnchorBox._highlightDescripto r);
551 delete this._popoverAnchorBox;
552 }
553
554 /**
555 * @param {number} lineNumber
556 * @param {number} columnNumber
557 * @param {string} condition
558 * @param {boolean} enabled
559 * @param {boolean} mutedWhileEditing
560 */
561 _addBreakpointDecoration(lineNumber, columnNumber, condition, enabled, mutedWh ileEditing) {
562 var breakpoint = {condition: condition, enabled: enabled, columnNumber: colu mnNumber};
563
564 this.textEditor.setAttribute(lineNumber, 'breakpoint', breakpoint);
565
566 var disabled = !enabled || mutedWhileEditing;
567 this.textEditor.addBreakpoint(lineNumber, disabled, !!condition);
568 }
569
570 _removeBreakpointDecoration(lineNumber) {
571 this.textEditor.removeAttribute(lineNumber, 'breakpoint');
572 this.textEditor.removeBreakpoint(lineNumber);
573 }
574
575 _onKeyDown(event) {
576 if (event.key === 'Escape') {
577 if (this._popoverHelper.isPopoverVisible()) {
578 this._popoverHelper.hidePopover();
579 event.consume();
580 }
581 }
582 }
583
584 /**
585 * @param {number} lineNumber
586 * @param {!WebInspector.BreakpointManager.Breakpoint=} breakpoint
587 */
588 _editBreakpointCondition(lineNumber, breakpoint) {
589 this._conditionElement = this._createConditionElement(lineNumber);
590 this.textEditor.addDecoration(this._conditionElement, lineNumber);
217 591
218 /** 592 /**
219 * @override 593 * @this {WebInspector.JavaScriptSourceFrame}
220 */ 594 */
221 onTextChanged: function(oldRange, newRange) 595 function finishEditing(committed, element, newText) {
222 { 596 this.textEditor.removeDecoration(this._conditionElement, lineNumber);
223 this._scriptsPanel.updateLastModificationTime(); 597 delete this._conditionEditorElement;
224 WebInspector.UISourceCodeFrame.prototype.onTextChanged.call(this, oldRan ge, newRange); 598 delete this._conditionElement;
225 if (this._compiler) 599 if (!committed)
226 this._compiler.scheduleCompile(); 600 return;
227 }, 601
228 602 if (breakpoint)
229 /** 603 breakpoint.setCondition(newText);
230 * @override 604 else
231 * @return {!Promise} 605 this._createNewBreakpoint(lineNumber, 0, newText, true);
232 */ 606 }
233 populateLineGutterContextMenu: function(contextMenu, lineNumber) 607
234 { 608 var config = new WebInspector.InplaceEditor.Config(finishEditing.bind(this, true), finishEditing.bind(this, false));
235 /** 609 WebInspector.InplaceEditor.startEditing(this._conditionEditorElement, config );
236 * @this {WebInspector.JavaScriptSourceFrame} 610 this._conditionEditorElement.value = breakpoint ? breakpoint.condition() : ' ';
237 */ 611 this._conditionEditorElement.select();
238 function populate(resolve, reject) 612 }
239 { 613
240 var uiLocation = new WebInspector.UILocation(this.uiSourceCode(), li neNumber, 0); 614 _createConditionElement(lineNumber) {
241 this._scriptsPanel.appendUILocationItems(contextMenu, uiLocation); 615 var conditionElement = createElementWithClass('div', 'source-frame-breakpoin t-condition');
242 var breakpoint = this._breakpointManager.findBreakpointOnLine(this.u iSourceCode(), lineNumber); 616
243 if (!breakpoint) { 617 var labelElement = conditionElement.createChild('label', 'source-frame-break point-message');
244 // This row doesn't have a breakpoint: We want to show Add Break point and Add and Edit Breakpoint. 618 labelElement.htmlFor = 'source-frame-breakpoint-condition';
245 contextMenu.appendItem(WebInspector.UIString("Add breakpoint"), this._createNewBreakpoint.bind(this, lineNumber, 0, "", true)); 619 labelElement.createTextChild(
246 contextMenu.appendItem(WebInspector.UIString("Add conditional br eakpoint…"), this._editBreakpointCondition.bind(this, lineNumber)); 620 WebInspector.UIString('The breakpoint on line %d will stop only if this expression is true:', lineNumber + 1));
247 contextMenu.appendItem(WebInspector.UIString("Never pause here") , this._createNewBreakpoint.bind(this, lineNumber, 0, "false", true)); 621
248 } else { 622 var editorElement = conditionElement.createChild('input', 'monospace');
249 // This row has a breakpoint, we want to show edit and remove br eakpoint, and either disable or enable. 623 editorElement.id = 'source-frame-breakpoint-condition';
250 contextMenu.appendItem(WebInspector.UIString("Remove breakpoint" ), breakpoint.remove.bind(breakpoint)); 624 editorElement.type = 'text';
251 contextMenu.appendItem(WebInspector.UIString("Edit breakpoint…") , this._editBreakpointCondition.bind(this, lineNumber, breakpoint)); 625 this._conditionEditorElement = editorElement;
252 if (breakpoint.enabled()) 626
253 contextMenu.appendItem(WebInspector.UIString("Disable breakp oint"), breakpoint.setEnabled.bind(breakpoint, false)); 627 return conditionElement;
254 else 628 }
255 contextMenu.appendItem(WebInspector.UIString("Enable breakpo int"), breakpoint.setEnabled.bind(breakpoint, true)); 629
256 } 630 /**
257 resolve(); 631 * @param {!WebInspector.UILocation} uiLocation
258 } 632 */
259 return new Promise(populate.bind(this)); 633 setExecutionLocation(uiLocation) {
260 }, 634 this._executionLocation = uiLocation;
261 635 if (!this.loaded)
262 /** 636 return;
263 * @override 637
264 * @return {!Promise} 638 this.textEditor.setExecutionLocation(uiLocation.lineNumber, uiLocation.colum nNumber);
265 */ 639 if (this.isShowing()) {
266 populateTextAreaContextMenu: function(contextMenu, lineNumber, columnNumber) 640 // We need SourcesTextEditor to be initialized prior to this call. @see cr bug.com/506566
267 { 641 setImmediate(this._generateValuesInSource.bind(this));
268 /** 642 }
269 * @param {!WebInspector.ResourceScriptFile} scriptFile 643 }
270 */ 644
271 function addSourceMapURL(scriptFile) 645 _generateValuesInSource() {
272 { 646 if (!WebInspector.moduleSetting('inlineVariableValues').get())
273 WebInspector.AddSourceMapURLDialog.show(addSourceMapURLDialogCallbac k.bind(null, scriptFile)); 647 return;
274 } 648 var executionContext = WebInspector.context.flavor(WebInspector.ExecutionCon text);
275 649 if (!executionContext)
276 /** 650 return;
277 * @param {!WebInspector.ResourceScriptFile} scriptFile 651 var callFrame = WebInspector.context.flavor(WebInspector.DebuggerModel.CallF rame);
278 * @param {string} url 652 if (!callFrame)
279 */ 653 return;
280 function addSourceMapURLDialogCallback(scriptFile, url) 654
281 { 655 var localScope = callFrame.localScope();
282 if (!url) 656 var functionLocation = callFrame.functionLocation();
283 return; 657 if (localScope && functionLocation)
284 scriptFile.addSourceMapURL(url); 658 WebInspector.SourceMapNamesResolver.resolveScopeInObject(localScope)
285 } 659 .getAllProperties(false, this._prepareScopeVariables.bind(this, callFr ame));
286 660
287 /** 661 if (this._clearValueWidgetsTimer) {
288 * @this {WebInspector.JavaScriptSourceFrame} 662 clearTimeout(this._clearValueWidgetsTimer);
289 */ 663 delete this._clearValueWidgetsTimer;
290 function populateSourceMapMembers() 664 }
291 { 665 }
292 if (this.uiSourceCode().project().type() === WebInspector.projectTyp es.Network && WebInspector.moduleSetting("jsSourceMapsEnabled").get() && !WebIns pector.blackboxManager.isBlackboxedUISourceCode(this.uiSourceCode())) { 666
293 if (this._scriptFileForTarget.size) { 667 /**
294 var scriptFile = this._scriptFileForTarget.valuesArray()[0]; 668 * @param {!WebInspector.DebuggerModel.CallFrame} callFrame
295 var addSourceMapURLLabel = WebInspector.UIString.capitalize( "Add ^source ^map\u2026"); 669 * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties
296 contextMenu.appendItem(addSourceMapURLLabel, addSourceMapURL .bind(null, scriptFile)); 670 * @param {?Array.<!WebInspector.RemoteObjectProperty>} internalProperties
297 contextMenu.appendSeparator(); 671 */
298 } 672 _prepareScopeVariables(callFrame, properties, internalProperties) {
299 } 673 if (!properties || !properties.length || properties.length > 500) {
300 } 674 this._clearValueWidgets();
301 675 return;
302 return WebInspector.UISourceCodeFrame.prototype.populateTextAreaContextM enu.call(this, contextMenu, lineNumber, columnNumber).then(populateSourceMapMemb ers.bind(this)); 676 }
303 }, 677
304 678 var functionUILocation = WebInspector.debuggerWorkspaceBinding.rawLocationTo UILocation(
305 _workingCopyChanged: function(event) 679 /** @type {!WebInspector.DebuggerModel.Location} */ (callFrame.functionL ocation()));
306 { 680 var executionUILocation = WebInspector.debuggerWorkspaceBinding.rawLocationT oUILocation(callFrame.location());
307 if (this._supportsEnabledBreakpointsWhileEditing() || this._scriptFileFo rTarget.size) 681 if (functionUILocation.uiSourceCode !== this.uiSourceCode() ||
308 return; 682 executionUILocation.uiSourceCode !== this.uiSourceCode()) {
309 683 this._clearValueWidgets();
310 if (this.uiSourceCode().isDirty()) 684 return;
311 this._muteBreakpointsWhileEditing(); 685 }
312 else 686
313 this._restoreBreakpointsAfterEditing(); 687 var fromLine = functionUILocation.lineNumber;
314 }, 688 var fromColumn = functionUILocation.columnNumber;
315 689 var toLine = executionUILocation.lineNumber;
316 _workingCopyCommitted: function(event) 690
317 { 691 // Make sure we have a chance to update all existing widgets.
318 this._scriptsPanel.updateLastModificationTime(); 692 if (this._valueWidgets) {
319 if (this._supportsEnabledBreakpointsWhileEditing()) 693 for (var line of this._valueWidgets.keys())
320 return; 694 toLine = Math.max(toLine, line + 1);
321 695 }
322 if (!this._scriptFileForTarget.size) 696 if (fromLine >= toLine || toLine - fromLine > 500 || fromLine < 0 || toLine >= this.textEditor.linesCount) {
323 this._restoreBreakpointsAfterEditing(); 697 this._clearValueWidgets();
324 }, 698 return;
325 699 }
326 _didMergeToVM: function() 700
327 { 701 var valuesMap = new Map();
328 if (this._supportsEnabledBreakpointsWhileEditing()) 702 for (var property of properties)
329 return; 703 valuesMap.set(property.name, property.value);
330 this._updateDivergedInfobar(); 704
331 this._restoreBreakpointsIfConsistentScripts(); 705 /** @type {!Map.<number, !Set<string>>} */
332 }, 706 var namesPerLine = new Map();
333 707 var skipObjectProperty = false;
334 _didDivergeFromVM: function() 708 var tokenizer = new WebInspector.CodeMirrorUtils.TokenizerFactory().createTo kenizer('text/javascript');
335 { 709 tokenizer(this.textEditor.line(fromLine).substring(fromColumn), processToken .bind(this, fromLine));
336 if (this._supportsEnabledBreakpointsWhileEditing()) 710 for (var i = fromLine + 1; i < toLine; ++i)
337 return; 711 tokenizer(this.textEditor.line(i), processToken.bind(this, i));
338 this._updateDivergedInfobar();
339 this._muteBreakpointsWhileEditing();
340 },
341
342 _muteBreakpointsWhileEditing: function()
343 {
344 if (this._muted)
345 return;
346 for (var lineNumber = 0; lineNumber < this._textEditor.linesCount; ++lin eNumber) {
347 var breakpointDecoration = this._textEditor.getAttribute(lineNumber, "breakpoint");
348 if (!breakpointDecoration)
349 continue;
350 this._removeBreakpointDecoration(lineNumber);
351 this._addBreakpointDecoration(lineNumber, breakpointDecoration.colum nNumber, breakpointDecoration.condition, breakpointDecoration.enabled, true);
352 }
353 this._muted = true;
354 },
355
356 _updateDivergedInfobar: function()
357 {
358 if (this.uiSourceCode().project().type() !== WebInspector.projectTypes.F ileSystem) {
359 this._hideDivergedInfobar();
360 return;
361 }
362
363 var scriptFiles = this._scriptFileForTarget.valuesArray();
364 var hasDivergedScript = false;
365 for (var i = 0; i < scriptFiles.length; ++i)
366 hasDivergedScript = hasDivergedScript || scriptFiles[i].hasDivergedF romVM();
367
368 if (this._divergedInfobar) {
369 if (!hasDivergedScript)
370 this._hideDivergedInfobar();
371 } else {
372 if (hasDivergedScript && !this.uiSourceCode().isDirty())
373 this._showDivergedInfobar();
374 }
375 },
376
377 _supportsEnabledBreakpointsWhileEditing: function()
378 {
379 return this.uiSourceCode().project().type() === WebInspector.projectType s.Snippets;
380 },
381
382 _restoreBreakpointsIfConsistentScripts: function()
383 {
384 var scriptFiles = this._scriptFileForTarget.valuesArray();
385 for (var i = 0; i < scriptFiles.length; ++i)
386 if (scriptFiles[i].hasDivergedFromVM() || scriptFiles[i].isMergingTo VM())
387 return;
388
389 this._restoreBreakpointsAfterEditing();
390 },
391
392 _restoreBreakpointsAfterEditing: function()
393 {
394 delete this._muted;
395 var breakpoints = {};
396 // Save and remove muted breakpoint decorations.
397 for (var lineNumber = 0; lineNumber < this._textEditor.linesCount; ++lin eNumber) {
398 var breakpointDecoration = this._textEditor.getAttribute(lineNumber, "breakpoint");
399 if (breakpointDecoration) {
400 breakpoints[lineNumber] = breakpointDecoration;
401 this._removeBreakpointDecoration(lineNumber);
402 }
403 }
404
405 // Remove all breakpoints.
406 this._removeAllBreakpoints();
407
408 // Restore all breakpoints from saved decorations.
409 for (var lineNumberString in breakpoints) {
410 var lineNumber = parseInt(lineNumberString, 10);
411 if (isNaN(lineNumber))
412 continue;
413 var breakpointDecoration = breakpoints[lineNumberString];
414 this._setBreakpoint(lineNumber, breakpointDecoration.columnNumber, b reakpointDecoration.condition, breakpointDecoration.enabled);
415 }
416 },
417
418 _removeAllBreakpoints: function()
419 {
420 var breakpoints = this._breakpointManager.breakpointsForUISourceCode(thi s.uiSourceCode());
421 for (var i = 0; i < breakpoints.length; ++i)
422 breakpoints[i].remove();
423 },
424
425 /**
426 * @param {string} tokenType
427 * @return {boolean}
428 */
429 _isIdentifier: function(tokenType)
430 {
431 return tokenType.startsWith("js-variable") || tokenType.startsWith("js-p roperty") || tokenType === "js-def";
432 },
433
434 _getPopoverAnchor: function(element, event)
435 {
436 var target = WebInspector.context.flavor(WebInspector.Target);
437 var debuggerModel = WebInspector.DebuggerModel.fromTarget(target);
438 if (!debuggerModel || !debuggerModel.isPaused())
439 return;
440
441 var textPosition = this.textEditor.coordinatesToCursorPosition(event.x, event.y);
442 if (!textPosition)
443 return;
444 var mouseLine = textPosition.startLine;
445 var mouseColumn = textPosition.startColumn;
446 var textSelection = this.textEditor.selection().normalize();
447 if (textSelection && !textSelection.isEmpty()) {
448 if (textSelection.startLine !== textSelection.endLine || textSelecti on.startLine !== mouseLine || mouseColumn < textSelection.startColumn || mouseCo lumn > textSelection.endColumn)
449 return;
450
451 var leftCorner = this.textEditor.cursorPositionToCoordinates(textSel ection.startLine, textSelection.startColumn);
452 var rightCorner = this.textEditor.cursorPositionToCoordinates(textSe lection.endLine, textSelection.endColumn);
453 var anchorBox = new AnchorBox(leftCorner.x, leftCorner.y, rightCorne r.x - leftCorner.x, leftCorner.height);
454 anchorBox.highlight = {
455 lineNumber: textSelection.startLine,
456 startColumn: textSelection.startColumn,
457 endColumn: textSelection.endColumn - 1
458 };
459 anchorBox.forSelection = true;
460 return anchorBox;
461 }
462
463 var token = this.textEditor.tokenAtTextPosition(textPosition.startLine, textPosition.startColumn);
464 if (!token || !token.type)
465 return;
466 var lineNumber = textPosition.startLine;
467 var line = this.textEditor.line(lineNumber);
468 var tokenContent = line.substring(token.startColumn, token.endColumn);
469
470 var isIdentifier = this._isIdentifier(token.type);
471 if (!isIdentifier && (token.type !== "js-keyword" || tokenContent !== "t his"))
472 return;
473
474 var leftCorner = this.textEditor.cursorPositionToCoordinates(lineNumber, token.startColumn);
475 var rightCorner = this.textEditor.cursorPositionToCoordinates(lineNumber , token.endColumn - 1);
476 var anchorBox = new AnchorBox(leftCorner.x, leftCorner.y, rightCorner.x - leftCorner.x, leftCorner.height);
477
478 anchorBox.highlight = {
479 lineNumber: lineNumber,
480 startColumn: token.startColumn,
481 endColumn: token.endColumn - 1
482 };
483
484 return anchorBox;
485 },
486
487 _resolveObjectForPopover: function(anchorBox, showCallback, objectGroupName)
488 {
489 var target = WebInspector.context.flavor(WebInspector.Target);
490 var selectedCallFrame = WebInspector.context.flavor(WebInspector.Debugge rModel.CallFrame);
491 if (!selectedCallFrame) {
492 this._popoverHelper.hidePopover();
493 return;
494 }
495 var lineNumber = anchorBox.highlight.lineNumber;
496 var startHighlight = anchorBox.highlight.startColumn;
497 var endHighlight = anchorBox.highlight.endColumn;
498 var line = this.textEditor.line(lineNumber);
499 if (!anchorBox.forSelection) {
500 while (startHighlight > 1 && line.charAt(startHighlight - 1) === "." ) {
501 var token = this.textEditor.tokenAtTextPosition(lineNumber, star tHighlight - 2);
502 if (!token || !token.type) {
503 this._popoverHelper.hidePopover();
504 return;
505 }
506 startHighlight = token.startColumn;
507 }
508 }
509 var evaluationText = line.substring(startHighlight, endHighlight + 1);
510 WebInspector.SourceMapNamesResolver.resolveExpression(selectedCallFrame, evaluationText, this.uiSourceCode(), lineNumber, startHighlight, endHighlight). then(onResolve.bind(this));
511
512 /**
513 * @param {?string=} text
514 * @this {WebInspector.JavaScriptSourceFrame}
515 */
516 function onResolve(text)
517 {
518 selectedCallFrame.evaluate(text || evaluationText, objectGroupName, false, true, false, false, showObjectPopover.bind(this));
519 }
520
521 /**
522 * @param {?RuntimeAgent.RemoteObject} result
523 * @param {!RuntimeAgent.ExceptionDetails=} exceptionDetails
524 * @this {WebInspector.JavaScriptSourceFrame}
525 */
526 function showObjectPopover(result, exceptionDetails)
527 {
528 var target = WebInspector.context.flavor(WebInspector.Target);
529 var potentiallyUpdatedCallFrame = WebInspector.context.flavor(WebIns pector.DebuggerModel.CallFrame);
530 if (selectedCallFrame !== potentiallyUpdatedCallFrame || !result) {
531 this._popoverHelper.hidePopover();
532 return;
533 }
534 this._popoverAnchorBox = anchorBox;
535 showCallback(target.runtimeModel.createRemoteObject(result), !!excep tionDetails, this._popoverAnchorBox);
536 // Popover may have been removed by showCallback().
537 if (this._popoverAnchorBox) {
538 var highlightRange = new WebInspector.TextRange(lineNumber, star tHighlight, lineNumber, endHighlight);
539 this._popoverAnchorBox._highlightDescriptor = this.textEditor.hi ghlightRange(highlightRange, "source-frame-eval-expression");
540 }
541 }
542 },
543
544 _onHidePopover: function()
545 {
546 if (!this._popoverAnchorBox)
547 return;
548 if (this._popoverAnchorBox._highlightDescriptor)
549 this.textEditor.removeHighlight(this._popoverAnchorBox._highlightDes criptor);
550 delete this._popoverAnchorBox;
551 },
552 712
553 /** 713 /**
554 * @param {number} lineNumber 714 * @param {number} lineNumber
555 * @param {number} columnNumber 715 * @param {string} tokenValue
556 * @param {string} condition 716 * @param {?string} tokenType
557 * @param {boolean} enabled 717 * @param {number} column
558 * @param {boolean} mutedWhileEditing 718 * @param {number} newColumn
719 * @this {WebInspector.JavaScriptSourceFrame}
559 */ 720 */
560 _addBreakpointDecoration: function(lineNumber, columnNumber, condition, enab led, mutedWhileEditing) 721 function processToken(lineNumber, tokenValue, tokenType, column, newColumn) {
561 { 722 if (!skipObjectProperty && tokenType && this._isIdentifier(tokenType) && v aluesMap.get(tokenValue)) {
562 var breakpoint = { 723 var names = namesPerLine.get(lineNumber);
563 condition: condition, 724 if (!names) {
564 enabled: enabled, 725 names = new Set();
565 columnNumber: columnNumber 726 namesPerLine.set(lineNumber, names);
566 };
567
568 this.textEditor.setAttribute(lineNumber, "breakpoint", breakpoint);
569
570 var disabled = !enabled || mutedWhileEditing;
571 this.textEditor.addBreakpoint(lineNumber, disabled, !!condition);
572 },
573
574 _removeBreakpointDecoration: function(lineNumber)
575 {
576 this.textEditor.removeAttribute(lineNumber, "breakpoint");
577 this.textEditor.removeBreakpoint(lineNumber);
578 },
579
580 _onKeyDown: function(event)
581 {
582 if (event.key === "Escape") {
583 if (this._popoverHelper.isPopoverVisible()) {
584 this._popoverHelper.hidePopover();
585 event.consume();
586 }
587 } 727 }
588 }, 728 names.add(tokenValue);
589 729 }
590 /** 730 skipObjectProperty = tokenValue === '.';
591 * @param {number} lineNumber 731 }
592 * @param {!WebInspector.BreakpointManager.Breakpoint=} breakpoint 732 this.textEditor.operation(this._renderDecorations.bind(this, valuesMap, name sPerLine, fromLine, toLine));
593 */ 733 }
594 _editBreakpointCondition: function(lineNumber, breakpoint) 734
595 { 735 /**
596 this._conditionElement = this._createConditionElement(lineNumber); 736 * @param {!Map.<string,!WebInspector.RemoteObject>} valuesMap
597 this.textEditor.addDecoration(this._conditionElement, lineNumber); 737 * @param {!Map.<number, !Set<string>>} namesPerLine
598 738 * @param {number} fromLine
599 /** 739 * @param {number} toLine
600 * @this {WebInspector.JavaScriptSourceFrame} 740 */
601 */ 741 _renderDecorations(valuesMap, namesPerLine, fromLine, toLine) {
602 function finishEditing(committed, element, newText) 742 var formatter = new WebInspector.RemoteObjectPreviewFormatter();
603 { 743 for (var i = fromLine; i < toLine; ++i) {
604 this.textEditor.removeDecoration(this._conditionElement, lineNumber) ; 744 var names = namesPerLine.get(i);
605 delete this._conditionEditorElement; 745 var oldWidget = this._valueWidgets.get(i);
606 delete this._conditionElement; 746 if (!names) {
607 if (!committed) 747 if (oldWidget) {
608 return; 748 this._valueWidgets.delete(i);
609 749 this.textEditor.removeDecoration(oldWidget, i);
610 if (breakpoint)
611 breakpoint.setCondition(newText);
612 else
613 this._createNewBreakpoint(lineNumber, 0, newText, true);
614 } 750 }
615 751 continue;
616 var config = new WebInspector.InplaceEditor.Config(finishEditing.bind(th is, true), finishEditing.bind(this, false)); 752 }
617 WebInspector.InplaceEditor.startEditing(this._conditionEditorElement, co nfig); 753
618 this._conditionEditorElement.value = breakpoint ? breakpoint.condition() : ""; 754 var widget = createElementWithClass('div', 'text-editor-value-decoration') ;
619 this._conditionEditorElement.select(); 755 var base = this.textEditor.cursorPositionToCoordinates(i, 0);
620 }, 756 var offset = this.textEditor.cursorPositionToCoordinates(i, this.textEdito r.line(i).length);
621 757 var codeMirrorLinesLeftPadding = 4;
622 _createConditionElement: function(lineNumber) 758 var left = offset.x - base.x + codeMirrorLinesLeftPadding;
623 { 759 widget.style.left = left + 'px';
624 var conditionElement = createElementWithClass("div", "source-frame-break point-condition"); 760 widget.__nameToToken = new Map();
625 761
626 var labelElement = conditionElement.createChild("label", "source-frame-b reakpoint-message"); 762 var renderedNameCount = 0;
627 labelElement.htmlFor = "source-frame-breakpoint-condition"; 763 for (var name of names) {
628 labelElement.createTextChild(WebInspector.UIString("The breakpoint on li ne %d will stop only if this expression is true:", lineNumber + 1)); 764 if (renderedNameCount > 10)
629 765 break;
630 var editorElement = conditionElement.createChild("input", "monospace"); 766 if (namesPerLine.get(i - 1) && namesPerLine.get(i - 1).has(name))
631 editorElement.id = "source-frame-breakpoint-condition"; 767 continue; // Only render name once in the given continuous block.
632 editorElement.type = "text"; 768 if (renderedNameCount)
633 this._conditionEditorElement = editorElement; 769 widget.createTextChild(', ');
634 770 var nameValuePair = widget.createChild('span');
635 return conditionElement; 771 widget.__nameToToken.set(name, nameValuePair);
636 }, 772 nameValuePair.createTextChild(name + ' = ');
637 773 var value = valuesMap.get(name);
638 /** 774 var propertyCount = value.preview ? value.preview.properties.length : 0;
639 * @param {!WebInspector.UILocation} uiLocation 775 var entryCount = value.preview && value.preview.entries ? value.preview. entries.length : 0;
640 */ 776 if (value.preview && propertyCount + entryCount < 10)
641 setExecutionLocation: function(uiLocation) 777 formatter.appendObjectPreview(nameValuePair, value.preview);
642 { 778 else
643 this._executionLocation = uiLocation; 779 nameValuePair.appendChild(WebInspector.ObjectPropertiesSection.createV alueElement(value, false));
644 if (!this.loaded) 780 ++renderedNameCount;
645 return; 781 }
646 782
647 this.textEditor.setExecutionLocation(uiLocation.lineNumber, uiLocation.c olumnNumber); 783 var widgetChanged = true;
648 if (this.isShowing()) { 784 if (oldWidget) {
649 // We need SourcesTextEditor to be initialized prior to this call. @ see crbug.com/506566 785 widgetChanged = false;
650 setImmediate(this._generateValuesInSource.bind(this)); 786 for (var name of widget.__nameToToken.keys()) {
787 var oldText = oldWidget.__nameToToken.get(name) ? oldWidget.__nameToTo ken.get(name).textContent : '';
788 var newText = widget.__nameToToken.get(name) ? widget.__nameToToken.ge t(name).textContent : '';
789 if (newText !== oldText) {
790 widgetChanged = true;
791 // value has changed, update it.
792 WebInspector.runCSSAnimationOnce(
793 /** @type {!Element} */ (widget.__nameToToken.get(name)), 'sourc e-frame-value-update-highlight');
794 }
651 } 795 }
652 }, 796 if (widgetChanged) {
653 797 this._valueWidgets.delete(i);
654 _generateValuesInSource: function() 798 this.textEditor.removeDecoration(oldWidget, i);
655 {
656 if (!WebInspector.moduleSetting("inlineVariableValues").get())
657 return;
658 var executionContext = WebInspector.context.flavor(WebInspector.Executio nContext);
659 if (!executionContext)
660 return;
661 var callFrame = WebInspector.context.flavor(WebInspector.DebuggerModel.C allFrame);
662 if (!callFrame)
663 return;
664
665 var localScope = callFrame.localScope();
666 var functionLocation = callFrame.functionLocation();
667 if (localScope && functionLocation)
668 WebInspector.SourceMapNamesResolver.resolveScopeInObject(localScope) .getAllProperties(false, this._prepareScopeVariables.bind(this, callFrame));
669
670 if (this._clearValueWidgetsTimer) {
671 clearTimeout(this._clearValueWidgetsTimer);
672 delete this._clearValueWidgetsTimer;
673 } 799 }
674 }, 800 }
675 801 if (widgetChanged) {
676 /** 802 this._valueWidgets.set(i, widget);
677 * @param {!WebInspector.DebuggerModel.CallFrame} callFrame 803 this.textEditor.addDecoration(widget, i);
678 * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties 804 }
679 * @param {?Array.<!WebInspector.RemoteObjectProperty>} internalProperties 805 }
680 */ 806 }
681 _prepareScopeVariables: function(callFrame, properties, internalProperties) 807
682 { 808 clearExecutionLine() {
683 if (!properties || !properties.length || properties.length > 500) { 809 if (this.loaded && this._executionLocation)
684 this._clearValueWidgets(); 810 this.textEditor.clearExecutionLine();
685 return; 811 delete this._executionLocation;
812 this._clearValueWidgetsTimer = setTimeout(this._clearValueWidgets.bind(this) , 1000);
813 }
814
815 _clearValueWidgets() {
816 delete this._clearValueWidgetsTimer;
817 for (var line of this._valueWidgets.keys())
818 this.textEditor.removeDecoration(this._valueWidgets.get(line), line);
819 this._valueWidgets.clear();
820 }
821
822 /**
823 * @return {boolean}
824 */
825 _shouldIgnoreExternalBreakpointEvents() {
826 if (this._supportsEnabledBreakpointsWhileEditing())
827 return false;
828 if (this._muted)
829 return true;
830 var scriptFiles = this._scriptFileForTarget.valuesArray();
831 for (var i = 0; i < scriptFiles.length; ++i) {
832 if (scriptFiles[i].isDivergingFromVM() || scriptFiles[i].isMergingToVM())
833 return true;
834 }
835 return false;
836 }
837
838 _breakpointAdded(event) {
839 var uiLocation = /** @type {!WebInspector.UILocation} */ (event.data.uiLocat ion);
840 if (uiLocation.uiSourceCode !== this.uiSourceCode())
841 return;
842 if (this._shouldIgnoreExternalBreakpointEvents())
843 return;
844
845 var breakpoint = /** @type {!WebInspector.BreakpointManager.Breakpoint} */ ( event.data.breakpoint);
846 if (this.loaded)
847 this._addBreakpointDecoration(
848 uiLocation.lineNumber, uiLocation.columnNumber, breakpoint.condition() , breakpoint.enabled(), false);
849 }
850
851 _breakpointRemoved(event) {
852 var uiLocation = /** @type {!WebInspector.UILocation} */ (event.data.uiLocat ion);
853 if (uiLocation.uiSourceCode !== this.uiSourceCode())
854 return;
855 if (this._shouldIgnoreExternalBreakpointEvents())
856 return;
857
858 var remainingBreakpoint = this._breakpointManager.findBreakpointOnLine(this. uiSourceCode(), uiLocation.lineNumber);
859 if (!remainingBreakpoint && this.loaded)
860 this._removeBreakpointDecoration(uiLocation.lineNumber);
861 }
862
863 /**
864 * @param {!WebInspector.Event} event
865 */
866 _onSourceMappingChanged(event) {
867 var data = /** @type {{target: !WebInspector.Target}} */ (event.data);
868 this._updateScriptFile(data.target);
869 this._updateLinesWithoutMappingHighlight();
870 }
871
872 _updateLinesWithoutMappingHighlight() {
873 var linesCount = this.textEditor.linesCount;
874 for (var i = 0; i < linesCount; ++i) {
875 var lineHasMapping = WebInspector.debuggerWorkspaceBinding.uiLineHasMappin g(this.uiSourceCode(), i);
876 if (!lineHasMapping)
877 this._hasLineWithoutMapping = true;
878 if (this._hasLineWithoutMapping)
879 this.textEditor.toggleLineClass(i, 'cm-line-without-source-mapping', !li neHasMapping);
880 }
881 }
882
883 /**
884 * @param {!WebInspector.Target} target
885 */
886 _updateScriptFile(target) {
887 var oldScriptFile = this._scriptFileForTarget.get(target);
888 var newScriptFile = WebInspector.debuggerWorkspaceBinding.scriptFile(this.ui SourceCode(), target);
889 this._scriptFileForTarget.remove(target);
890 if (oldScriptFile) {
891 oldScriptFile.removeEventListener(WebInspector.ResourceScriptFile.Events.D idMergeToVM, this._didMergeToVM, this);
892 oldScriptFile.removeEventListener(
893 WebInspector.ResourceScriptFile.Events.DidDivergeFromVM, this._didDive rgeFromVM, this);
894 if (this._muted && !this.uiSourceCode().isDirty())
895 this._restoreBreakpointsIfConsistentScripts();
896 }
897 if (newScriptFile)
898 this._scriptFileForTarget.set(target, newScriptFile);
899
900 this._updateDivergedInfobar();
901
902 if (newScriptFile) {
903 newScriptFile.addEventListener(WebInspector.ResourceScriptFile.Events.DidM ergeToVM, this._didMergeToVM, this);
904 newScriptFile.addEventListener(
905 WebInspector.ResourceScriptFile.Events.DidDivergeFromVM, this._didDive rgeFromVM, this);
906 if (this.loaded)
907 newScriptFile.checkMapping();
908 if (newScriptFile.hasSourceMapURL()) {
909 var sourceMapInfobar = WebInspector.Infobar.create(
910 WebInspector.Infobar.Type.Info, WebInspector.UIString('Source Map de tected.'),
911 WebInspector.settings.createSetting('sourceMapInfobarDisabled', fals e));
912 if (sourceMapInfobar) {
913 sourceMapInfobar.createDetailsRowMessage(WebInspector.UIString(
914 'Associated files should be added to the file tree. You can debug these resolved source files as regular JavaScript files.'));
915 sourceMapInfobar.createDetailsRowMessage(WebInspector.UIString(
916 'Associated files are available via file tree or %s.',
917 WebInspector.shortcutRegistry.shortcutTitleForAction('sources.go-t o-source')));
918 this.attachInfobars([sourceMapInfobar]);
686 } 919 }
687 920 }
688 var functionUILocation = WebInspector.debuggerWorkspaceBinding.rawLocati onToUILocation(/** @type {!WebInspector.DebuggerModel.Location} */ (callFrame.fu nctionLocation())); 921 }
689 var executionUILocation = WebInspector.debuggerWorkspaceBinding.rawLocat ionToUILocation(callFrame.location()); 922 }
690 if (functionUILocation.uiSourceCode !== this.uiSourceCode() || execution UILocation.uiSourceCode !== this.uiSourceCode()) { 923
691 this._clearValueWidgets(); 924 /**
692 return; 925 * @override
693 } 926 */
694 927 onTextEditorContentSet() {
695 var fromLine = functionUILocation.lineNumber; 928 super.onTextEditorContentSet();
696 var fromColumn = functionUILocation.columnNumber; 929 if (this._executionLocation)
697 var toLine = executionUILocation.lineNumber; 930 this.setExecutionLocation(this._executionLocation);
698 931
699 // Make sure we have a chance to update all existing widgets. 932 var breakpointLocations = this._breakpointManager.breakpointLocationsForUISo urceCode(this.uiSourceCode());
700 if (this._valueWidgets) { 933 for (var i = 0; i < breakpointLocations.length; ++i)
701 for (var line of this._valueWidgets.keys()) 934 this._breakpointAdded({data: breakpointLocations[i]});
702 toLine = Math.max(toLine, line + 1); 935
703 } 936 var scriptFiles = this._scriptFileForTarget.valuesArray();
704 if (fromLine >= toLine || toLine - fromLine > 500 || fromLine < 0 || toL ine >= this.textEditor.linesCount) { 937 for (var i = 0; i < scriptFiles.length; ++i)
705 this._clearValueWidgets(); 938 scriptFiles[i].checkMapping();
706 return; 939
707 } 940 this._updateLinesWithoutMappingHighlight();
708 941 this._detectMinified();
709 var valuesMap = new Map(); 942 }
710 for (var property of properties) 943
711 valuesMap.set(property.name, property.value); 944 _detectMinified() {
712 945 if (this._prettyPrintInfobar)
713 /** @type {!Map.<number, !Set<string>>} */ 946 return;
714 var namesPerLine = new Map(); 947
715 var skipObjectProperty = false; 948 var minified = false;
716 var tokenizer = new WebInspector.CodeMirrorUtils.TokenizerFactory().crea teTokenizer("text/javascript"); 949 for (var i = 0; i < 10 && i < this.textEditor.linesCount; ++i) {
717 tokenizer(this.textEditor.line(fromLine).substring(fromColumn), processT oken.bind(this, fromLine)); 950 var line = this.textEditor.line(i);
718 for (var i = fromLine + 1; i < toLine; ++i) 951 if (line.startsWith('//#')) // mind source map.
719 tokenizer(this.textEditor.line(i), processToken.bind(this, i)); 952 continue;
720 953 if (line.length > 500) {
721 /** 954 minified = true;
722 * @param {number} lineNumber 955 break;
723 * @param {string} tokenValue 956 }
724 * @param {?string} tokenType 957 }
725 * @param {number} column 958 if (!minified)
726 * @param {number} newColumn 959 return;
727 * @this {WebInspector.JavaScriptSourceFrame} 960
728 */ 961 this._prettyPrintInfobar = WebInspector.Infobar.create(
729 function processToken(lineNumber, tokenValue, tokenType, column, newColu mn) 962 WebInspector.Infobar.Type.Info, WebInspector.UIString('Pretty-print this minified file?'),
730 { 963 WebInspector.settings.createSetting('prettyPrintInfobarDisabled', false) );
731 if (!skipObjectProperty && tokenType && this._isIdentifier(tokenType ) && valuesMap.get(tokenValue)) { 964 if (!this._prettyPrintInfobar)
732 var names = namesPerLine.get(lineNumber); 965 return;
733 if (!names) { 966
734 names = new Set(); 967 this._prettyPrintInfobar.setCloseCallback(() => delete this._prettyPrintInfo bar);
735 namesPerLine.set(lineNumber, names); 968 var toolbar = new WebInspector.Toolbar('');
736 } 969 var button = new WebInspector.ToolbarButton('', 'format-toolbar-item');
737 names.add(tokenValue); 970 toolbar.appendToolbarItem(button);
738 } 971 toolbar.element.style.display = 'inline-block';
739 skipObjectProperty = tokenValue === "."; 972 toolbar.element.style.verticalAlign = 'middle';
740 } 973 toolbar.element.style.marginBottom = '3px';
741 this.textEditor.operation(this._renderDecorations.bind(this, valuesMap, namesPerLine, fromLine, toLine)); 974 toolbar.element.style.pointerEvents = 'none';
742 }, 975 var element = this._prettyPrintInfobar.createDetailsRowMessage();
743 976 element.appendChild(WebInspector.formatLocalized(
744 /** 977 'You can click the %s button on the bottom status bar, and continue debu gging with the new formatted source.',
745 * @param {!Map.<string,!WebInspector.RemoteObject>} valuesMap 978 [toolbar.element]));
746 * @param {!Map.<number, !Set<string>>} namesPerLine 979 this.attachInfobars([this._prettyPrintInfobar]);
747 * @param {number} fromLine 980 }
748 * @param {number} toLine 981
749 */ 982 /**
750 _renderDecorations: function(valuesMap, namesPerLine, fromLine, toLine) 983 * @param {!WebInspector.Event} event
751 { 984 */
752 var formatter = new WebInspector.RemoteObjectPreviewFormatter(); 985 _handleGutterClick(event) {
753 for (var i = fromLine; i < toLine; ++i) { 986 if (this._muted)
754 var names = namesPerLine.get(i); 987 return;
755 var oldWidget = this._valueWidgets.get(i); 988
756 if (!names) { 989 var eventData = /** @type {!WebInspector.SourcesTextEditor.GutterClickEventD ata} */ (event.data);
757 if (oldWidget) { 990 var lineNumber = eventData.lineNumber;
758 this._valueWidgets.delete(i); 991 var eventObject = eventData.event;
759 this.textEditor.removeDecoration(oldWidget, i); 992
760 } 993 if (eventObject.button !== 0 || eventObject.altKey || eventObject.ctrlKey || eventObject.metaKey)
761 continue; 994 return;
762 } 995
763 996 this._toggleBreakpoint(lineNumber, eventObject.shiftKey);
764 var widget = createElementWithClass("div", "text-editor-value-decora tion"); 997 eventObject.consume(true);
765 var base = this.textEditor.cursorPositionToCoordinates(i, 0); 998 }
766 var offset = this.textEditor.cursorPositionToCoordinates(i, this.tex tEditor.line(i).length); 999
767 var codeMirrorLinesLeftPadding = 4; 1000 /**
768 var left = offset.x - base.x + codeMirrorLinesLeftPadding; 1001 * @param {number} lineNumber
769 widget.style.left = left + "px"; 1002 * @param {boolean} onlyDisable
770 widget.__nameToToken = new Map(); 1003 */
771 1004 _toggleBreakpoint(lineNumber, onlyDisable) {
772 var renderedNameCount = 0; 1005 var breakpoint = this._breakpointManager.findBreakpointOnLine(this.uiSourceC ode(), lineNumber);
773 for (var name of names) { 1006 if (breakpoint) {
774 if (renderedNameCount > 10) 1007 if (onlyDisable)
775 break; 1008 breakpoint.setEnabled(!breakpoint.enabled());
776 if (namesPerLine.get(i - 1) && namesPerLine.get(i - 1).has(name) ) 1009 else
777 continue; // Only render name once in the given continuous block. 1010 breakpoint.remove();
778 if (renderedNameCount) 1011 } else
779 widget.createTextChild(", "); 1012 this._createNewBreakpoint(lineNumber, 0, '', true);
780 var nameValuePair = widget.createChild("span"); 1013 }
781 widget.__nameToToken.set(name, nameValuePair); 1014
782 nameValuePair.createTextChild(name + " = "); 1015 /**
783 var value = valuesMap.get(name); 1016 * @param {number} lineNumber
784 var propertyCount = value.preview ? value.preview.properties.len gth : 0; 1017 * @param {number} columnNumber
785 var entryCount = value.preview && value.preview.entries ? value. preview.entries.length : 0; 1018 * @param {string} condition
786 if (value.preview && propertyCount + entryCount < 10) 1019 * @param {boolean} enabled
787 formatter.appendObjectPreview(nameValuePair, value.preview); 1020 */
788 else 1021 _createNewBreakpoint(lineNumber, columnNumber, condition, enabled) {
789 nameValuePair.appendChild(WebInspector.ObjectPropertiesSecti on.createValueElement(value, false)); 1022 this._setBreakpoint(lineNumber, columnNumber, condition, enabled);
790 ++renderedNameCount; 1023 WebInspector.userMetrics.actionTaken(WebInspector.UserMetrics.Action.Scripts BreakpointSet);
791 } 1024 }
792 1025
793 var widgetChanged = true; 1026 toggleBreakpointOnCurrentLine() {
794 if (oldWidget) { 1027 if (this._muted)
795 widgetChanged = false; 1028 return;
796 for (var name of widget.__nameToToken.keys()) { 1029
797 var oldText = oldWidget.__nameToToken.get(name) ? oldWidget. __nameToToken.get(name).textContent : ""; 1030 var selection = this.textEditor.selection();
798 var newText = widget.__nameToToken.get(name) ? widget.__name ToToken.get(name).textContent : ""; 1031 if (!selection)
799 if (newText !== oldText) { 1032 return;
800 widgetChanged = true; 1033 this._toggleBreakpoint(selection.startLine, false);
801 // value has changed, update it. 1034 }
802 WebInspector.runCSSAnimationOnce(/** @type {!Element} */ (widget.__nameToToken.get(name)), "source-frame-value-update-highlight"); 1035
803 } 1036 /**
804 } 1037 * @param {number} lineNumber
805 if (widgetChanged) { 1038 * @param {number} columnNumber
806 this._valueWidgets.delete(i); 1039 * @param {string} condition
807 this.textEditor.removeDecoration(oldWidget, i); 1040 * @param {boolean} enabled
808 } 1041 */
809 } 1042 _setBreakpoint(lineNumber, columnNumber, condition, enabled) {
810 if (widgetChanged) { 1043 if (!WebInspector.debuggerWorkspaceBinding.uiLineHasMapping(this.uiSourceCod e(), lineNumber))
811 this._valueWidgets.set(i, widget); 1044 return;
812 this.textEditor.addDecoration(widget, i); 1045
813 } 1046 this._breakpointManager.setBreakpoint(this.uiSourceCode(), lineNumber, colum nNumber, condition, enabled);
814 } 1047 }
815 }, 1048
816 1049 /**
817 clearExecutionLine: function() 1050 * @override
818 { 1051 */
819 if (this.loaded && this._executionLocation) 1052 dispose() {
820 this.textEditor.clearExecutionLine(); 1053 this._breakpointManager.removeEventListener(
821 delete this._executionLocation; 1054 WebInspector.BreakpointManager.Events.BreakpointAdded, this._breakpointA dded, this);
822 this._clearValueWidgetsTimer = setTimeout(this._clearValueWidgets.bind(t his), 1000); 1055 this._breakpointManager.removeEventListener(
823 }, 1056 WebInspector.BreakpointManager.Events.BreakpointRemoved, this._breakpoin tRemoved, this);
824 1057 this.uiSourceCode().removeEventListener(
825 _clearValueWidgets: function() 1058 WebInspector.UISourceCode.Events.SourceMappingChanged, this._onSourceMap pingChanged, this);
826 { 1059 this.uiSourceCode().removeEventListener(
827 delete this._clearValueWidgetsTimer; 1060 WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyCh anged, this);
828 for (var line of this._valueWidgets.keys()) 1061 this.uiSourceCode().removeEventListener(
829 this.textEditor.removeDecoration(this._valueWidgets.get(line), line) ; 1062 WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._workingCopy Committed, this);
830 this._valueWidgets.clear(); 1063 this.uiSourceCode().removeEventListener(
831 }, 1064 WebInspector.UISourceCode.Events.TitleChanged, this._showBlackboxInfobar IfNeeded, this);
832 1065 WebInspector.moduleSetting('skipStackFramesPattern').removeChangeListener(th is._showBlackboxInfobarIfNeeded, this);
833 /** 1066 WebInspector.moduleSetting('skipContentScripts').removeChangeListener(this._ showBlackboxInfobarIfNeeded, this);
834 * @return {boolean} 1067 super.dispose();
835 */ 1068 }
836 _shouldIgnoreExternalBreakpointEvents: function()
837 {
838 if (this._supportsEnabledBreakpointsWhileEditing())
839 return false;
840 if (this._muted)
841 return true;
842 var scriptFiles = this._scriptFileForTarget.valuesArray();
843 for (var i = 0; i < scriptFiles.length; ++i) {
844 if (scriptFiles[i].isDivergingFromVM() || scriptFiles[i].isMergingTo VM())
845 return true;
846 }
847 return false;
848 },
849
850 _breakpointAdded: function(event)
851 {
852 var uiLocation = /** @type {!WebInspector.UILocation} */ (event.data.uiL ocation);
853 if (uiLocation.uiSourceCode !== this.uiSourceCode())
854 return;
855 if (this._shouldIgnoreExternalBreakpointEvents())
856 return;
857
858 var breakpoint = /** @type {!WebInspector.BreakpointManager.Breakpoint} */ (event.data.breakpoint);
859 if (this.loaded)
860 this._addBreakpointDecoration(uiLocation.lineNumber, uiLocation.colu mnNumber, breakpoint.condition(), breakpoint.enabled(), false);
861 },
862
863 _breakpointRemoved: function(event)
864 {
865 var uiLocation = /** @type {!WebInspector.UILocation} */ (event.data.uiL ocation);
866 if (uiLocation.uiSourceCode !== this.uiSourceCode())
867 return;
868 if (this._shouldIgnoreExternalBreakpointEvents())
869 return;
870
871 var remainingBreakpoint = this._breakpointManager.findBreakpointOnLine(t his.uiSourceCode(), uiLocation.lineNumber);
872 if (!remainingBreakpoint && this.loaded)
873 this._removeBreakpointDecoration(uiLocation.lineNumber);
874 },
875
876 /**
877 * @param {!WebInspector.Event} event
878 */
879 _onSourceMappingChanged: function(event)
880 {
881 var data = /** @type {{target: !WebInspector.Target}} */ (event.data);
882 this._updateScriptFile(data.target);
883 this._updateLinesWithoutMappingHighlight();
884 },
885
886 _updateLinesWithoutMappingHighlight: function()
887 {
888 var linesCount = this.textEditor.linesCount;
889 for (var i = 0; i < linesCount; ++i) {
890 var lineHasMapping = WebInspector.debuggerWorkspaceBinding.uiLineHas Mapping(this.uiSourceCode(), i);
891 if (!lineHasMapping)
892 this._hasLineWithoutMapping = true;
893 if (this._hasLineWithoutMapping)
894 this.textEditor.toggleLineClass(i, "cm-line-without-source-mappi ng", !lineHasMapping);
895 }
896 },
897
898 /**
899 * @param {!WebInspector.Target} target
900 */
901 _updateScriptFile: function(target)
902 {
903 var oldScriptFile = this._scriptFileForTarget.get(target);
904 var newScriptFile = WebInspector.debuggerWorkspaceBinding.scriptFile(thi s.uiSourceCode(), target);
905 this._scriptFileForTarget.remove(target);
906 if (oldScriptFile) {
907 oldScriptFile.removeEventListener(WebInspector.ResourceScriptFile.Ev ents.DidMergeToVM, this._didMergeToVM, this);
908 oldScriptFile.removeEventListener(WebInspector.ResourceScriptFile.Ev ents.DidDivergeFromVM, this._didDivergeFromVM, this);
909 if (this._muted && !this.uiSourceCode().isDirty())
910 this._restoreBreakpointsIfConsistentScripts();
911 }
912 if (newScriptFile)
913 this._scriptFileForTarget.set(target, newScriptFile);
914
915 this._updateDivergedInfobar();
916
917 if (newScriptFile) {
918 newScriptFile.addEventListener(WebInspector.ResourceScriptFile.Event s.DidMergeToVM, this._didMergeToVM, this);
919 newScriptFile.addEventListener(WebInspector.ResourceScriptFile.Event s.DidDivergeFromVM, this._didDivergeFromVM, this);
920 if (this.loaded)
921 newScriptFile.checkMapping();
922 if (newScriptFile.hasSourceMapURL()) {
923 var sourceMapInfobar = WebInspector.Infobar.create(WebInspector. Infobar.Type.Info, WebInspector.UIString("Source Map detected."), WebInspector.s ettings.createSetting("sourceMapInfobarDisabled", false));
924 if (sourceMapInfobar) {
925 sourceMapInfobar.createDetailsRowMessage(WebInspector.UIStri ng("Associated files should be added to the file tree. You can debug these resol ved source files as regular JavaScript files."));
926 sourceMapInfobar.createDetailsRowMessage(WebInspector.UIStri ng("Associated files are available via file tree or %s.", WebInspector.shortcutR egistry.shortcutTitleForAction("sources.go-to-source")));
927 this.attachInfobars([sourceMapInfobar]);
928 }
929 }
930 }
931 },
932
933 /**
934 * @override
935 */
936 onTextEditorContentSet: function()
937 {
938 WebInspector.UISourceCodeFrame.prototype.onTextEditorContentSet.call(thi s);
939 if (this._executionLocation)
940 this.setExecutionLocation(this._executionLocation);
941
942 var breakpointLocations = this._breakpointManager.breakpointLocationsFor UISourceCode(this.uiSourceCode());
943 for (var i = 0; i < breakpointLocations.length; ++i)
944 this._breakpointAdded({data:breakpointLocations[i]});
945
946 var scriptFiles = this._scriptFileForTarget.valuesArray();
947 for (var i = 0; i < scriptFiles.length; ++i)
948 scriptFiles[i].checkMapping();
949
950 this._updateLinesWithoutMappingHighlight();
951 this._detectMinified();
952 },
953
954 _detectMinified: function()
955 {
956 if (this._prettyPrintInfobar)
957 return;
958
959 var minified = false;
960 for (var i = 0; i < 10 && i < this.textEditor.linesCount; ++i) {
961 var line = this.textEditor.line(i);
962 if (line.startsWith("//#")) // mind source map.
963 continue;
964 if (line.length > 500) {
965 minified = true;
966 break;
967 }
968 }
969 if (!minified)
970 return;
971
972 this._prettyPrintInfobar = WebInspector.Infobar.create(
973 WebInspector.Infobar.Type.Info,
974 WebInspector.UIString("Pretty-print this minified file?"),
975 WebInspector.settings.createSetting("prettyPrintInfobarDisabled", fa lse));
976 if (!this._prettyPrintInfobar)
977 return;
978
979 this._prettyPrintInfobar.setCloseCallback(() => delete this._prettyPrint Infobar);
980 var toolbar = new WebInspector.Toolbar("");
981 var button = new WebInspector.ToolbarButton("", "format-toolbar-item");
982 toolbar.appendToolbarItem(button);
983 toolbar.element.style.display = "inline-block";
984 toolbar.element.style.verticalAlign = "middle";
985 toolbar.element.style.marginBottom = "3px";
986 toolbar.element.style.pointerEvents = "none";
987 var element = this._prettyPrintInfobar.createDetailsRowMessage();
988 element.appendChild(WebInspector.formatLocalized("You can click the %s b utton on the bottom status bar, and continue debugging with the new formatted so urce.", [toolbar.element]));
989 this.attachInfobars([this._prettyPrintInfobar]);
990 },
991
992 /**
993 * @param {!WebInspector.Event} event
994 */
995 _handleGutterClick: function(event)
996 {
997 if (this._muted)
998 return;
999
1000 var eventData = /** @type {!WebInspector.SourcesTextEditor.GutterClickEv entData} */ (event.data);
1001 var lineNumber = eventData.lineNumber;
1002 var eventObject = eventData.event;
1003
1004 if (eventObject.button !== 0 || eventObject.altKey || eventObject.ctrlKe y || eventObject.metaKey)
1005 return;
1006
1007 this._toggleBreakpoint(lineNumber, eventObject.shiftKey);
1008 eventObject.consume(true);
1009 },
1010
1011 /**
1012 * @param {number} lineNumber
1013 * @param {boolean} onlyDisable
1014 */
1015 _toggleBreakpoint: function(lineNumber, onlyDisable)
1016 {
1017 var breakpoint = this._breakpointManager.findBreakpointOnLine(this.uiSou rceCode(), lineNumber);
1018 if (breakpoint) {
1019 if (onlyDisable)
1020 breakpoint.setEnabled(!breakpoint.enabled());
1021 else
1022 breakpoint.remove();
1023 } else
1024 this._createNewBreakpoint(lineNumber, 0, "", true);
1025 },
1026
1027 /**
1028 * @param {number} lineNumber
1029 * @param {number} columnNumber
1030 * @param {string} condition
1031 * @param {boolean} enabled
1032 */
1033 _createNewBreakpoint: function(lineNumber, columnNumber, condition, enabled)
1034 {
1035 this._setBreakpoint(lineNumber, columnNumber, condition, enabled);
1036 WebInspector.userMetrics.actionTaken(WebInspector.UserMetrics.Action.Scr iptsBreakpointSet);
1037 },
1038
1039 toggleBreakpointOnCurrentLine: function()
1040 {
1041 if (this._muted)
1042 return;
1043
1044 var selection = this.textEditor.selection();
1045 if (!selection)
1046 return;
1047 this._toggleBreakpoint(selection.startLine, false);
1048 },
1049
1050 /**
1051 * @param {number} lineNumber
1052 * @param {number} columnNumber
1053 * @param {string} condition
1054 * @param {boolean} enabled
1055 */
1056 _setBreakpoint: function(lineNumber, columnNumber, condition, enabled)
1057 {
1058 if (!WebInspector.debuggerWorkspaceBinding.uiLineHasMapping(this.uiSourc eCode(), lineNumber))
1059 return;
1060
1061 this._breakpointManager.setBreakpoint(this.uiSourceCode(), lineNumber, c olumnNumber, condition, enabled);
1062 },
1063
1064 dispose: function()
1065 {
1066 this._breakpointManager.removeEventListener(WebInspector.BreakpointManag er.Events.BreakpointAdded, this._breakpointAdded, this);
1067 this._breakpointManager.removeEventListener(WebInspector.BreakpointManag er.Events.BreakpointRemoved, this._breakpointRemoved, this);
1068 this.uiSourceCode().removeEventListener(WebInspector.UISourceCode.Events .SourceMappingChanged, this._onSourceMappingChanged, this);
1069 this.uiSourceCode().removeEventListener(WebInspector.UISourceCode.Events .WorkingCopyChanged, this._workingCopyChanged, this);
1070 this.uiSourceCode().removeEventListener(WebInspector.UISourceCode.Events .WorkingCopyCommitted, this._workingCopyCommitted, this);
1071 this.uiSourceCode().removeEventListener(WebInspector.UISourceCode.Events .TitleChanged, this._showBlackboxInfobarIfNeeded, this);
1072 WebInspector.moduleSetting("skipStackFramesPattern").removeChangeListene r(this._showBlackboxInfobarIfNeeded, this);
1073 WebInspector.moduleSetting("skipContentScripts").removeChangeListener(th is._showBlackboxInfobarIfNeeded, this);
1074 WebInspector.UISourceCodeFrame.prototype.dispose.call(this);
1075 },
1076
1077 __proto__: WebInspector.UISourceCodeFrame.prototype
1078 }; 1069 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698