2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
33 * @extends {WebInspector.UISourceCodeFrame}
34 * @param {!WebInspector.SourcesPanel} scriptsPanel
35 * @param {!WebInspector.UISourceCode} uiSourceCode
37 WebInspector.JavaScriptSourceFrame = function(scriptsPanel, uiSourceCode)
39 this._scriptsPanel = scriptsPanel;
40 this._breakpointManager = WebInspector.breakpointManager;
41 this._uiSourceCode = uiSourceCode;
43 WebInspector.UISourceCodeFrame.call(this, uiSourceCode);
44 if (uiSourceCode.project().type() === WebInspector.projectTypes.Debugger)
45 this.element.classList.add("source-frame-debugger-script");
47 this._popoverHelper = new WebInspector.ObjectPopoverHelper(this.textEditor.element,
48 this._getPopoverAnchor.bind(this), this._resolveObjectForPopover.bind(this), this._onHidePopover.bind(this), true);
50 this.textEditor.element.addEventListener("keydown", this._onKeyDown.bind(this), true);
52 this.textEditor.addEventListener(WebInspector.TextEditor.Events.GutterClick, this._handleGutterClick.bind(this), this);
54 this._breakpointManager.addEventListener(WebInspector.BreakpointManager.Events.BreakpointAdded, this._breakpointAdded, this);
55 this._breakpointManager.addEventListener(WebInspector.BreakpointManager.Events.BreakpointRemoved, this._breakpointRemoved, this);
57 this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.ConsoleMessageAdded, this._consoleMessageAdded, this);
58 this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.ConsoleMessageRemoved, this._consoleMessageRemoved, this);
59 this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.ConsoleMessagesCleared, this._consoleMessagesCleared, this);
60 this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._onSourceMappingChanged, this);
61 this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this);
62 this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._workingCopyCommitted, this);
64 this._registerShortcuts();
65 this._updateScriptFile();
68 WebInspector.JavaScriptSourceFrame.prototype = {
70 * @param {!Element} infobarElement
72 _showInfobar: function(infobarElement)
74 if (this._infobarElement)
75 this._infobarElement.remove();
76 this._infobarElement = infobarElement;
77 this._infobarElement.classList.add("java-script-source-frame-infobar");
78 this.element.insertBefore(this._infobarElement, this.element.children[0]);
83 * @param {!Element} infobarElement
85 _hideInfobar: function(infobarElement)
87 infobarElement.remove();
91 _showDivergedInfobar: function()
93 var target = this._scriptFile.target();
97 this._divergedInfobarElement = document.createElement("div");
98 var infobarMainRow = this._divergedInfobarElement.createChild("div", "java-script-source-frame-infobar-main-row");
99 var infobarDetailsContainer = this._divergedInfobarElement.createChild("span", "java-script-source-frame-infobar-details-container");
101 infobarMainRow.createChild("span", "java-script-source-frame-infobar-warning-icon");
102 var infobarMessage = infobarMainRow.createChild("span", "java-script-source-frame-infobar-row-message");
103 infobarMessage.textContent = WebInspector.UIString("Workspace mapping mismatch");
106 * @this {WebInspector.JavaScriptSourceFrame}
108 function updateDetailsVisibility()
110 detailsToggleElement.textContent = detailsToggleElement._toggled ? WebInspector.UIString("less") : WebInspector.UIString("more");
111 infobarDetailsContainer.classList.toggle("hidden", !detailsToggleElement._toggled);
116 * @this {WebInspector.JavaScriptSourceFrame}
118 function toggleDetails()
120 detailsToggleElement._toggled = !detailsToggleElement._toggled;
121 updateDetailsVisibility.call(this);
124 infobarMainRow.appendChild(document.createTextNode("\u00a0"));
125 var detailsToggleElement = infobarMainRow.createChild("div", "java-script-source-frame-infobar-toggle");
126 detailsToggleElement.addEventListener("click", toggleDetails.bind(this));
127 updateDetailsVisibility.call(this);
129 function createDetailsRowMessage()
131 var infobarDetailsRow = infobarDetailsContainer.createChild("div", "java-script-source-frame-infobar-details-row");
132 return infobarDetailsRow.createChild("span", "java-script-source-frame-infobar-row-message");
135 var infobarDetailsRowMessage;
137 infobarDetailsRowMessage = createDetailsRowMessage();
138 infobarDetailsRowMessage.appendChild(document.createTextNode(WebInspector.UIString("The content of this file on the file system:\u00a0")));
139 var fileURL = this._uiSourceCode.originURL();
140 infobarDetailsRowMessage.appendChild(WebInspector.linkifyURLAsNode(fileURL, fileURL, "java-script-source-frame-infobar-details-url", true, fileURL));
142 infobarDetailsRowMessage = createDetailsRowMessage();
143 infobarDetailsRowMessage.appendChild(document.createTextNode(WebInspector.UIString("does not match the loaded script:\u00a0")));
144 var scriptURL = this._uiSourceCode.url;
145 infobarDetailsRowMessage.appendChild(WebInspector.linkifyURLAsNode(scriptURL, scriptURL, "java-script-source-frame-infobar-details-url", true, scriptURL));
148 createDetailsRowMessage();
150 createDetailsRowMessage().textContent = WebInspector.UIString("Possible solutions are:");;
152 function createDetailsRowMessageAction(title)
154 infobarDetailsRowMessage = createDetailsRowMessage();
155 infobarDetailsRowMessage.appendChild(document.createTextNode(" - "));
156 infobarDetailsRowMessage.appendChild(document.createTextNode(title));
159 if (WebInspector.settings.cacheDisabled.get())
160 createDetailsRowMessageAction(WebInspector.UIString("Reload inspected page"));
162 createDetailsRowMessageAction(WebInspector.UIString("Check \"Disable cache\" in settings and reload inspected page (recommended setup for authoring and debugging)"));
163 createDetailsRowMessageAction(WebInspector.UIString("Check that your file and script are both loaded from the correct source and their contents match."));
165 this._showInfobar(this._divergedInfobarElement);
168 _hideDivergedInfobar: function()
170 if (!this._divergedInfobarElement)
172 this._hideInfobar(this._divergedInfobarElement);
173 delete this._divergedInfobarElement;
176 _registerShortcuts: function()
178 var shortcutKeys = WebInspector.ShortcutsScreen.SourcesPanelShortcuts;
179 for (var i = 0; i < shortcutKeys.EvaluateSelectionInConsole.length; ++i) {
180 var keyDescriptor = shortcutKeys.EvaluateSelectionInConsole[i];
181 this.addShortcut(keyDescriptor.key, this._evaluateSelectionInConsole.bind(this));
183 for (var i = 0; i < shortcutKeys.AddSelectionToWatch.length; ++i) {
184 var keyDescriptor = shortcutKeys.AddSelectionToWatch[i];
185 this.addShortcut(keyDescriptor.key, this._addCurrentSelectionToWatch.bind(this));
189 _addCurrentSelectionToWatch: function()
191 var textSelection = this.textEditor.selection();
192 if (textSelection && !textSelection.isEmpty())
193 this._innerAddToWatch(this.textEditor.copyRange(textSelection));
197 * @param {string} expression
199 _innerAddToWatch: function(expression)
201 this._scriptsPanel.addToWatch(expression);
207 _evaluateSelectionInConsole: function()
209 var selection = this.textEditor.selection();
210 if (!selection || selection.isEmpty())
212 this._evaluateInConsole(this.textEditor.copyRange(selection));
217 * @param {string} expression
219 _evaluateInConsole: function(expression)
221 var currentExecutionContext = WebInspector.context.flavor(WebInspector.ExecutionContext);
222 if (currentExecutionContext)
223 WebInspector.ConsoleModel.evaluateCommandInConsole(currentExecutionContext, expression);
229 WebInspector.UISourceCodeFrame.prototype.wasShown.call(this);
234 WebInspector.UISourceCodeFrame.prototype.willHide.call(this);
235 this._popoverHelper.hidePopover();
238 onUISourceCodeContentChanged: function()
240 this._removeAllBreakpoints();
241 WebInspector.UISourceCodeFrame.prototype.onUISourceCodeContentChanged.call(this);
244 populateLineGutterContextMenu: function(contextMenu, lineNumber)
246 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Continue to here" : "Continue to Here"), this._continueToLine.bind(this, lineNumber));
247 var breakpoint = this._breakpointManager.findBreakpointOnLine(this._uiSourceCode, lineNumber);
249 // This row doesn't have a breakpoint: We want to show Add Breakpoint and Add and Edit Breakpoint.
250 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Add breakpoint" : "Add Breakpoint"), this._setBreakpoint.bind(this, lineNumber, 0, "", true));
251 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Add conditional breakpoint…" : "Add Conditional Breakpoint…"), this._editBreakpointCondition.bind(this, lineNumber));
253 // This row has a breakpoint, we want to show edit and remove breakpoint, and either disable or enable.
254 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove breakpoint" : "Remove Breakpoint"), breakpoint.remove.bind(breakpoint));
255 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Edit breakpoint…" : "Edit Breakpoint…"), this._editBreakpointCondition.bind(this, lineNumber, breakpoint));
256 if (breakpoint.enabled())
257 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Disable breakpoint" : "Disable Breakpoint"), breakpoint.setEnabled.bind(breakpoint, false));
259 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Enable breakpoint" : "Enable Breakpoint"), breakpoint.setEnabled.bind(breakpoint, true));
263 populateTextAreaContextMenu: function(contextMenu, lineNumber)
265 var textSelection = this.textEditor.selection();
266 if (textSelection && !textSelection.isEmpty()) {
267 var selection = this.textEditor.copyRange(textSelection);
268 var addToWatchLabel = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Add to watch" : "Add to Watch");
269 contextMenu.appendItem(addToWatchLabel, this._innerAddToWatch.bind(this, selection));
270 var evaluateLabel = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Evaluate in console" : "Evaluate in Console");
271 contextMenu.appendItem(evaluateLabel, this._evaluateInConsole.bind(this, selection));
272 contextMenu.appendSeparator();
273 } else if (this._uiSourceCode.project().type() === WebInspector.projectTypes.Debugger) {
274 // FIXME: Change condition above to explicitly check that current uiSourceCode is created by default debugger mapping
275 // and move the code adding this menu item to generic context menu provider for UISourceCode.
276 var liveEditLabel = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Live edit" : "Live Edit");
277 contextMenu.appendItem(liveEditLabel, liveEdit.bind(this));
278 contextMenu.appendSeparator();
282 * @this {WebInspector.JavaScriptSourceFrame}
286 var liveEditUISourceCode = WebInspector.liveEditSupport.uiSourceCodeForLiveEdit(this._uiSourceCode);
287 WebInspector.Revealer.reveal(liveEditUISourceCode.uiLocation(lineNumber));
290 WebInspector.UISourceCodeFrame.prototype.populateTextAreaContextMenu.call(this, contextMenu, lineNumber);
293 _workingCopyChanged: function(event)
295 if (this._supportsEnabledBreakpointsWhileEditing() || this._scriptFile)
298 if (this._uiSourceCode.isDirty())
299 this._muteBreakpointsWhileEditing();
301 this._restoreBreakpointsAfterEditing();
304 _workingCopyCommitted: function(event)
306 if (this._supportsEnabledBreakpointsWhileEditing())
308 if (this._scriptFile) {
309 this._hasCommittedLiveEdit = true;
310 this._scriptFile.commitLiveEdit();
313 this._restoreBreakpointsAfterEditing();
316 _didMergeToVM: function()
318 if (this._supportsEnabledBreakpointsWhileEditing())
320 this._updateDivergedInfobar();
321 this._restoreBreakpointsAfterEditing();
324 _didDivergeFromVM: function()
326 if (this._supportsEnabledBreakpointsWhileEditing())
328 this._updateDivergedInfobar();
329 this._muteBreakpointsWhileEditing();
332 _muteBreakpointsWhileEditing: function()
336 for (var lineNumber = 0; lineNumber < this._textEditor.linesCount; ++lineNumber) {
337 var breakpointDecoration = this._textEditor.getAttribute(lineNumber, "breakpoint");
338 if (!breakpointDecoration)
340 this._removeBreakpointDecoration(lineNumber);
341 this._addBreakpointDecoration(lineNumber, breakpointDecoration.columnNumber, breakpointDecoration.condition, breakpointDecoration.enabled, true);
346 _updateDivergedInfobar: function()
348 if (this._uiSourceCode.project().type() !== WebInspector.projectTypes.FileSystem) {
349 this._hideDivergedInfobar();
352 if (this._divergedInfobarElement) {
353 if (!this._scriptFile || !this._scriptFile.hasDivergedFromVM() || this._hasCommittedLiveEdit)
354 this._hideDivergedInfobar();
356 if (this._scriptFile && this._scriptFile.hasDivergedFromVM() && !this._uiSourceCode.isDirty() && !this._hasCommittedLiveEdit)
357 this._showDivergedInfobar();
361 _supportsEnabledBreakpointsWhileEditing: function()
363 return this._uiSourceCode.project().type() === WebInspector.projectTypes.Snippets;
366 _restoreBreakpointsAfterEditing: function()
369 var breakpoints = {};
370 // Save and remove muted breakpoint decorations.
371 for (var lineNumber = 0; lineNumber < this._textEditor.linesCount; ++lineNumber) {
372 var breakpointDecoration = this._textEditor.getAttribute(lineNumber, "breakpoint");
373 if (breakpointDecoration) {
374 breakpoints[lineNumber] = breakpointDecoration;
375 this._removeBreakpointDecoration(lineNumber);
379 // Remove all breakpoints.
380 this._removeAllBreakpoints();
382 // Restore all breakpoints from saved decorations.
383 for (var lineNumberString in breakpoints) {
384 var lineNumber = parseInt(lineNumberString, 10);
385 if (isNaN(lineNumber))
387 var breakpointDecoration = breakpoints[lineNumberString];
388 this._setBreakpoint(lineNumber, breakpointDecoration.columnNumber, breakpointDecoration.condition, breakpointDecoration.enabled);
392 _removeAllBreakpoints: function()
394 var breakpoints = this._breakpointManager.breakpointsForUISourceCode(this._uiSourceCode);
395 for (var i = 0; i < breakpoints.length; ++i)
396 breakpoints[i].remove();
399 _getPopoverAnchor: function(element, event)
401 if (!WebInspector.debuggerModel.isPaused())
404 var textPosition = this.textEditor.coordinatesToCursorPosition(event.x, event.y);
407 var mouseLine = textPosition.startLine;
408 var mouseColumn = textPosition.startColumn;
409 var textSelection = this.textEditor.selection().normalize();
410 if (textSelection && !textSelection.isEmpty()) {
411 if (textSelection.startLine !== textSelection.endLine || textSelection.startLine !== mouseLine || mouseColumn < textSelection.startColumn || mouseColumn > textSelection.endColumn)
414 var leftCorner = this.textEditor.cursorPositionToCoordinates(textSelection.startLine, textSelection.startColumn);
415 var rightCorner = this.textEditor.cursorPositionToCoordinates(textSelection.endLine, textSelection.endColumn);
416 var anchorBox = new AnchorBox(leftCorner.x, leftCorner.y, rightCorner.x - leftCorner.x, leftCorner.height);
417 anchorBox.highlight = {
418 lineNumber: textSelection.startLine,
419 startColumn: textSelection.startColumn,
420 endColumn: textSelection.endColumn - 1
422 anchorBox.forSelection = true;
426 var token = this.textEditor.tokenAtTextPosition(textPosition.startLine, textPosition.startColumn);
429 var lineNumber = textPosition.startLine;
430 var line = this.textEditor.line(lineNumber);
431 var tokenContent = line.substring(token.startColumn, token.endColumn + 1);
433 var isIdentifier = token.type.startsWith("js-variable") || token.type.startsWith("js-property") || token.type == "js-def";
434 if (!isIdentifier && (token.type !== "js-keyword" || tokenContent !== "this"))
437 var leftCorner = this.textEditor.cursorPositionToCoordinates(lineNumber, token.startColumn);
438 var rightCorner = this.textEditor.cursorPositionToCoordinates(lineNumber, token.endColumn + 1);
439 var anchorBox = new AnchorBox(leftCorner.x, leftCorner.y, rightCorner.x - leftCorner.x, leftCorner.height);
441 anchorBox.highlight = {
442 lineNumber: lineNumber,
443 startColumn: token.startColumn,
444 endColumn: token.endColumn
450 _resolveObjectForPopover: function(anchorBox, showCallback, objectGroupName)
452 if (!WebInspector.debuggerModel.isPaused()) {
453 this._popoverHelper.hidePopover();
456 var lineNumber = anchorBox.highlight.lineNumber;
457 var startHighlight = anchorBox.highlight.startColumn;
458 var endHighlight = anchorBox.highlight.endColumn;
459 var line = this.textEditor.line(lineNumber);
460 if (!anchorBox.forSelection) {
461 while (startHighlight > 1 && line.charAt(startHighlight - 1) === '.') {
462 var token = this.textEditor.tokenAtTextPosition(lineNumber, startHighlight - 2);
464 this._popoverHelper.hidePopover();
467 startHighlight = token.startColumn;
470 var evaluationText = line.substring(startHighlight, endHighlight + 1);
471 var selectedCallFrame = WebInspector.debuggerModel.selectedCallFrame();
472 selectedCallFrame.evaluate(evaluationText, objectGroupName, false, true, false, false, showObjectPopover.bind(this));
475 * @param {?RuntimeAgent.RemoteObject} result
476 * @param {boolean=} wasThrown
477 * @this {WebInspector.JavaScriptSourceFrame}
479 function showObjectPopover(result, wasThrown)
481 if (!WebInspector.debuggerModel.isPaused() || !result) {
482 this._popoverHelper.hidePopover();
485 this._popoverAnchorBox = anchorBox;
486 showCallback(selectedCallFrame.target().runtimeModel.createRemoteObject(result), wasThrown, this._popoverAnchorBox);
487 // Popover may have been removed by showCallback().
488 if (this._popoverAnchorBox) {
489 var highlightRange = new WebInspector.TextRange(lineNumber, startHighlight, lineNumber, endHighlight);
490 this._popoverAnchorBox._highlightDescriptor = this.textEditor.highlightRange(highlightRange, "source-frame-eval-expression");
495 _onHidePopover: function()
497 if (!this._popoverAnchorBox)
499 if (this._popoverAnchorBox._highlightDescriptor)
500 this.textEditor.removeHighlight(this._popoverAnchorBox._highlightDescriptor);
501 delete this._popoverAnchorBox;
505 * @param {number} lineNumber
506 * @param {number} columnNumber
507 * @param {string} condition
508 * @param {boolean} enabled
509 * @param {boolean} mutedWhileEditing
511 _addBreakpointDecoration: function(lineNumber, columnNumber, condition, enabled, mutedWhileEditing)
514 condition: condition,
516 columnNumber: columnNumber
519 this.textEditor.setAttribute(lineNumber, "breakpoint", breakpoint);
521 var disabled = !enabled || mutedWhileEditing;
522 this.textEditor.addBreakpoint(lineNumber, disabled, !!condition);
525 _removeBreakpointDecoration: function(lineNumber)
527 this.textEditor.removeAttribute(lineNumber, "breakpoint");
528 this.textEditor.removeBreakpoint(lineNumber);
531 _onKeyDown: function(event)
533 if (event.keyIdentifier === "U+001B") { // Escape key
534 if (this._popoverHelper.isPopoverVisible()) {
535 this._popoverHelper.hidePopover();
542 * @param {number} lineNumber
543 * @param {!WebInspector.BreakpointManager.Breakpoint=} breakpoint
545 _editBreakpointCondition: function(lineNumber, breakpoint)
547 this._conditionElement = this._createConditionElement(lineNumber);
548 this.textEditor.addDecoration(lineNumber, this._conditionElement);
551 * @this {WebInspector.JavaScriptSourceFrame}
553 function finishEditing(committed, element, newText)
555 this.textEditor.removeDecoration(lineNumber, this._conditionElement);
556 delete this._conditionEditorElement;
557 delete this._conditionElement;
562 breakpoint.setCondition(newText);
564 this._setBreakpoint(lineNumber, 0, newText, true);
567 var config = new WebInspector.InplaceEditor.Config(finishEditing.bind(this, true), finishEditing.bind(this, false));
568 WebInspector.InplaceEditor.startEditing(this._conditionEditorElement, config);
569 this._conditionEditorElement.value = breakpoint ? breakpoint.condition() : "";
570 this._conditionEditorElement.select();
573 _createConditionElement: function(lineNumber)
575 var conditionElement = document.createElement("div");
576 conditionElement.className = "source-frame-breakpoint-condition";
578 var labelElement = document.createElement("label");
579 labelElement.className = "source-frame-breakpoint-message";
580 labelElement.htmlFor = "source-frame-breakpoint-condition";
581 labelElement.appendChild(document.createTextNode(WebInspector.UIString("The breakpoint on line %d will stop only if this expression is true:", lineNumber)));
582 conditionElement.appendChild(labelElement);
584 var editorElement = document.createElement("input");
585 editorElement.id = "source-frame-breakpoint-condition";
586 editorElement.className = "monospace";
587 editorElement.type = "text";
588 conditionElement.appendChild(editorElement);
589 this._conditionEditorElement = editorElement;
591 return conditionElement;
595 * @param {number} lineNumber
597 setExecutionLine: function(lineNumber)
599 this._executionLineNumber = lineNumber;
601 this.textEditor.setExecutionLine(lineNumber);
604 clearExecutionLine: function()
606 if (this.loaded && typeof this._executionLineNumber === "number")
607 this.textEditor.clearExecutionLine();
608 delete this._executionLineNumber;
614 _shouldIgnoreExternalBreakpointEvents: function()
616 if (this._supportsEnabledBreakpointsWhileEditing())
620 return this._scriptFile && (this._scriptFile.isDivergingFromVM() || this._scriptFile.isMergingToVM());
623 _breakpointAdded: function(event)
625 var uiLocation = /** @type {!WebInspector.UILocation} */ (event.data.uiLocation);
626 if (uiLocation.uiSourceCode !== this._uiSourceCode)
628 if (this._shouldIgnoreExternalBreakpointEvents())
631 var breakpoint = /** @type {!WebInspector.BreakpointManager.Breakpoint} */ (event.data.breakpoint);
633 this._addBreakpointDecoration(uiLocation.lineNumber, uiLocation.columnNumber, breakpoint.condition(), breakpoint.enabled(), false);
636 _breakpointRemoved: function(event)
638 var uiLocation = /** @type {!WebInspector.UILocation} */ (event.data.uiLocation);
639 if (uiLocation.uiSourceCode !== this._uiSourceCode)
641 if (this._shouldIgnoreExternalBreakpointEvents())
644 var breakpoint = /** @type {!WebInspector.BreakpointManager.Breakpoint} */ (event.data.breakpoint);
645 var remainingBreakpoint = this._breakpointManager.findBreakpointOnLine(this._uiSourceCode, uiLocation.lineNumber);
646 if (!remainingBreakpoint && this.loaded)
647 this._removeBreakpointDecoration(uiLocation.lineNumber);
650 _consoleMessageAdded: function(event)
652 var message = /** @type {!WebInspector.PresentationConsoleMessage} */ (event.data);
654 this.addMessageToSource(message.lineNumber, message.originalMessage);
657 _consoleMessageRemoved: function(event)
659 var message = /** @type {!WebInspector.PresentationConsoleMessage} */ (event.data);
661 this.removeMessageFromSource(message.lineNumber, message.originalMessage);
664 _consoleMessagesCleared: function(event)
666 this.clearMessages();
670 * @param {!WebInspector.Event} event
672 _onSourceMappingChanged: function(event)
674 this._updateScriptFile();
677 _updateScriptFile: function()
679 if (this._scriptFile) {
680 this._scriptFile.removeEventListener(WebInspector.ScriptFile.Events.DidMergeToVM, this._didMergeToVM, this);
681 this._scriptFile.removeEventListener(WebInspector.ScriptFile.Events.DidDivergeFromVM, this._didDivergeFromVM, this);
682 if (this._muted && !this._uiSourceCode.isDirty())
683 this._restoreBreakpointsAfterEditing();
685 delete this._hasCommittedLiveEdit;
686 this._scriptFile = this._uiSourceCode.scriptFile();
687 this._updateDivergedInfobar();
688 if (this._scriptFile) {
689 this._scriptFile.addEventListener(WebInspector.ScriptFile.Events.DidMergeToVM, this._didMergeToVM, this);
690 this._scriptFile.addEventListener(WebInspector.ScriptFile.Events.DidDivergeFromVM, this._didDivergeFromVM, this);
693 this._scriptFile.checkMapping();
697 onTextEditorContentLoaded: function()
699 if (typeof this._executionLineNumber === "number")
700 this.setExecutionLine(this._executionLineNumber);
702 var breakpointLocations = this._breakpointManager.breakpointLocationsForUISourceCode(this._uiSourceCode);
703 for (var i = 0; i < breakpointLocations.length; ++i)
704 this._breakpointAdded({data:breakpointLocations[i]});
706 var messages = this._uiSourceCode.consoleMessages();
707 for (var i = 0; i < messages.length; ++i) {
708 var message = messages[i];
709 this.addMessageToSource(message.lineNumber, message.originalMessage);
712 if (this._scriptFile)
713 this._scriptFile.checkMapping();
717 * @param {!WebInspector.Event} event
719 _handleGutterClick: function(event)
724 var eventData = /** @type {!WebInspector.TextEditor.GutterClickEventData} */ (event.data);
725 var lineNumber = eventData.lineNumber;
726 var eventObject = /** @type {!Event} */ (eventData.event);
728 if (eventObject.button != 0 || eventObject.altKey || eventObject.ctrlKey || eventObject.metaKey)
731 this._toggleBreakpoint(lineNumber, eventObject.shiftKey);
732 eventObject.consume(true);
736 * @param {number} lineNumber
737 * @param {boolean} onlyDisable
739 _toggleBreakpoint: function(lineNumber, onlyDisable)
741 var breakpoint = this._breakpointManager.findBreakpointOnLine(this._uiSourceCode, lineNumber);
744 breakpoint.setEnabled(!breakpoint.enabled());
748 this._setBreakpoint(lineNumber, 0, "", true);
751 toggleBreakpointOnCurrentLine: function()
756 var selection = this.textEditor.selection();
759 this._toggleBreakpoint(selection.startLine, false);
763 * @param {number} lineNumber
764 * @param {number} columnNumber
765 * @param {string} condition
766 * @param {boolean} enabled
768 _setBreakpoint: function(lineNumber, columnNumber, condition, enabled)
770 this._breakpointManager.setBreakpoint(this._uiSourceCode, lineNumber, columnNumber, condition, enabled);
772 WebInspector.notifications.dispatchEventToListeners(WebInspector.UserMetrics.UserAction, {
773 action: WebInspector.UserMetrics.UserActionNames.SetBreakpoint,
774 url: this._uiSourceCode.originURL(),
781 * @param {number} lineNumber
783 _continueToLine: function(lineNumber)
785 var rawLocation = /** @type {!WebInspector.DebuggerModel.Location} */ (this._uiSourceCode.uiLocationToRawLocation(lineNumber, 0));
786 rawLocation.continueToLocation();
791 this._breakpointManager.removeEventListener(WebInspector.BreakpointManager.Events.BreakpointAdded, this._breakpointAdded, this);
792 this._breakpointManager.removeEventListener(WebInspector.BreakpointManager.Events.BreakpointRemoved, this._breakpointRemoved, this);
793 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.ConsoleMessageAdded, this._consoleMessageAdded, this);
794 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.ConsoleMessageRemoved, this._consoleMessageRemoved, this);
795 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.ConsoleMessagesCleared, this._consoleMessagesCleared, this);
796 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._onSourceMappingChanged, this);
797 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this);
798 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._workingCopyCommitted, this);
799 WebInspector.UISourceCodeFrame.prototype.dispose.call(this);
802 __proto__: WebInspector.UISourceCodeFrame.prototype