OLD | NEW |
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 }; |
OLD | NEW |