blob: fa13a8217d8b13b57bea46613898d6840d1fbe26 [file] [log] [blame] [edit]
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
WebInspector.Breakpoint = function(sourceCodeLocationOrInfo, disabled, condition)
{
WebInspector.Object.call(this);
if (sourceCodeLocationOrInfo instanceof WebInspector.SourceCodeLocation) {
var sourceCode = sourceCodeLocationOrInfo.sourceCode;
var url = sourceCode ? sourceCode.url : null;
var scriptIdentifier = sourceCode instanceof WebInspector.Script ? sourceCode.id : null;
var location = sourceCodeLocationOrInfo;
} else if (sourceCodeLocationOrInfo && typeof sourceCodeLocationOrInfo === "object") {
var url = sourceCodeLocationOrInfo.url;
var lineNumber = sourceCodeLocationOrInfo.lineNumber || 0;
var columnNumber = sourceCodeLocationOrInfo.columnNumber || 0;
var location = new WebInspector.SourceCodeLocation(null, lineNumber, columnNumber);
disabled = sourceCodeLocationOrInfo.disabled;
condition = sourceCodeLocationOrInfo.condition;
} else
console.error("Unexpected type passed to WebInspector.Breakpoint", sourceCodeLocationOrInfo);
this._id = null;
this._url = url || null;
this._scriptIdentifier = scriptIdentifier || null;
this._disabled = disabled || false;
this._condition = condition || "";
this._resolved = false;
this._sourceCodeLocation = location;
this._sourceCodeLocation.addEventListener(WebInspector.SourceCodeLocation.Event.LocationChanged, this._sourceCodeLocationLocationChanged, this);
this._sourceCodeLocation.addEventListener(WebInspector.SourceCodeLocation.Event.DisplayLocationChanged, this._sourceCodeLocationDisplayLocationChanged, this);
};
WebInspector.Object.addConstructorFunctions(WebInspector.Breakpoint);
WebInspector.Breakpoint.PopoverClassName = "edit-breakpoint-popover-content";
WebInspector.Breakpoint.PopoverConditionInputId = "edit-breakpoint-popover-condition";
WebInspector.Breakpoint.Event = {
DisabledStateDidChange: "breakpoint-disabled-state-did-change",
ResolvedStateDidChange: "breakpoint-resolved-state-did-change",
ConditionDidChange: "breakpoint-condition-did-change",
LocationDidChange: "breakpoint-location-did-change",
DisplayLocationDidChange: "breakpoint-display-location-did-change",
};
WebInspector.Breakpoint.prototype = {
constructor: WebInspector.Breakpoint,
// Public
get id()
{
return this._id;
},
set id(id)
{
this._id = id || null;
},
get url()
{
return this._url;
},
get scriptIdentifier()
{
return this._scriptIdentifier;
},
get sourceCodeLocation()
{
return this._sourceCodeLocation;
},
get resolved()
{
return this._resolved && WebInspector.debuggerManager.breakpointsEnabled;
},
set resolved(resolved)
{
if (this._resolved === resolved)
return;
this._resolved = resolved || false;
this.dispatchEventToListeners(WebInspector.Breakpoint.Event.ResolvedStateDidChange);
},
get disabled()
{
return this._disabled;
},
set disabled(disabled)
{
if (this._disabled === disabled)
return;
this._disabled = disabled || false;
this.dispatchEventToListeners(WebInspector.Breakpoint.Event.DisabledStateDidChange);
},
get condition()
{
return this._condition;
},
set condition(condition)
{
if (this._condition === condition)
return;
this._condition = condition;
this.dispatchEventToListeners(WebInspector.Breakpoint.Event.ConditionDidChange);
},
get info()
{
// The id, scriptIdentifier and resolved state are tied to the current session, so don't include them for serialization.
return {
url: this._url,
lineNumber: this._sourceCodeLocation.lineNumber,
columnNumber: this._sourceCodeLocation.columnNumber,
disabled: this._disabled,
condition: this._condition
};
},
appendContextMenuItems: function(contextMenu, breakpointDisplayElement)
{
function editBreakpoint()
{
this._showEditBreakpointPopover(breakpointDisplayElement);
}
function removeBreakpoint()
{
WebInspector.debuggerManager.removeBreakpoint(this);
}
function toggleBreakpoint()
{
this.disabled = !this.disabled;
}
function revealOriginalSourceCodeLocation()
{
WebInspector.resourceSidebarPanel.showOriginalOrFormattedSourceCodeLocation(this._sourceCodeLocation);
}
if (WebInspector.debuggerManager.isBreakpointEditable(this))
contextMenu.appendItem(WebInspector.UIString("Edit Breakpoint…"), editBreakpoint.bind(this));
if (this._disabled)
contextMenu.appendItem(WebInspector.UIString("Enable Breakpoint"), toggleBreakpoint.bind(this));
else
contextMenu.appendItem(WebInspector.UIString("Disable Breakpoint"), toggleBreakpoint.bind(this));
if (WebInspector.debuggerManager.isBreakpointRemovable(this)) {
contextMenu.appendSeparator();
contextMenu.appendItem(WebInspector.UIString("Delete Breakpoint"), removeBreakpoint.bind(this));
}
if (this._sourceCodeLocation.hasMappedLocation()) {
contextMenu.appendSeparator();
contextMenu.appendItem(WebInspector.UIString("Reveal in Original Resource"), revealOriginalSourceCodeLocation.bind(this));
}
},
// Private
_popoverToggleCheckboxChanged: function(event)
{
this.disabled = !event.target.checked;
},
_popoverConditionInputChanged: function(event)
{
this.condition = event.target.value;
},
_popoverConditionInputKeyDown: function(event)
{
if (this._keyboardShortcutEsc.matchesEvent(event) || this._keyboardShortcutEnter.matchesEvent(event)) {
this._popover.dismiss();
event.stopPropagation();
event.preventDefault();
}
},
_editBreakpointPopoverContentElement: function()
{
var content = document.createElement("div");
content.className = WebInspector.Breakpoint.PopoverClassName;
var checkboxElement = document.createElement("input");
checkboxElement.type = "checkbox";
checkboxElement.checked = !this._disabled;
checkboxElement.addEventListener("change", this._popoverToggleCheckboxChanged.bind(this));
var checkboxLabel = document.createElement("label");
checkboxLabel.className = "toggle";
checkboxLabel.appendChild(checkboxElement);
checkboxLabel.appendChild(document.createTextNode(this._sourceCodeLocation.displayLocationString()));
var table = document.createElement("table");
var conditionRow = table.appendChild(document.createElement("tr"));
var conditionHeader = conditionRow.appendChild(document.createElement("th"));
var conditionData = conditionRow.appendChild(document.createElement("td"));
var conditionLabel = conditionHeader.appendChild(document.createElement("label"));
var conditionInput = conditionData.appendChild(document.createElement("input"));
conditionInput.id = WebInspector.Breakpoint.PopoverConditionInputId;
conditionInput.value = this._condition || "";
conditionInput.spellcheck = false;
conditionInput.addEventListener("change", this._popoverConditionInputChanged.bind(this));
conditionInput.addEventListener("keydown", this._popoverConditionInputKeyDown.bind(this));
conditionInput.placeholder = WebInspector.UIString("Conditional expression");
conditionLabel.setAttribute("for", conditionInput.id);
conditionLabel.textContent = WebInspector.UIString("Condition");
content.appendChild(checkboxLabel);
content.appendChild(table);
return content;
},
_showEditBreakpointPopover: function(element)
{
const padding = 2;
var bounds = WebInspector.Rect.rectFromClientRect(element.getBoundingClientRect());
bounds.origin.x -= 1; // Move the anchor left one pixel so it looks more centered.
bounds.origin.x -= padding;
bounds.origin.y -= padding;
bounds.size.width += padding * 2;
bounds.size.height += padding * 2;
this._popover = this._popover || new WebInspector.Popover(this);
this._popover.content = this._editBreakpointPopoverContentElement();
this._popover.present(bounds, [WebInspector.RectEdge.MAX_Y]);
if (!this._keyboardShortcutEsc) {
this._keyboardShortcutEsc = new WebInspector.KeyboardShortcut(null, WebInspector.KeyboardShortcut.Key.Escape);
this._keyboardShortcutEnter = new WebInspector.KeyboardShortcut(null, WebInspector.KeyboardShortcut.Key.Enter);
}
document.getElementById(WebInspector.Breakpoint.PopoverConditionInputId).select();
},
_sourceCodeLocationLocationChanged: function(event)
{
this.dispatchEventToListeners(WebInspector.Breakpoint.Event.LocationDidChange, event.data);
},
_sourceCodeLocationDisplayLocationChanged: function(event)
{
this.dispatchEventToListeners(WebInspector.Breakpoint.Event.DisplayLocationDidChange, event.data);
}
};
WebInspector.Breakpoint.prototype.__proto__ = WebInspector.Object.prototype;