summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/devtools/front_end/components/DOMBreakpointsSidebarPane.js
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/devtools/front_end/components/DOMBreakpointsSidebarPane.js')
-rw-r--r--chromium/third_party/WebKit/Source/devtools/front_end/components/DOMBreakpointsSidebarPane.js462
1 files changed, 462 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/devtools/front_end/components/DOMBreakpointsSidebarPane.js b/chromium/third_party/WebKit/Source/devtools/front_end/components/DOMBreakpointsSidebarPane.js
new file mode 100644
index 00000000000..51c3c1ec3fb
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/devtools/front_end/components/DOMBreakpointsSidebarPane.js
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.NativeBreakpointsSidebarPane}
+ * @implements {WebInspector.TargetManager.Observer}
+ */
+WebInspector.DOMBreakpointsSidebarPane = function()
+{
+ WebInspector.NativeBreakpointsSidebarPane.call(this, WebInspector.UIString("DOM Breakpoints"));
+
+ this._breakpointElements = {};
+
+ this._breakpointTypes = {
+ SubtreeModified: "subtree-modified",
+ AttributeModified: "attribute-modified",
+ NodeRemoved: "node-removed"
+ };
+ this._breakpointTypeLabels = {};
+ this._breakpointTypeLabels[this._breakpointTypes.SubtreeModified] = WebInspector.UIString("Subtree Modified");
+ this._breakpointTypeLabels[this._breakpointTypes.AttributeModified] = WebInspector.UIString("Attribute Modified");
+ this._breakpointTypeLabels[this._breakpointTypes.NodeRemoved] = WebInspector.UIString("Node Removed");
+
+ this._contextMenuLabels = {};
+ this._contextMenuLabels[this._breakpointTypes.SubtreeModified] = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Subtree modifications" : "Subtree Modifications");
+ this._contextMenuLabels[this._breakpointTypes.AttributeModified] = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Attributes modifications" : "Attributes Modifications");
+ this._contextMenuLabels[this._breakpointTypes.NodeRemoved] = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Node removal" : "Node Removal");
+
+ WebInspector.targetManager.observeTargets(this);
+}
+
+WebInspector.DOMBreakpointsSidebarPane.prototype = {
+ /**
+ * @param {!WebInspector.Target} target
+ */
+ targetAdded: function(target)
+ {
+ target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._inspectedURLChanged, this);
+ target.domModel.addEventListener(WebInspector.DOMModel.Events.NodeRemoved, this._nodeRemoved, this);
+ },
+
+ /**
+ * @param {!WebInspector.Target} target
+ */
+ targetRemoved: function(target)
+ {
+ target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._inspectedURLChanged, this);
+ target.domModel.removeEventListener(WebInspector.DOMModel.Events.NodeRemoved, this._nodeRemoved, this);
+ },
+
+ _inspectedURLChanged: function(event)
+ {
+ this._breakpointElements = {};
+ this._reset();
+ var url = /** @type {string} */ (event.data);
+ this._inspectedURL = url.removeURLFragment();
+ },
+
+ /**
+ * @param {!WebInspector.DOMNode} node
+ * @param {!WebInspector.ContextMenu} contextMenu
+ */
+ populateNodeContextMenu: function(node, contextMenu)
+ {
+ if (node.pseudoType())
+ return;
+
+ var nodeBreakpoints = {};
+ for (var id in this._breakpointElements) {
+ var element = this._breakpointElements[id];
+ if (element._node === node)
+ nodeBreakpoints[element._type] = true;
+ }
+
+ /**
+ * @param {string} type
+ * @this {WebInspector.DOMBreakpointsSidebarPane}
+ */
+ function toggleBreakpoint(type)
+ {
+ if (!nodeBreakpoints[type])
+ this._setBreakpoint(node, type, true);
+ else
+ this._removeBreakpoint(node, type);
+ this._saveBreakpoints();
+ }
+
+ var breakPointSubMenu = contextMenu.appendSubMenuItem(WebInspector.UIString("Break on..."));
+ for (var key in this._breakpointTypes) {
+ var type = this._breakpointTypes[key];
+ var label = this._contextMenuLabels[type];
+ breakPointSubMenu.appendCheckboxItem(label, toggleBreakpoint.bind(this, type), nodeBreakpoints[type]);
+ }
+ },
+
+ /**
+ * @param {!WebInspector.DebuggerPausedDetails} details
+ * @param {function(!Element)} callback
+ */
+ createBreakpointHitStatusMessage: function(details, callback)
+ {
+ var auxData = /** @type {!Object} */ (details.auxData);
+ var domModel = details.target().domModel;
+ if (auxData.type === this._breakpointTypes.SubtreeModified) {
+ var targetNodeObject = details.target().runtimeModel.createRemoteObject(auxData["targetNode"]);
+ targetNodeObject.pushNodeToFrontend(didPushNodeToFrontend.bind(this));
+ } else {
+ this._doCreateBreakpointHitStatusMessage(auxData, domModel.nodeForId(auxData.nodeId), null, callback);
+ }
+
+ /**
+ * @param {?WebInspector.DOMNode} targetNode
+ * @this {WebInspector.DOMBreakpointsSidebarPane}
+ */
+ function didPushNodeToFrontend(targetNode)
+ {
+ if (targetNode)
+ targetNodeObject.release();
+ this._doCreateBreakpointHitStatusMessage(auxData, domModel.nodeForId(auxData.nodeId), targetNode, callback);
+ }
+ },
+
+ /**
+ * @param {!Object} auxData
+ * @param {?WebInspector.DOMNode} node
+ * @param {?WebInspector.DOMNode} targetNode
+ * @param {function(!Element)} callback
+ */
+ _doCreateBreakpointHitStatusMessage: function(auxData, node, targetNode, callback)
+ {
+ var message;
+ var typeLabel = this._breakpointTypeLabels[auxData.type];
+ var linkifiedNode = WebInspector.DOMPresentationUtils.linkifyNodeReference(node);
+ var substitutions = [typeLabel, linkifiedNode];
+ var targetNodeLink = "";
+ if (targetNode)
+ targetNodeLink = WebInspector.DOMPresentationUtils.linkifyNodeReference(targetNode);
+
+ if (auxData.type === this._breakpointTypes.SubtreeModified) {
+ if (auxData.insertion) {
+ if (targetNode !== node) {
+ message = "Paused on a \"%s\" breakpoint set on %s, because a new child was added to its descendant %s.";
+ substitutions.push(targetNodeLink);
+ } else
+ message = "Paused on a \"%s\" breakpoint set on %s, because a new child was added to that node.";
+ } else {
+ message = "Paused on a \"%s\" breakpoint set on %s, because its descendant %s was removed.";
+ substitutions.push(targetNodeLink);
+ }
+ } else
+ message = "Paused on a \"%s\" breakpoint set on %s.";
+
+ var element = document.createElement("span");
+ var formatters = {
+ s: function(substitution)
+ {
+ return substitution;
+ }
+ };
+ function append(a, b)
+ {
+ if (typeof b === "string")
+ b = document.createTextNode(b);
+ element.appendChild(b);
+ }
+ WebInspector.formatLocalized(message, substitutions, formatters, "", append);
+
+ callback(element);
+ },
+
+ _nodeRemoved: function(event)
+ {
+ var node = event.data.node;
+ this._removeBreakpointsForNode(event.data.node);
+ var children = node.children();
+ if (!children)
+ return;
+ for (var i = 0; i < children.length; ++i)
+ this._removeBreakpointsForNode(children[i]);
+ this._saveBreakpoints();
+ },
+
+ _removeBreakpointsForNode: function(node)
+ {
+ for (var id in this._breakpointElements) {
+ var element = this._breakpointElements[id];
+ if (element._node === node)
+ this._removeBreakpoint(element._node, element._type);
+ }
+ },
+
+ _setBreakpoint: function(node, type, enabled)
+ {
+ var breakpointId = this._createBreakpointId(node.id, type);
+ if (breakpointId in this._breakpointElements)
+ return;
+
+ var element = document.createElement("li");
+ element._node = node;
+ element._type = type;
+ element.addEventListener("contextmenu", this._contextMenu.bind(this, node, type), true);
+
+ var checkboxElement = document.createElement("input");
+ checkboxElement.className = "checkbox-elem";
+ checkboxElement.type = "checkbox";
+ checkboxElement.checked = enabled;
+ checkboxElement.addEventListener("click", this._checkboxClicked.bind(this, node, type), false);
+ element._checkboxElement = checkboxElement;
+ element.appendChild(checkboxElement);
+
+ var labelElement = document.createElement("span");
+ element.appendChild(labelElement);
+
+ var linkifiedNode = WebInspector.DOMPresentationUtils.linkifyNodeReference(node);
+ linkifiedNode.classList.add("monospace");
+ labelElement.appendChild(linkifiedNode);
+
+ var description = document.createElement("div");
+ description.className = "source-text";
+ description.textContent = this._breakpointTypeLabels[type];
+ labelElement.appendChild(description);
+
+ var currentElement = this.listElement.firstChild;
+ while (currentElement) {
+ if (currentElement._type && currentElement._type < element._type)
+ break;
+ currentElement = currentElement.nextSibling;
+ }
+ this._addListElement(element, currentElement);
+ this._breakpointElements[breakpointId] = element;
+ if (enabled)
+ DOMDebuggerAgent.setDOMBreakpoint(node.id, type);
+ },
+
+ _removeAllBreakpoints: function()
+ {
+ for (var id in this._breakpointElements) {
+ var element = this._breakpointElements[id];
+ this._removeBreakpoint(element._node, element._type);
+ }
+ this._saveBreakpoints();
+ },
+
+ _removeBreakpoint: function(node, type)
+ {
+ var breakpointId = this._createBreakpointId(node.id, type);
+ var element = this._breakpointElements[breakpointId];
+ if (!element)
+ return;
+
+ this._removeListElement(element);
+ delete this._breakpointElements[breakpointId];
+ if (element._checkboxElement.checked)
+ DOMDebuggerAgent.removeDOMBreakpoint(node.id, type);
+ },
+
+ _contextMenu: function(node, type, event)
+ {
+ var contextMenu = new WebInspector.ContextMenu(event);
+
+ /**
+ * @this {WebInspector.DOMBreakpointsSidebarPane}
+ */
+ function removeBreakpoint()
+ {
+ this._removeBreakpoint(node, type);
+ this._saveBreakpoints();
+ }
+ contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove breakpoint" : "Remove Breakpoint"), removeBreakpoint.bind(this));
+ contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove all DOM breakpoints" : "Remove All DOM Breakpoints"), this._removeAllBreakpoints.bind(this));
+ contextMenu.show();
+ },
+
+ _checkboxClicked: function(node, type, event)
+ {
+ if (event.target.checked)
+ DOMDebuggerAgent.setDOMBreakpoint(node.id, type);
+ else
+ DOMDebuggerAgent.removeDOMBreakpoint(node.id, type);
+ this._saveBreakpoints();
+ },
+
+ highlightBreakpoint: function(auxData)
+ {
+ var breakpointId = this._createBreakpointId(auxData.nodeId, auxData.type);
+ var element = this._breakpointElements[breakpointId];
+ if (!element)
+ return;
+ this.expand();
+ element.classList.add("breakpoint-hit");
+ this._highlightedElement = element;
+ },
+
+ clearBreakpointHighlight: function()
+ {
+ if (this._highlightedElement) {
+ this._highlightedElement.classList.remove("breakpoint-hit");
+ delete this._highlightedElement;
+ }
+ },
+
+ _createBreakpointId: function(nodeId, type)
+ {
+ return nodeId + ":" + type;
+ },
+
+ _saveBreakpoints: function()
+ {
+ var breakpoints = [];
+ var storedBreakpoints = WebInspector.settings.domBreakpoints.get();
+ for (var i = 0; i < storedBreakpoints.length; ++i) {
+ var breakpoint = storedBreakpoints[i];
+ if (breakpoint.url !== this._inspectedURL)
+ breakpoints.push(breakpoint);
+ }
+ for (var id in this._breakpointElements) {
+ var element = this._breakpointElements[id];
+ breakpoints.push({ url: this._inspectedURL, path: element._node.path(), type: element._type, enabled: element._checkboxElement.checked });
+ }
+ WebInspector.settings.domBreakpoints.set(breakpoints);
+ },
+
+ /**
+ * @param {!WebInspector.Target} target
+ */
+ restoreBreakpoints: function(target)
+ {
+ var pathToBreakpoints = {};
+
+ /**
+ * @param {string} path
+ * @param {?DOMAgent.NodeId} nodeId
+ * @this {WebInspector.DOMBreakpointsSidebarPane}
+ */
+ function didPushNodeByPathToFrontend(path, nodeId)
+ {
+ var node = nodeId ? target.domModel.nodeForId(nodeId) : null;
+ if (!node)
+ return;
+
+ var breakpoints = pathToBreakpoints[path];
+ for (var i = 0; i < breakpoints.length; ++i)
+ this._setBreakpoint(node, breakpoints[i].type, breakpoints[i].enabled);
+ }
+
+ var breakpoints = WebInspector.settings.domBreakpoints.get();
+ for (var i = 0; i < breakpoints.length; ++i) {
+ var breakpoint = breakpoints[i];
+ if (breakpoint.url !== this._inspectedURL)
+ continue;
+ var path = breakpoint.path;
+ if (!pathToBreakpoints[path]) {
+ pathToBreakpoints[path] = [];
+ target.domModel.pushNodeByPathToFrontend(path, didPushNodeByPathToFrontend.bind(this, path));
+ }
+ pathToBreakpoints[path].push(breakpoint);
+ }
+ },
+
+ /**
+ * @param {!WebInspector.Panel} panel
+ * @return {!WebInspector.DOMBreakpointsSidebarPane.Proxy}
+ */
+ createProxy: function(panel)
+ {
+ var proxy = new WebInspector.DOMBreakpointsSidebarPane.Proxy(this, panel);
+ if (!this._proxies)
+ this._proxies = [];
+ this._proxies.push(proxy);
+ return proxy;
+ },
+
+ onContentReady: function()
+ {
+ for (var i = 0; i != this._proxies.length; i++)
+ this._proxies[i].onContentReady();
+ },
+
+ __proto__: WebInspector.NativeBreakpointsSidebarPane.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.SidebarPane}
+ * @param {!WebInspector.DOMBreakpointsSidebarPane} pane
+ * @param {!WebInspector.Panel} panel
+ */
+WebInspector.DOMBreakpointsSidebarPane.Proxy = function(pane, panel)
+{
+ WebInspector.View._assert(!pane.titleElement.firstChild, "Cannot create proxy for a sidebar pane with a toolbar");
+
+ WebInspector.SidebarPane.call(this, pane.title());
+ this.registerRequiredCSS("breakpointsList.css");
+
+ this._wrappedPane = pane;
+ this._panel = panel;
+
+ this.bodyElement.remove();
+ this.bodyElement = this._wrappedPane.bodyElement;
+}
+
+WebInspector.DOMBreakpointsSidebarPane.Proxy.prototype = {
+ expand: function()
+ {
+ this._wrappedPane.expand();
+ },
+
+ onContentReady: function()
+ {
+ if (this._panel.isShowing())
+ this._reattachBody();
+
+ WebInspector.SidebarPane.prototype.onContentReady.call(this);
+ },
+
+ wasShown: function()
+ {
+ WebInspector.SidebarPane.prototype.wasShown.call(this);
+ this._reattachBody();
+ },
+
+ _reattachBody: function()
+ {
+ if (this.bodyElement.parentNode !== this.element)
+ this.element.appendChild(this.bodyElement);
+ },
+
+ __proto__: WebInspector.SidebarPane.prototype
+}
+
+/**
+ * @type {!WebInspector.DOMBreakpointsSidebarPane}
+ */
+WebInspector.domBreakpointsSidebarPane;