summaryrefslogtreecommitdiff
path: root/Source/WebInspectorUI/UserInterface/Controllers/BreakpointPopoverController.js
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/Controllers/BreakpointPopoverController.js
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Controllers/BreakpointPopoverController.js')
-rw-r--r--Source/WebInspectorUI/UserInterface/Controllers/BreakpointPopoverController.js382
1 files changed, 382 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/Controllers/BreakpointPopoverController.js b/Source/WebInspectorUI/UserInterface/Controllers/BreakpointPopoverController.js
new file mode 100644
index 000000000..1b30fc98c
--- /dev/null
+++ b/Source/WebInspectorUI/UserInterface/Controllers/BreakpointPopoverController.js
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2015 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.BreakpointPopoverController = class BreakpointPopoverController extends WebInspector.Object
+{
+ constructor()
+ {
+ super();
+
+ this._breakpoint = null;
+ this._popover = null;
+ this._popoverContentElement = null;
+ }
+
+ // Public
+
+ appendContextMenuItems(contextMenu, breakpoint, breakpointDisplayElement)
+ {
+ console.assert(document.body.contains(breakpointDisplayElement), "Breakpoint popover display element must be in the DOM.");
+
+ const editBreakpoint = () => {
+ console.assert(!this._popover, "Breakpoint popover already exists.");
+ if (this._popover)
+ return;
+
+ this._createPopoverContent(breakpoint);
+ this._popover = new WebInspector.Popover(this);
+ this._popover.content = this._popoverContentElement;
+
+ let bounds = WebInspector.Rect.rectFromClientRect(breakpointDisplayElement.getBoundingClientRect());
+ bounds.origin.x -= 1; // Move the anchor left one pixel so it looks more centered.
+ this._popover.present(bounds.pad(2), [WebInspector.RectEdge.MAX_Y]);
+ };
+
+ const removeBreakpoint = () => {
+ WebInspector.debuggerManager.removeBreakpoint(breakpoint);
+ };
+
+ const toggleBreakpoint = () => {
+ breakpoint.disabled = !breakpoint.disabled;
+ };
+
+ const toggleAutoContinue = () => {
+ breakpoint.autoContinue = !breakpoint.autoContinue;
+ };
+
+ const revealOriginalSourceCodeLocation = () => {
+ WebInspector.showOriginalOrFormattedSourceCodeLocation(breakpoint.sourceCodeLocation);
+ };
+
+ if (WebInspector.debuggerManager.isBreakpointEditable(breakpoint))
+ contextMenu.appendItem(WebInspector.UIString("Edit Breakpoint…"), editBreakpoint);
+
+ if (breakpoint.autoContinue && !breakpoint.disabled) {
+ contextMenu.appendItem(WebInspector.UIString("Disable Breakpoint"), toggleBreakpoint);
+ contextMenu.appendItem(WebInspector.UIString("Cancel Automatic Continue"), toggleAutoContinue);
+ } else if (!breakpoint.disabled)
+ contextMenu.appendItem(WebInspector.UIString("Disable Breakpoint"), toggleBreakpoint);
+ else
+ contextMenu.appendItem(WebInspector.UIString("Enable Breakpoint"), toggleBreakpoint);
+
+ if (!breakpoint.autoContinue && !breakpoint.disabled && breakpoint.actions.length)
+ contextMenu.appendItem(WebInspector.UIString("Set to Automatically Continue"), toggleAutoContinue);
+
+ if (WebInspector.debuggerManager.isBreakpointRemovable(breakpoint)) {
+ contextMenu.appendSeparator();
+ contextMenu.appendItem(WebInspector.UIString("Delete Breakpoint"), removeBreakpoint);
+ }
+
+ if (breakpoint._sourceCodeLocation.hasMappedLocation()) {
+ contextMenu.appendSeparator();
+ contextMenu.appendItem(WebInspector.UIString("Reveal in Original Resource"), revealOriginalSourceCodeLocation);
+ }
+ }
+
+ // CodeMirrorCompletionController delegate
+
+ completionControllerShouldAllowEscapeCompletion()
+ {
+ return false;
+ }
+
+ // Private
+
+ _createPopoverContent(breakpoint)
+ {
+ console.assert(!this._popoverContentElement, "Popover content element already exists.");
+ if (this._popoverContentElement)
+ return;
+
+ this._breakpoint = breakpoint;
+ this._popoverContentElement = document.createElement("div");
+ this._popoverContentElement.className = "edit-breakpoint-popover-content";
+
+ let checkboxElement = document.createElement("input");
+ checkboxElement.type = "checkbox";
+ checkboxElement.checked = !this._breakpoint.disabled;
+ checkboxElement.addEventListener("change", this._popoverToggleEnabledCheckboxChanged.bind(this));
+
+ let checkboxLabel = document.createElement("label");
+ checkboxLabel.className = "toggle";
+ checkboxLabel.appendChild(checkboxElement);
+ checkboxLabel.append(this._breakpoint.sourceCodeLocation.displayLocationString());
+
+ let table = document.createElement("table");
+
+ let conditionRow = table.appendChild(document.createElement("tr"));
+ let conditionHeader = conditionRow.appendChild(document.createElement("th"));
+ let conditionData = conditionRow.appendChild(document.createElement("td"));
+ let conditionLabel = conditionHeader.appendChild(document.createElement("label"));
+ conditionLabel.textContent = WebInspector.UIString("Condition");
+ let conditionEditorElement = conditionData.appendChild(document.createElement("div"));
+ conditionEditorElement.classList.add("edit-breakpoint-popover-condition", WebInspector.SyntaxHighlightedStyleClassName);
+
+ this._conditionCodeMirror = WebInspector.CodeMirrorEditor.create(conditionEditorElement, {
+ extraKeys: {Tab: false},
+ lineWrapping: false,
+ mode: "text/javascript",
+ matchBrackets: true,
+ placeholder: WebInspector.UIString("Conditional expression"),
+ scrollbarStyle: null,
+ value: this._breakpoint.condition || "",
+ });
+
+ let conditionCodeMirrorInputField = this._conditionCodeMirror.getInputField();
+ conditionCodeMirrorInputField.id = "codemirror-condition-input-field";
+ conditionLabel.setAttribute("for", conditionCodeMirrorInputField.id);
+
+ this._conditionCodeMirrorEscapeOrEnterKeyHandler = this._conditionCodeMirrorEscapeOrEnterKey.bind(this);
+ this._conditionCodeMirror.addKeyMap({
+ "Esc": this._conditionCodeMirrorEscapeOrEnterKeyHandler,
+ "Enter": this._conditionCodeMirrorEscapeOrEnterKeyHandler,
+ });
+
+ this._conditionCodeMirror.on("change", this._conditionCodeMirrorChanged.bind(this));
+ this._conditionCodeMirror.on("beforeChange", this._conditionCodeMirrorBeforeChange.bind(this));
+
+ let completionController = new WebInspector.CodeMirrorCompletionController(this._conditionCodeMirror, this);
+ completionController.addExtendedCompletionProvider("javascript", WebInspector.javaScriptRuntimeCompletionProvider);
+
+ // CodeMirror needs a refresh after the popover displays, to layout, otherwise it doesn't appear.
+ setTimeout(() => {
+ this._conditionCodeMirror.refresh();
+ this._conditionCodeMirror.focus();
+ }, 0);
+
+ // COMPATIBILITY (iOS 7): Debugger.setBreakpoint did not support options.
+ if (DebuggerAgent.setBreakpoint.supports("options")) {
+ // COMPATIBILITY (iOS 9): Legacy backends don't support breakpoint ignore count. Since support
+ // can't be tested directly, check for CSS.getSupportedSystemFontFamilyNames.
+ // FIXME: Use explicit version checking once https://webkit.org/b/148680 is fixed.
+ if (CSSAgent.getSupportedSystemFontFamilyNames) {
+ let ignoreCountRow = table.appendChild(document.createElement("tr"));
+ let ignoreCountHeader = ignoreCountRow.appendChild(document.createElement("th"));
+ let ignoreCountLabel = ignoreCountHeader.appendChild(document.createElement("label"));
+ let ignoreCountData = ignoreCountRow.appendChild(document.createElement("td"));
+ this._ignoreCountInput = ignoreCountData.appendChild(document.createElement("input"));
+ this._ignoreCountInput.id = "edit-breakpoint-popover-ignore";
+ this._ignoreCountInput.type = "number";
+ this._ignoreCountInput.min = 0;
+ this._ignoreCountInput.value = 0;
+ this._ignoreCountInput.addEventListener("change", this._popoverIgnoreInputChanged.bind(this));
+
+ ignoreCountLabel.setAttribute("for", this._ignoreCountInput.id);
+ ignoreCountLabel.textContent = WebInspector.UIString("Ignore");
+
+ this._ignoreCountText = ignoreCountData.appendChild(document.createElement("span"));
+ this._updateIgnoreCountText();
+ }
+
+ let actionRow = table.appendChild(document.createElement("tr"));
+ let actionHeader = actionRow.appendChild(document.createElement("th"));
+ let actionData = this._actionsContainer = actionRow.appendChild(document.createElement("td"));
+ let actionLabel = actionHeader.appendChild(document.createElement("label"));
+ actionLabel.textContent = WebInspector.UIString("Action");
+
+ if (!this._breakpoint.actions.length)
+ this._popoverActionsCreateAddActionButton();
+ else {
+ this._popoverContentElement.classList.add(WebInspector.BreakpointPopoverController.WidePopoverClassName);
+ for (let i = 0; i < this._breakpoint.actions.length; ++i) {
+ let breakpointActionView = new WebInspector.BreakpointActionView(this._breakpoint.actions[i], this, true);
+ this._popoverActionsInsertBreakpointActionView(breakpointActionView, i);
+ }
+ }
+
+ let optionsRow = this._popoverOptionsRowElement = table.appendChild(document.createElement("tr"));
+ if (!this._breakpoint.actions.length)
+ optionsRow.classList.add(WebInspector.BreakpointPopoverController.HiddenStyleClassName);
+ let optionsHeader = optionsRow.appendChild(document.createElement("th"));
+ let optionsData = optionsRow.appendChild(document.createElement("td"));
+ let optionsLabel = optionsHeader.appendChild(document.createElement("label"));
+ let optionsCheckbox = this._popoverOptionsCheckboxElement = optionsData.appendChild(document.createElement("input"));
+ let optionsCheckboxLabel = optionsData.appendChild(document.createElement("label"));
+ optionsCheckbox.id = "edit-breakpoint-popoover-auto-continue";
+ optionsCheckbox.type = "checkbox";
+ optionsCheckbox.checked = this._breakpoint.autoContinue;
+ optionsCheckbox.addEventListener("change", this._popoverToggleAutoContinueCheckboxChanged.bind(this));
+ optionsLabel.textContent = WebInspector.UIString("Options");
+ optionsCheckboxLabel.setAttribute("for", optionsCheckbox.id);
+ optionsCheckboxLabel.textContent = WebInspector.UIString("Automatically continue after evaluating");
+ }
+
+ this._popoverContentElement.appendChild(checkboxLabel);
+ this._popoverContentElement.appendChild(table);
+ }
+
+ _popoverToggleEnabledCheckboxChanged(event)
+ {
+ this._breakpoint.disabled = !event.target.checked;
+ }
+
+ _conditionCodeMirrorChanged(codeMirror, change)
+ {
+ this._breakpoint.condition = (codeMirror.getValue() || "").trim();
+ }
+
+ _conditionCodeMirrorBeforeChange(codeMirror, change)
+ {
+ if (change.update) {
+ let newText = change.text.join("").replace(/\n/g, "");
+ change.update(change.from, change.to, [newText]);
+ }
+
+ return true;
+ }
+
+ _conditionCodeMirrorEscapeOrEnterKey()
+ {
+ if (!this._popover)
+ return;
+
+ this._popover.dismiss();
+ }
+
+ _popoverIgnoreInputChanged(event)
+ {
+ let ignoreCount = 0;
+ if (event.target.value) {
+ ignoreCount = parseInt(event.target.value, 10);
+ if (isNaN(ignoreCount) || ignoreCount < 0)
+ ignoreCount = 0;
+ }
+
+ this._ignoreCountInput.value = ignoreCount;
+ this._breakpoint.ignoreCount = ignoreCount;
+
+ this._updateIgnoreCountText();
+ }
+
+ _popoverToggleAutoContinueCheckboxChanged(event)
+ {
+ this._breakpoint.autoContinue = event.target.checked;
+ }
+
+ _popoverActionsCreateAddActionButton()
+ {
+ this._popoverContentElement.classList.remove(WebInspector.BreakpointPopoverController.WidePopoverClassName);
+ this._actionsContainer.removeChildren();
+
+ let addActionButton = this._actionsContainer.appendChild(document.createElement("button"));
+ addActionButton.textContent = WebInspector.UIString("Add Action");
+ addActionButton.addEventListener("click", this._popoverActionsAddActionButtonClicked.bind(this));
+ }
+
+ _popoverActionsAddActionButtonClicked(event)
+ {
+ this._popoverContentElement.classList.add(WebInspector.BreakpointPopoverController.WidePopoverClassName);
+ this._actionsContainer.removeChildren();
+
+ let newAction = this._breakpoint.createAction(WebInspector.Breakpoint.DefaultBreakpointActionType);
+ let newBreakpointActionView = new WebInspector.BreakpointActionView(newAction, this);
+ this._popoverActionsInsertBreakpointActionView(newBreakpointActionView, -1);
+ this._popoverOptionsRowElement.classList.remove(WebInspector.BreakpointPopoverController.HiddenStyleClassName);
+ this._popover.update();
+ }
+
+ _popoverActionsInsertBreakpointActionView(breakpointActionView, index)
+ {
+ if (index === -1)
+ this._actionsContainer.appendChild(breakpointActionView.element);
+ else {
+ let nextElement = this._actionsContainer.children[index + 1] || null;
+ this._actionsContainer.insertBefore(breakpointActionView.element, nextElement);
+ }
+ }
+
+ _updateIgnoreCountText()
+ {
+ if (this._breakpoint.ignoreCount === 1)
+ this._ignoreCountText.textContent = WebInspector.UIString("time before stopping");
+ else
+ this._ignoreCountText.textContent = WebInspector.UIString("times before stopping");
+ }
+
+ breakpointActionViewAppendActionView(breakpointActionView, newAction)
+ {
+ let newBreakpointActionView = new WebInspector.BreakpointActionView(newAction, this);
+
+ let index = 0;
+ let children = this._actionsContainer.children;
+ for (let i = 0; children.length; ++i) {
+ if (children[i] === breakpointActionView.element) {
+ index = i;
+ break;
+ }
+ }
+
+ this._popoverActionsInsertBreakpointActionView(newBreakpointActionView, index);
+ this._popoverOptionsRowElement.classList.remove(WebInspector.BreakpointPopoverController.HiddenStyleClassName);
+
+ this._popover.update();
+ }
+
+ breakpointActionViewRemoveActionView(breakpointActionView)
+ {
+ breakpointActionView.element.remove();
+
+ if (!this._actionsContainer.children.length) {
+ this._popoverActionsCreateAddActionButton();
+ this._popoverOptionsRowElement.classList.add(WebInspector.BreakpointPopoverController.HiddenStyleClassName);
+ this._popoverOptionsCheckboxElement.checked = false;
+ }
+
+ this._popover.update();
+ }
+
+ breakpointActionViewResized(breakpointActionView)
+ {
+ this._popover.update();
+ }
+
+ willDismissPopover(popover)
+ {
+ console.assert(this._popover === popover);
+ this._popoverContentElement = null;
+ this._popoverOptionsRowElement = null;
+ this._popoverOptionsCheckboxElement = null;
+ this._actionsContainer = null;
+ this._popover = null;
+ }
+
+ didDismissPopover(popover)
+ {
+ // Remove Evaluate and Probe actions that have no data.
+ let emptyActions = this._breakpoint.actions.filter(function(action) {
+ if (action.type !== WebInspector.BreakpointAction.Type.Evaluate && action.type !== WebInspector.BreakpointAction.Type.Probe)
+ return false;
+ return !(action.data && action.data.trim());
+ });
+
+ for (let action of emptyActions)
+ this._breakpoint.removeAction(action);
+
+ this._breakpoint = null;
+ }
+};
+
+WebInspector.BreakpointPopoverController.WidePopoverClassName = "wide";
+WebInspector.BreakpointPopoverController.HiddenStyleClassName = "hidden";