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 WebInspector.presentationConsoleMessageHelper.addConsoleMessageEventListener(WebInspector.PresentationConsoleMessageHelper.Events.ConsoleMessageAdded, this._uiSourceCode, this._consoleMessageAdded, this);
58 WebInspector.presentationConsoleMessageHelper.addConsoleMessageEventListener(WebInspector.PresentationConsoleMessageHelper.Events.ConsoleMessageRemoved, this._uiSourceCode, this._consoleMessageRemoved, this);
59 WebInspector.presentationConsoleMessageHelper.addConsoleMessageEventListener(WebInspector.PresentationConsoleMessageHelper.Events.ConsoleMessagesCleared, this._uiSourceCode, 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);
63 this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._showBlackboxInfobarIfNeeded, this);
65 /** @type {!Map.<!WebInspector.Target, !WebInspector.ResourceScriptFile>}*/
66 this._scriptFileForTarget = new Map();
67 this._registerShortcuts();
68 var targets = WebInspector.targetManager.targets();
69 for (var i = 0; i < targets.length; ++i) {
70 var scriptFile = WebInspector.debuggerWorkspaceBinding.scriptFile(uiSourceCode, targets[i]);
72 this._updateScriptFile(targets[i]);
75 WebInspector.settings.skipStackFramesPattern.addChangeListener(this._showBlackboxInfobarIfNeeded, this);
76 WebInspector.settings.skipContentScripts.addChangeListener(this._showBlackboxInfobarIfNeeded, this);
77 this._showBlackboxInfobarIfNeeded();
80 WebInspector.JavaScriptSourceFrame.prototype = {
81 _updateInfobars: function()
83 this.attachInfobars([this._blackboxInfobar, this._divergedInfobar]);
86 _showDivergedInfobar: function()
88 if (this._uiSourceCode.contentType() !== WebInspector.resourceTypes.Script)
91 if (this._divergedInfobar)
92 this._divergedInfobar.dispose();
94 var infobar = new WebInspector.UISourceCodeFrame.Infobar(WebInspector.UISourceCodeFrame.Infobar.Level.Warning, WebInspector.UIString("Workspace mapping mismatch"));
95 this._divergedInfobar = infobar;
97 var fileURL = this._uiSourceCode.originURL();
98 infobar.createDetailsRowMessage(WebInspector.UIString("The content of this file on the file system:\u00a0")).appendChild(
99 WebInspector.linkifyURLAsNode(fileURL, fileURL, "source-frame-infobar-details-url", true, fileURL));
101 var scriptURL = this._uiSourceCode.url;
102 infobar.createDetailsRowMessage(WebInspector.UIString("does not match the loaded script:\u00a0")).appendChild(
103 WebInspector.linkifyURLAsNode(scriptURL, scriptURL, "source-frame-infobar-details-url", true, scriptURL));
105 infobar.createDetailsRowMessage();
106 infobar.createDetailsRowMessage(WebInspector.UIString("Possible solutions are:"));
108 if (WebInspector.settings.cacheDisabled.get())
109 infobar.createDetailsRowMessage(" - ").createTextChild(WebInspector.UIString("Reload inspected page"));
111 infobar.createDetailsRowMessage(" - ").createTextChild(WebInspector.UIString("Check \"Disable cache\" in settings and reload inspected page (recommended setup for authoring and debugging)"));
112 infobar.createDetailsRowMessage(" - ").createTextChild(WebInspector.UIString("Check that your file and script are both loaded from the correct source and their contents match"));
114 this._updateInfobars();
117 _hideDivergedInfobar: function()
119 if (!this._divergedInfobar)
121 this._divergedInfobar.dispose();
122 delete this._divergedInfobar;
125 _showBlackboxInfobarIfNeeded: function()
127 var contentType = this._uiSourceCode.contentType();
128 if (contentType !== WebInspector.resourceTypes.Script && contentType !== WebInspector.resourceTypes.Document)
130 var projectType = this._uiSourceCode.project().type();
131 if (projectType === WebInspector.projectTypes.Snippets)
133 var url = this._uiSourceCode.url;
134 var isContentScript = projectType === WebInspector.projectTypes.ContentScripts;
135 if (!WebInspector.BlackboxSupport.isBlackboxed(url, isContentScript)) {
136 this._hideBlackboxInfobar();
140 if (this._blackboxInfobar)
141 this._blackboxInfobar.dispose();
143 var infobar = new WebInspector.UISourceCodeFrame.Infobar(WebInspector.UISourceCodeFrame.Infobar.Level.Warning, WebInspector.UIString("This script is blackboxed in debugger"));
144 this._blackboxInfobar = infobar;
146 infobar.createDetailsRowMessage(WebInspector.UIString("Debugger will skip stepping through this script, and will not stop on exceptions"));
147 infobar.createDetailsRowMessage();
148 infobar.createDetailsRowMessage(WebInspector.UIString("Possible ways to cancel this behavior are:"));
150 infobar.createDetailsRowMessage(" - ").createTextChild(WebInspector.UIString("Press \"%s\" button in settings", WebInspector.manageBlackboxingButtonLabel()));
151 var unblackboxLink = infobar.createDetailsRowMessage(" - ").createChild("span", "source-frame-infobar-link");
152 unblackboxLink.textContent = WebInspector.UIString("Unblackbox this script");
153 unblackboxLink.addEventListener("click", unblackbox, false);
155 function unblackbox()
157 WebInspector.BlackboxSupport.unblackbox(url, isContentScript);
160 this._updateInfobars();
163 _hideBlackboxInfobar: function()
165 if (!this._blackboxInfobar)
167 this._blackboxInfobar.dispose();
168 delete this._blackboxInfobar;
171 _registerShortcuts: function()
173 var shortcutKeys = WebInspector.ShortcutsScreen.SourcesPanelShortcuts;
174 for (var i = 0; i < shortcutKeys.EvaluateSelectionInConsole.length; ++i) {
175 var keyDescriptor = shortcutKeys.EvaluateSelectionInConsole[i];
176 this.addShortcut(keyDescriptor.key, this._evaluateSelectionInConsole.bind(this));
178 for (var i = 0; i < shortcutKeys.AddSelectionToWatch.length; ++i) {
179 var keyDescriptor = shortcutKeys.AddSelectionToWatch[i];
180 this.addShortcut(keyDescriptor.key, this._addCurrentSelectionToWatch.bind(this));
184 _addCurrentSelectionToWatch: function()
186 var textSelection = this.textEditor.selection();
187 if (textSelection && !textSelection.isEmpty())
188 this._innerAddToWatch(this.textEditor.copyRange(textSelection));
193 * @param {string} expression
195 _innerAddToWatch: function(expression)
197 this._scriptsPanel.addToWatch(expression);
203 _evaluateSelectionInConsole: function()
205 var selection = this.textEditor.selection();
206 if (!selection || selection.isEmpty())
208 this._evaluateInConsole(this.textEditor.copyRange(selection));
213 * @param {string} expression
215 _evaluateInConsole: function(expression)
217 var currentExecutionContext = WebInspector.context.flavor(WebInspector.ExecutionContext);
218 if (currentExecutionContext)
219 WebInspector.ConsoleModel.evaluateCommandInConsole(currentExecutionContext, expression);
225 WebInspector.UISourceCodeFrame.prototype.wasShown.call(this);
230 WebInspector.UISourceCodeFrame.prototype.willHide.call(this);
231 this._popoverHelper.hidePopover();
234 onUISourceCodeContentChanged: function()
236 this._removeAllBreakpoints();
237 WebInspector.UISourceCodeFrame.prototype.onUISourceCodeContentChanged.call(this);
240 onTextChanged: function(oldRange, newRange)
242 this._scriptsPanel.setIgnoreExecutionLineEvents(true);
243 WebInspector.UISourceCodeFrame.prototype.onTextChanged.call(this, oldRange, newRange);
244 this._scriptsPanel.setIgnoreExecutionLineEvents(false);
247 populateLineGutterContextMenu: function(contextMenu, lineNumber)
249 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Continue to here" : "Continue to Here"), this._continueToLine.bind(this, lineNumber));
250 var breakpoint = this._breakpointManager.findBreakpointOnLine(this._uiSourceCode, lineNumber);
252 // This row doesn't have a breakpoint: We want to show Add Breakpoint and Add and Edit Breakpoint.
253 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Add breakpoint" : "Add Breakpoint"), this._setBreakpoint.bind(this, lineNumber, 0, "", true));
254 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Add conditional breakpoint…" : "Add Conditional Breakpoint…"), this._editBreakpointCondition.bind(this, lineNumber));
256 // This row has a breakpoint, we want to show edit and remove breakpoint, and either disable or enable.
257 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove breakpoint" : "Remove Breakpoint"), breakpoint.remove.bind(breakpoint));
258 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Edit breakpoint…" : "Edit Breakpoint…"), this._editBreakpointCondition.bind(this, lineNumber, breakpoint));
259 if (breakpoint.enabled())
260 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Disable breakpoint" : "Disable Breakpoint"), breakpoint.setEnabled.bind(breakpoint, false));
262 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Enable breakpoint" : "Enable Breakpoint"), breakpoint.setEnabled.bind(breakpoint, true));
266 populateTextAreaContextMenu: function(contextMenu, lineNumber)
268 var textSelection = this.textEditor.selection();
269 if (textSelection && !textSelection.isEmpty()) {
270 var selection = this.textEditor.copyRange(textSelection);
271 var addToWatchLabel = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Add to watch" : "Add to Watch");
272 contextMenu.appendItem(addToWatchLabel, this._innerAddToWatch.bind(this, selection));
273 var evaluateLabel = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Evaluate in console" : "Evaluate in Console");
274 contextMenu.appendItem(evaluateLabel, this._evaluateInConsole.bind(this, selection));
275 contextMenu.appendSeparator();
276 } else if (this._uiSourceCode.project().type() === WebInspector.projectTypes.Debugger) {
277 // FIXME: Change condition above to explicitly check that current uiSourceCode is created by default debugger mapping
278 // and move the code adding this menu item to generic context menu provider for UISourceCode.
279 var liveEditLabel = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Live edit" : "Live Edit");
280 var liveEditSupport = WebInspector.LiveEditSupport.liveEditSupportForUISourceCode(this._uiSourceCode);
281 if (!liveEditSupport)
284 contextMenu.appendItem(liveEditLabel, liveEdit.bind(this, liveEditSupport));
285 contextMenu.appendSeparator();
289 * @this {WebInspector.JavaScriptSourceFrame}
290 * @param {!WebInspector.LiveEditSupport} liveEditSupport
292 function liveEdit(liveEditSupport)
294 var liveEditUISourceCode = liveEditSupport.uiSourceCodeForLiveEdit(this._uiSourceCode);
295 if (!liveEditUISourceCode)
297 WebInspector.Revealer.reveal(liveEditUISourceCode.uiLocation(lineNumber));
301 * @this {WebInspector.JavaScriptSourceFrame}
302 * @param {!WebInspector.ResourceScriptFile} scriptFile
304 function addSourceMapURL(scriptFile)
306 WebInspector.AddSourceMapURLDialog.show(this.element, addSourceMapURLDialogCallback.bind(null, scriptFile));
310 * @param {!WebInspector.ResourceScriptFile} scriptFile
311 * @param {string} url
313 function addSourceMapURLDialogCallback(scriptFile, url)
317 scriptFile.addSourceMapURL(url);
320 WebInspector.UISourceCodeFrame.prototype.populateTextAreaContextMenu.call(this, contextMenu, lineNumber);
322 if (this._uiSourceCode.project().type() === WebInspector.projectTypes.Network && WebInspector.settings.jsSourceMapsEnabled.get()) {
323 if (this._scriptFileForTarget.size) {
324 var scriptFile = this._scriptFileForTarget.values()[0];
325 var addSourceMapURLLabel = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Add source map\u2026" : "Add Source Map\u2026");
326 contextMenu.appendItem(addSourceMapURLLabel, addSourceMapURL.bind(this, scriptFile));
327 contextMenu.appendSeparator();
332 _workingCopyChanged: function(event)
334 if (this._supportsEnabledBreakpointsWhileEditing() || this._scriptFileForTarget.size)
337 if (this._uiSourceCode.isDirty())
338 this._muteBreakpointsWhileEditing();
340 this._restoreBreakpointsAfterEditing();
343 _workingCopyCommitted: function(event)
345 if (this._supportsEnabledBreakpointsWhileEditing())
348 if (!this._scriptFileForTarget.size) {
349 this._restoreBreakpointsAfterEditing();
354 var liveEditErrorData;
356 var succeededEdits = 0;
360 * @this {WebInspector.JavaScriptSourceFrame}
361 * @param {?string} error
362 * @param {!DebuggerAgent.SetScriptSourceError=} errorData
363 * @param {!WebInspector.Script=} script
365 function liveEditCallback(error, errorData, script)
368 liveEditError = error;
369 liveEditErrorData = errorData;
370 contextScript = script;
375 if (succeededEdits + failedEdits !== scriptFiles.length)
379 WebInspector.LiveEditSupport.logSuccess();
381 WebInspector.LiveEditSupport.logDetailedError(liveEditError, liveEditErrorData, contextScript)
382 this._scriptsPanel.setIgnoreExecutionLineEvents(false);
385 this._scriptsPanel.setIgnoreExecutionLineEvents(true);
386 this._hasCommittedLiveEdit = true;
387 var scriptFiles = this._scriptFileForTarget.values();
388 for (var i = 0; i < scriptFiles.length; ++i)
389 scriptFiles[i].commitLiveEdit(liveEditCallback.bind(this));
392 _didMergeToVM: function()
394 if (this._supportsEnabledBreakpointsWhileEditing())
396 this._updateDivergedInfobar();
397 this._restoreBreakpointsIfConsistentScripts();
400 _didDivergeFromVM: function()
402 if (this._supportsEnabledBreakpointsWhileEditing())
404 this._updateDivergedInfobar();
405 this._muteBreakpointsWhileEditing();
408 _muteBreakpointsWhileEditing: function()
412 for (var lineNumber = 0; lineNumber < this._textEditor.linesCount; ++lineNumber) {
413 var breakpointDecoration = this._textEditor.getAttribute(lineNumber, "breakpoint");
414 if (!breakpointDecoration)
416 this._removeBreakpointDecoration(lineNumber);
417 this._addBreakpointDecoration(lineNumber, breakpointDecoration.columnNumber, breakpointDecoration.condition, breakpointDecoration.enabled, true);
422 _updateDivergedInfobar: function()
424 if (this._uiSourceCode.project().type() !== WebInspector.projectTypes.FileSystem) {
425 this._hideDivergedInfobar();
429 var scriptFiles = this._scriptFileForTarget.values();
430 var hasDivergedScript = false;
431 for (var i = 0; i < scriptFiles.length; ++i)
432 hasDivergedScript = hasDivergedScript || scriptFiles[i].hasDivergedFromVM();
434 if (this._divergedInfobar) {
435 if (!hasDivergedScript || this._hasCommittedLiveEdit)
436 this._hideDivergedInfobar();
438 if (hasDivergedScript && !this._uiSourceCode.isDirty() && !this._hasCommittedLiveEdit)
439 this._showDivergedInfobar();
443 _supportsEnabledBreakpointsWhileEditing: function()
445 return this._uiSourceCode.project().type() === WebInspector.projectTypes.Snippets;
448 _restoreBreakpointsIfConsistentScripts: function()
450 var scriptFiles = this._scriptFileForTarget.values();
451 for (var i = 0; i < scriptFiles.length; ++i)
452 if (scriptFiles[i].hasDivergedFromVM() || scriptFiles[i].isMergingToVM())
455 this._restoreBreakpointsAfterEditing();
458 _restoreBreakpointsAfterEditing: function()
461 var breakpoints = {};
462 // Save and remove muted breakpoint decorations.
463 for (var lineNumber = 0; lineNumber < this._textEditor.linesCount; ++lineNumber) {
464 var breakpointDecoration = this._textEditor.getAttribute(lineNumber, "breakpoint");
465 if (breakpointDecoration) {
466 breakpoints[lineNumber] = breakpointDecoration;
467 this._removeBreakpointDecoration(lineNumber);
471 // Remove all breakpoints.
472 this._removeAllBreakpoints();
474 // Restore all breakpoints from saved decorations.
475 for (var lineNumberString in breakpoints) {
476 var lineNumber = parseInt(lineNumberString, 10);
477 if (isNaN(lineNumber))
479 var breakpointDecoration = breakpoints[lineNumberString];
480 this._setBreakpoint(lineNumber, breakpointDecoration.columnNumber, breakpointDecoration.condition, breakpointDecoration.enabled);
484 _removeAllBreakpoints: function()
486 var breakpoints = this._breakpointManager.breakpointsForUISourceCode(this._uiSourceCode);
487 for (var i = 0; i < breakpoints.length; ++i)
488 breakpoints[i].remove();
491 _getPopoverAnchor: function(element, event)
493 var target = WebInspector.context.flavor(WebInspector.Target);
494 if (!target || !target.debuggerModel.isPaused())
497 var textPosition = this.textEditor.coordinatesToCursorPosition(event.x, event.y);
500 var mouseLine = textPosition.startLine;
501 var mouseColumn = textPosition.startColumn;
502 var textSelection = this.textEditor.selection().normalize();
503 if (textSelection && !textSelection.isEmpty()) {
504 if (textSelection.startLine !== textSelection.endLine || textSelection.startLine !== mouseLine || mouseColumn < textSelection.startColumn || mouseColumn > textSelection.endColumn)
507 var leftCorner = this.textEditor.cursorPositionToCoordinates(textSelection.startLine, textSelection.startColumn);
508 var rightCorner = this.textEditor.cursorPositionToCoordinates(textSelection.endLine, textSelection.endColumn);
509 var anchorBox = new AnchorBox(leftCorner.x, leftCorner.y, rightCorner.x - leftCorner.x, leftCorner.height);
510 anchorBox.highlight = {
511 lineNumber: textSelection.startLine,
512 startColumn: textSelection.startColumn,
513 endColumn: textSelection.endColumn - 1
515 anchorBox.forSelection = true;
519 var token = this.textEditor.tokenAtTextPosition(textPosition.startLine, textPosition.startColumn);
522 var lineNumber = textPosition.startLine;
523 var line = this.textEditor.line(lineNumber);
524 var tokenContent = line.substring(token.startColumn, token.endColumn);
526 var isIdentifier = token.type.startsWith("js-variable") || token.type.startsWith("js-property") || token.type == "js-def";
527 if (!isIdentifier && (token.type !== "js-keyword" || tokenContent !== "this"))
530 var leftCorner = this.textEditor.cursorPositionToCoordinates(lineNumber, token.startColumn);
531 var rightCorner = this.textEditor.cursorPositionToCoordinates(lineNumber, token.endColumn - 1);
532 var anchorBox = new AnchorBox(leftCorner.x, leftCorner.y, rightCorner.x - leftCorner.x, leftCorner.height);
534 anchorBox.highlight = {
535 lineNumber: lineNumber,
536 startColumn: token.startColumn,
537 endColumn: token.endColumn - 1
543 _resolveObjectForPopover: function(anchorBox, showCallback, objectGroupName)
545 var target = WebInspector.context.flavor(WebInspector.Target);
546 if (!target || !target.debuggerModel.isPaused()) {
547 this._popoverHelper.hidePopover();
550 var lineNumber = anchorBox.highlight.lineNumber;
551 var startHighlight = anchorBox.highlight.startColumn;
552 var endHighlight = anchorBox.highlight.endColumn;
553 var line = this.textEditor.line(lineNumber);
554 if (!anchorBox.forSelection) {
555 while (startHighlight > 1 && line.charAt(startHighlight - 1) === '.') {
556 var token = this.textEditor.tokenAtTextPosition(lineNumber, startHighlight - 2);
558 this._popoverHelper.hidePopover();
561 startHighlight = token.startColumn;
564 var evaluationText = line.substring(startHighlight, endHighlight + 1);
565 var selectedCallFrame = target.debuggerModel.selectedCallFrame();
566 selectedCallFrame.evaluate(evaluationText, objectGroupName, false, true, false, false, showObjectPopover.bind(this));
569 * @param {?RuntimeAgent.RemoteObject} result
570 * @param {boolean=} wasThrown
571 * @this {WebInspector.JavaScriptSourceFrame}
573 function showObjectPopover(result, wasThrown)
575 var target = WebInspector.context.flavor(WebInspector.Target);
576 if (selectedCallFrame.target() != target || !target.debuggerModel.isPaused() || !result) {
577 this._popoverHelper.hidePopover();
580 this._popoverAnchorBox = anchorBox;
581 showCallback(target.runtimeModel.createRemoteObject(result), wasThrown, this._popoverAnchorBox);
582 // Popover may have been removed by showCallback().
583 if (this._popoverAnchorBox) {
584 var highlightRange = new WebInspector.TextRange(lineNumber, startHighlight, lineNumber, endHighlight);
585 this._popoverAnchorBox._highlightDescriptor = this.textEditor.highlightRange(highlightRange, "source-frame-eval-expression");
590 _onHidePopover: function()
592 if (!this._popoverAnchorBox)
594 if (this._popoverAnchorBox._highlightDescriptor)
595 this.textEditor.removeHighlight(this._popoverAnchorBox._highlightDescriptor);
596 delete this._popoverAnchorBox;
600 * @param {number} lineNumber
601 * @param {number} columnNumber
602 * @param {string} condition
603 * @param {boolean} enabled
604 * @param {boolean} mutedWhileEditing
606 _addBreakpointDecoration: function(lineNumber, columnNumber, condition, enabled, mutedWhileEditing)
609 condition: condition,
611 columnNumber: columnNumber
614 this.textEditor.setAttribute(lineNumber, "breakpoint", breakpoint);
616 var disabled = !enabled || mutedWhileEditing;
617 this.textEditor.addBreakpoint(lineNumber, disabled, !!condition);
620 _removeBreakpointDecoration: function(lineNumber)
622 this.textEditor.removeAttribute(lineNumber, "breakpoint");
623 this.textEditor.removeBreakpoint(lineNumber);
626 _onKeyDown: function(event)
628 if (event.keyIdentifier === "U+001B") { // Escape key
629 if (this._popoverHelper.isPopoverVisible()) {
630 this._popoverHelper.hidePopover();
637 * @param {number} lineNumber
638 * @param {!WebInspector.BreakpointManager.Breakpoint=} breakpoint
640 _editBreakpointCondition: function(lineNumber, breakpoint)
642 this._conditionElement = this._createConditionElement(lineNumber);
643 this.textEditor.addDecoration(lineNumber, this._conditionElement);
646 * @this {WebInspector.JavaScriptSourceFrame}
648 function finishEditing(committed, element, newText)
650 this.textEditor.removeDecoration(lineNumber, this._conditionElement);
651 delete this._conditionEditorElement;
652 delete this._conditionElement;
657 breakpoint.setCondition(newText);
659 this._setBreakpoint(lineNumber, 0, newText, true);
662 var config = new WebInspector.InplaceEditor.Config(finishEditing.bind(this, true), finishEditing.bind(this, false));
663 WebInspector.InplaceEditor.startEditing(this._conditionEditorElement, config);
664 this._conditionEditorElement.value = breakpoint ? breakpoint.condition() : "";
665 this._conditionEditorElement.select();
668 _createConditionElement: function(lineNumber)
670 var conditionElement = document.createElementWithClass("div", "source-frame-breakpoint-condition");
672 var labelElement = conditionElement.createChild("label", "source-frame-breakpoint-message");
673 labelElement.htmlFor = "source-frame-breakpoint-condition";
674 labelElement.createTextChild(WebInspector.UIString("The breakpoint on line %d will stop only if this expression is true:", lineNumber + 1));
676 var editorElement = conditionElement.createChild("input", "monospace");
677 editorElement.id = "source-frame-breakpoint-condition";
678 editorElement.type = "text";
679 this._conditionEditorElement = editorElement;
681 return conditionElement;
685 * @param {number} lineNumber
687 setExecutionLine: function(lineNumber)
689 this._executionLineNumber = lineNumber;
691 this.textEditor.setExecutionLine(lineNumber);
694 clearExecutionLine: function()
696 if (this.loaded && typeof this._executionLineNumber === "number")
697 this.textEditor.clearExecutionLine();
698 delete this._executionLineNumber;
704 _shouldIgnoreExternalBreakpointEvents: function()
706 if (this._supportsEnabledBreakpointsWhileEditing())
710 var scriptFiles = this._scriptFileForTarget.values();
711 var hasDivergingOrMergingFile = false;
712 for (var i = 0; i < scriptFiles.length; ++i)
713 if (scriptFiles[i].isDivergingFromVM() || scriptFiles[i].isMergingToVM())
718 _breakpointAdded: function(event)
720 var uiLocation = /** @type {!WebInspector.UILocation} */ (event.data.uiLocation);
721 if (uiLocation.uiSourceCode !== this._uiSourceCode)
723 if (this._shouldIgnoreExternalBreakpointEvents())
726 var breakpoint = /** @type {!WebInspector.BreakpointManager.Breakpoint} */ (event.data.breakpoint);
728 this._addBreakpointDecoration(uiLocation.lineNumber, uiLocation.columnNumber, breakpoint.condition(), breakpoint.enabled(), false);
731 _breakpointRemoved: function(event)
733 var uiLocation = /** @type {!WebInspector.UILocation} */ (event.data.uiLocation);
734 if (uiLocation.uiSourceCode !== this._uiSourceCode)
736 if (this._shouldIgnoreExternalBreakpointEvents())
739 var breakpoint = /** @type {!WebInspector.BreakpointManager.Breakpoint} */ (event.data.breakpoint);
740 var remainingBreakpoint = this._breakpointManager.findBreakpointOnLine(this._uiSourceCode, uiLocation.lineNumber);
741 if (!remainingBreakpoint && this.loaded)
742 this._removeBreakpointDecoration(uiLocation.lineNumber);
745 _consoleMessageAdded: function(event)
747 var message = /** @type {!WebInspector.PresentationConsoleMessage} */ (event.data);
749 this.addMessageToSource(message.lineNumber, message.originalMessage);
752 _consoleMessageRemoved: function(event)
754 var message = /** @type {!WebInspector.PresentationConsoleMessage} */ (event.data);
756 this.removeMessageFromSource(message.lineNumber, message.originalMessage);
759 _consoleMessagesCleared: function(event)
761 this.clearMessages();
765 * @param {!WebInspector.Event} event
767 _onSourceMappingChanged: function(event)
769 var data = /** @type {{target: !WebInspector.Target}} */ (event.data);
770 this._updateScriptFile(data.target);
771 this._updateLinesWithoutMappingHighlight();
774 _updateLinesWithoutMappingHighlight: function()
776 var linesCount = this.textEditor.linesCount;
777 for (var i = 0; i < linesCount; ++i)
778 this.textEditor.toggleLineClass(i, "cm-line-without-source-mapping", !WebInspector.debuggerWorkspaceBinding.uiLineHasMapping(this._uiSourceCode, i));
782 * @param {!WebInspector.Target} target
784 _updateScriptFile: function(target)
786 var oldScriptFile = this._scriptFileForTarget.get(target);
787 var newScriptFile = WebInspector.debuggerWorkspaceBinding.scriptFile(this._uiSourceCode, target);
788 this._scriptFileForTarget.remove(target);
790 oldScriptFile.removeEventListener(WebInspector.ResourceScriptFile.Events.DidMergeToVM, this._didMergeToVM, this);
791 oldScriptFile.removeEventListener(WebInspector.ResourceScriptFile.Events.DidDivergeFromVM, this._didDivergeFromVM, this);
792 if (this._muted && !this._uiSourceCode.isDirty())
793 this._restoreBreakpointsIfConsistentScripts();
796 this._scriptFileForTarget.set(target, newScriptFile);
798 delete this._hasCommittedLiveEdit;
799 this._updateDivergedInfobar();
802 newScriptFile.addEventListener(WebInspector.ResourceScriptFile.Events.DidMergeToVM, this._didMergeToVM, this);
803 newScriptFile.addEventListener(WebInspector.ResourceScriptFile.Events.DidDivergeFromVM, this._didDivergeFromVM, this);
805 newScriptFile.checkMapping();
809 onTextEditorContentLoaded: function()
811 if (typeof this._executionLineNumber === "number")
812 this.setExecutionLine(this._executionLineNumber);
814 var breakpointLocations = this._breakpointManager.breakpointLocationsForUISourceCode(this._uiSourceCode);
815 for (var i = 0; i < breakpointLocations.length; ++i)
816 this._breakpointAdded({data:breakpointLocations[i]});
818 var messages = WebInspector.presentationConsoleMessageHelper.consoleMessages(this._uiSourceCode);
819 for (var i = 0; i < messages.length; ++i) {
820 var message = messages[i];
821 this.addMessageToSource(message.lineNumber, message.originalMessage);
824 var scriptFiles = this._scriptFileForTarget.values();
825 for (var i = 0; i < scriptFiles.length; ++i)
826 scriptFiles[i].checkMapping();
828 this._updateLinesWithoutMappingHighlight();
832 * @param {!WebInspector.Event} event
834 _handleGutterClick: function(event)
839 var eventData = /** @type {!WebInspector.TextEditor.GutterClickEventData} */ (event.data);
840 var lineNumber = eventData.lineNumber;
841 var eventObject = eventData.event;
843 if (eventObject.button != 0 || eventObject.altKey || eventObject.ctrlKey || eventObject.metaKey)
846 this._toggleBreakpoint(lineNumber, eventObject.shiftKey);
847 eventObject.consume(true);
851 * @param {number} lineNumber
852 * @param {boolean} onlyDisable
854 _toggleBreakpoint: function(lineNumber, onlyDisable)
856 var breakpoint = this._breakpointManager.findBreakpointOnLine(this._uiSourceCode, lineNumber);
859 breakpoint.setEnabled(!breakpoint.enabled());
863 this._setBreakpoint(lineNumber, 0, "", true);
866 toggleBreakpointOnCurrentLine: function()
871 var selection = this.textEditor.selection();
874 this._toggleBreakpoint(selection.startLine, false);
878 * @param {number} lineNumber
879 * @param {number} columnNumber
880 * @param {string} condition
881 * @param {boolean} enabled
883 _setBreakpoint: function(lineNumber, columnNumber, condition, enabled)
885 this._breakpointManager.setBreakpoint(this._uiSourceCode, lineNumber, columnNumber, condition, enabled);
887 WebInspector.notifications.dispatchEventToListeners(WebInspector.UserMetrics.UserAction, {
888 action: WebInspector.UserMetrics.UserActionNames.SetBreakpoint,
889 url: this._uiSourceCode.originURL(),
896 * @param {number} lineNumber
898 _continueToLine: function(lineNumber)
900 var executionContext = WebInspector.context.flavor(WebInspector.ExecutionContext);
901 if (!executionContext)
903 var rawLocation = WebInspector.debuggerWorkspaceBinding.uiLocationToRawLocation(executionContext.target(), this._uiSourceCode, lineNumber, 0);
906 this._scriptsPanel.continueToLocation(rawLocation);
911 this._breakpointManager.removeEventListener(WebInspector.BreakpointManager.Events.BreakpointAdded, this._breakpointAdded, this);
912 this._breakpointManager.removeEventListener(WebInspector.BreakpointManager.Events.BreakpointRemoved, this._breakpointRemoved, this);
913 WebInspector.presentationConsoleMessageHelper.removeConsoleMessageEventListener(WebInspector.PresentationConsoleMessageHelper.Events.ConsoleMessageAdded, this._uiSourceCode, this._consoleMessageAdded, this);
914 WebInspector.presentationConsoleMessageHelper.removeConsoleMessageEventListener(WebInspector.PresentationConsoleMessageHelper.Events.ConsoleMessageRemoved, this._uiSourceCode, this._consoleMessageRemoved, this);
915 WebInspector.presentationConsoleMessageHelper.removeConsoleMessageEventListener(WebInspector.PresentationConsoleMessageHelper.Events.ConsoleMessagesCleared, this._uiSourceCode, this._consoleMessagesCleared, this);
916 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._onSourceMappingChanged, this);
917 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this);
918 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._workingCopyCommitted, this);
919 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._showBlackboxInfobarIfNeeded, this);
920 WebInspector.settings.skipStackFramesPattern.removeChangeListener(this._showBlackboxInfobarIfNeeded, this);
921 WebInspector.settings.skipContentScripts.removeChangeListener(this._showBlackboxInfobarIfNeeded, this);
922 WebInspector.UISourceCodeFrame.prototype.dispose.call(this);
925 __proto__: WebInspector.UISourceCodeFrame.prototype