| /* |
| * Copyright (C) 2009, 2010 Google Inc. All rights reserved. |
| * Copyright (C) 2009 Joseph Pecoraro |
| * 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: |
| * |
| * * 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. |
| */ |
| |
| // FIXME: DOMManager lacks advanced multi-target support. (DOMNodes per-target) |
| |
| WI.DOMManager = class DOMManager extends WI.Object |
| { |
| constructor() |
| { |
| super(); |
| |
| this._idToDOMNode = {}; |
| this._document = null; |
| this._attributeLoadNodeIds = {}; |
| this._restoreSelectedNodeIsAllowed = true; |
| this._loadNodeAttributesTimeout = 0; |
| this._inspectedNode = null; |
| |
| this._breakpointsForEventListeners = new Map; |
| |
| this._hasRequestedDocument = false; |
| this._pendingDocumentRequestCallbacks = null; |
| |
| WI.EventBreakpoint.addEventListener(WI.EventBreakpoint.Event.DisabledStateChanged, this._handleEventBreakpointDisabledStateChanged, this); |
| |
| WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this); |
| } |
| |
| // Target |
| |
| initializeTarget(target) |
| { |
| // FIXME: This should be improved when adding better DOM multi-target support since it is really per-target. |
| // This currently uses a setTimeout since it doesn't need to happen immediately, and DOMManager uses the |
| // global DOMAgent to request the document, so we want to make sure we've transitioned the global agents |
| // to this target if necessary. |
| if (target.hasDomain("DOM")) { |
| setTimeout(() => { |
| this.ensureDocument(); |
| }); |
| |
| if (WI.isEngineeringBuild) { |
| if (DOMManager.supportsEditingUserAgentShadowTrees({target})) |
| target.DOMAgent.setAllowEditingUserAgentShadowTrees(WI.settings.engineeringAllowEditingUserAgentShadowTrees.value); |
| } |
| } |
| } |
| |
| transitionPageTarget() |
| { |
| this._documentUpdated(); |
| } |
| |
| // Static |
| |
| static buildHighlightConfig(mode) |
| { |
| mode = mode || "all"; |
| |
| let highlightConfig = {showInfo: mode === "all"}; |
| |
| if (mode === "all" || mode === "content") |
| highlightConfig.contentColor = {r: 111, g: 168, b: 220, a: 0.66}; |
| |
| if (mode === "all" || mode === "padding") |
| highlightConfig.paddingColor = {r: 147, g: 196, b: 125, a: 0.66}; |
| |
| if (mode === "all" || mode === "border") |
| highlightConfig.borderColor = {r: 255, g: 229, b: 153, a: 0.66}; |
| |
| if (mode === "all" || mode === "margin") |
| highlightConfig.marginColor = {r: 246, g: 178, b: 107, a: 0.66}; |
| |
| return highlightConfig; |
| } |
| |
| static wrapClientCallback(callback) |
| { |
| if (!callback) |
| return null; |
| |
| return function(error, result) { |
| if (error) |
| console.error("Error during DOMAgent operation: " + error); |
| callback(error ? null : result); |
| }; |
| } |
| |
| static supportsDisablingEventListeners() |
| { |
| return InspectorBackend.hasCommand("DOM.setEventListenerDisabled"); |
| } |
| |
| static supportsEventListenerBreakpoints() |
| { |
| return InspectorBackend.hasCommand("DOM.setBreakpointForEventListener") |
| && InspectorBackend.hasCommand("DOM.removeBreakpointForEventListener"); |
| } |
| |
| static supportsEditingUserAgentShadowTrees({frontendOnly, target} = {}) |
| { |
| target = target || InspectorBackend; |
| return WI.settings.engineeringAllowEditingUserAgentShadowTrees.value |
| && (frontendOnly || target.hasCommand("DOM.setAllowEditingUserAgentShadowTrees")); |
| |
| } |
| |
| // Public |
| |
| get inspectedNode() { return this._inspectedNode; } |
| |
| get eventListenerBreakpoints() |
| { |
| return Array.from(this._breakpointsForEventListeners.values()); |
| } |
| |
| requestDocument(callback) |
| { |
| if (this._document) { |
| callback(this._document); |
| return; |
| } |
| |
| if (this._pendingDocumentRequestCallbacks) |
| this._pendingDocumentRequestCallbacks.push(callback); |
| else |
| this._pendingDocumentRequestCallbacks = [callback]; |
| |
| if (this._hasRequestedDocument) |
| return; |
| |
| if (!WI.pageTarget) |
| return; |
| |
| if (!WI.pageTarget.hasDomain("DOM")) |
| return; |
| |
| this._hasRequestedDocument = true; |
| |
| WI.pageTarget.DOMAgent.getDocument((error, root) => { |
| if (!error) |
| this._setDocument(root); |
| |
| for (let callback of this._pendingDocumentRequestCallbacks) |
| callback(this._document); |
| |
| this._pendingDocumentRequestCallbacks = null; |
| }); |
| } |
| |
| ensureDocument() |
| { |
| this.requestDocument(function(){}); |
| } |
| |
| pushNodeToFrontend(objectId, callback) |
| { |
| let target = WI.assumingMainTarget(); |
| this._dispatchWhenDocumentAvailable((callbackWrapper) => { |
| target.DOMAgent.requestNode(objectId, callbackWrapper); |
| }, callback); |
| } |
| |
| pushNodeByPathToFrontend(path, callback) |
| { |
| let target = WI.assumingMainTarget(); |
| this._dispatchWhenDocumentAvailable((callbackWrapper) => { |
| target.DOMAgent.pushNodeByPathToFrontend(path, callbackWrapper); |
| }, callback); |
| } |
| |
| // DOMObserver |
| |
| didAddEventListener(nodeId) |
| { |
| let node = this._idToDOMNode[nodeId]; |
| if (!node) |
| return; |
| |
| node.dispatchEventToListeners(WI.DOMNode.Event.EventListenersChanged); |
| } |
| |
| willRemoveEventListener(nodeId) |
| { |
| let node = this._idToDOMNode[nodeId]; |
| if (!node) |
| return; |
| |
| node.dispatchEventToListeners(WI.DOMNode.Event.EventListenersChanged); |
| } |
| |
| didFireEvent(nodeId, eventName, timestamp, data) |
| { |
| let node = this._idToDOMNode[nodeId]; |
| if (!node) |
| return; |
| |
| node.didFireEvent(eventName, timestamp, data); |
| } |
| |
| powerEfficientPlaybackStateChanged(nodeId, timestamp, isPowerEfficient) |
| { |
| let node = this._idToDOMNode[nodeId]; |
| if (!node) |
| return; |
| |
| node.powerEfficientPlaybackStateChanged(timestamp, isPowerEfficient); |
| } |
| |
| // Private |
| |
| _dispatchWhenDocumentAvailable(func, callback) |
| { |
| var callbackWrapper = DOMManager.wrapClientCallback(callback); |
| |
| function onDocumentAvailable() |
| { |
| if (this._document) |
| func(callbackWrapper); |
| else { |
| if (callbackWrapper) |
| callbackWrapper("No document"); |
| } |
| } |
| this.requestDocument(onDocumentAvailable.bind(this)); |
| } |
| |
| _attributeModified(nodeId, name, value) |
| { |
| var node = this._idToDOMNode[nodeId]; |
| if (!node) |
| return; |
| |
| node._setAttribute(name, value); |
| this.dispatchEventToListeners(WI.DOMManager.Event.AttributeModified, {node, name}); |
| node.dispatchEventToListeners(WI.DOMNode.Event.AttributeModified, {name}); |
| } |
| |
| _attributeRemoved(nodeId, name) |
| { |
| var node = this._idToDOMNode[nodeId]; |
| if (!node) |
| return; |
| |
| node._removeAttribute(name); |
| this.dispatchEventToListeners(WI.DOMManager.Event.AttributeRemoved, {node, name}); |
| node.dispatchEventToListeners(WI.DOMNode.Event.AttributeRemoved, {name}); |
| } |
| |
| _inlineStyleInvalidated(nodeIds) |
| { |
| for (var nodeId of nodeIds) |
| this._attributeLoadNodeIds[nodeId] = true; |
| if (this._loadNodeAttributesTimeout) |
| return; |
| this._loadNodeAttributesTimeout = setTimeout(this._loadNodeAttributes.bind(this), 0); |
| } |
| |
| _loadNodeAttributes() |
| { |
| function callback(nodeId, error, attributes) |
| { |
| if (error) { |
| console.error("Error during DOMAgent operation: " + error); |
| return; |
| } |
| var node = this._idToDOMNode[nodeId]; |
| if (node) { |
| node._setAttributesPayload(attributes); |
| this.dispatchEventToListeners(WI.DOMManager.Event.AttributeModified, {node, name: "style"}); |
| node.dispatchEventToListeners(WI.DOMNode.Event.AttributeModified, {name: "style"}); |
| } |
| } |
| |
| this._loadNodeAttributesTimeout = 0; |
| |
| let target = WI.assumingMainTarget(); |
| |
| for (var nodeId in this._attributeLoadNodeIds) { |
| if (!(nodeId in this._idToDOMNode)) |
| continue; |
| var nodeIdAsNumber = parseInt(nodeId); |
| target.DOMAgent.getAttributes(nodeIdAsNumber, callback.bind(this, nodeIdAsNumber)); |
| } |
| this._attributeLoadNodeIds = {}; |
| } |
| |
| _characterDataModified(nodeId, newValue) |
| { |
| var node = this._idToDOMNode[nodeId]; |
| node._nodeValue = newValue; |
| this.dispatchEventToListeners(WI.DOMManager.Event.CharacterDataModified, {node}); |
| } |
| |
| nodeForId(nodeId) |
| { |
| return this._idToDOMNode[nodeId] || null; |
| } |
| |
| _documentUpdated() |
| { |
| this._setDocument(null); |
| } |
| |
| _setDocument(payload) |
| { |
| for (let node of Object.values(this._idToDOMNode)) |
| node.markDestroyed(); |
| |
| this._idToDOMNode = {}; |
| |
| for (let breakpoint of this._breakpointsForEventListeners.values()) |
| WI.domDebuggerManager.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointRemoved, {breakpoint}); |
| this._breakpointsForEventListeners.clear(); |
| |
| let newDocument = null; |
| if (payload && "nodeId" in payload) |
| newDocument = new WI.DOMNode(this, null, false, payload); |
| |
| if (this._document === newDocument) |
| return; |
| |
| this._document = newDocument; |
| |
| if (!this._document) |
| this._hasRequestedDocument = false; |
| |
| this.dispatchEventToListeners(WI.DOMManager.Event.DocumentUpdated, {document: this._document}); |
| } |
| |
| _setDetachedRoot(payload) |
| { |
| new WI.DOMNode(this, null, false, payload); |
| } |
| |
| _setChildNodes(parentId, payloads) |
| { |
| if (!parentId && payloads.length) { |
| this._setDetachedRoot(payloads[0]); |
| return; |
| } |
| |
| var parent = this._idToDOMNode[parentId]; |
| parent._setChildrenPayload(payloads); |
| } |
| |
| _childNodeCountUpdated(nodeId, newValue) |
| { |
| var node = this._idToDOMNode[nodeId]; |
| node.childNodeCount = newValue; |
| this.dispatchEventToListeners(WI.DOMManager.Event.ChildNodeCountUpdated, node); |
| } |
| |
| _childNodeInserted(parentId, prevId, payload) |
| { |
| var parent = this._idToDOMNode[parentId]; |
| var prev = this._idToDOMNode[prevId]; |
| var node = parent._insertChild(prev, payload); |
| this._idToDOMNode[node.id] = node; |
| this.dispatchEventToListeners(WI.DOMManager.Event.NodeInserted, {node, parent}); |
| } |
| |
| _childNodeRemoved(parentId, nodeId) |
| { |
| var parent = this._idToDOMNode[parentId]; |
| var node = this._idToDOMNode[nodeId]; |
| parent._removeChild(node); |
| this._unbind(node); |
| this.dispatchEventToListeners(WI.DOMManager.Event.NodeRemoved, {node, parent}); |
| } |
| |
| _customElementStateChanged(elementId, newState) |
| { |
| const node = this._idToDOMNode[elementId]; |
| node._customElementState = newState; |
| this.dispatchEventToListeners(WI.DOMManager.Event.CustomElementStateChanged, {node}); |
| } |
| |
| _pseudoElementAdded(parentId, pseudoElement) |
| { |
| var parent = this._idToDOMNode[parentId]; |
| if (!parent) |
| return; |
| |
| var node = new WI.DOMNode(this, parent.ownerDocument, false, pseudoElement); |
| node.parentNode = parent; |
| this._idToDOMNode[node.id] = node; |
| console.assert(!parent.pseudoElements().get(node.pseudoType())); |
| parent.pseudoElements().set(node.pseudoType(), node); |
| this.dispatchEventToListeners(WI.DOMManager.Event.NodeInserted, {node, parent}); |
| } |
| |
| _pseudoElementRemoved(parentId, pseudoElementId) |
| { |
| var pseudoElement = this._idToDOMNode[pseudoElementId]; |
| if (!pseudoElement) |
| return; |
| |
| var parent = pseudoElement.parentNode; |
| console.assert(parent); |
| console.assert(parent.id === parentId); |
| if (!parent) |
| return; |
| |
| parent._removeChild(pseudoElement); |
| this._unbind(pseudoElement); |
| this.dispatchEventToListeners(WI.DOMManager.Event.NodeRemoved, {node: pseudoElement, parent}); |
| } |
| |
| _unbind(node) |
| { |
| node.markDestroyed(); |
| |
| delete this._idToDOMNode[node.id]; |
| |
| for (let i = 0; node.children && i < node.children.length; ++i) |
| this._unbind(node.children[i]); |
| |
| let templateContent = node.templateContent(); |
| if (templateContent) |
| this._unbind(templateContent); |
| |
| for (let pseudoElement of node.pseudoElements().values()) |
| this._unbind(pseudoElement); |
| |
| // FIXME: Handle shadow roots. |
| } |
| |
| get restoreSelectedNodeIsAllowed() |
| { |
| return this._restoreSelectedNodeIsAllowed; |
| } |
| |
| inspectElement(nodeId, options = {}) |
| { |
| var node = this._idToDOMNode[nodeId]; |
| if (!node || !node.ownerDocument) |
| return; |
| |
| // This code path is hit by "Reveal in DOM Tree" and clicking element links/console widgets. |
| // Unless overridden by callers, assume that this is navigation is initiated by a Inspect mode. |
| let initiatorHint = options.initiatorHint || WI.TabBrowser.TabNavigationInitiator.Inspect; |
| this.dispatchEventToListeners(WI.DOMManager.Event.DOMNodeWasInspected, {node, initiatorHint}); |
| |
| this._inspectModeEnabled = false; |
| this.dispatchEventToListeners(WI.DOMManager.Event.InspectModeStateChanged); |
| } |
| |
| inspectNodeObject(remoteObject) |
| { |
| this._restoreSelectedNodeIsAllowed = false; |
| |
| function nodeAvailable(nodeId) |
| { |
| remoteObject.release(); |
| |
| console.assert(nodeId); |
| if (!nodeId) |
| return; |
| |
| this.inspectElement(nodeId); |
| |
| // Re-resolve the node in the console's object group when adding to the console. |
| let domNode = this.nodeForId(nodeId); |
| WI.RemoteObject.resolveNode(domNode, WI.RuntimeManager.ConsoleObjectGroup).then((remoteObject) => { |
| const specialLogStyles = true; |
| const shouldRevealConsole = false; |
| WI.consoleLogViewController.appendImmediateExecutionWithResult(WI.UIString("Selected Element"), remoteObject, specialLogStyles, shouldRevealConsole); |
| }); |
| } |
| |
| remoteObject.pushNodeToFrontend(nodeAvailable.bind(this)); |
| } |
| |
| highlightDOMNodeList(nodes, mode) |
| { |
| let target = WI.assumingMainTarget(); |
| |
| // COMPATIBILITY (iOS 11): DOM.highlightNodeList did not exist. |
| if (!target.hasCommand("DOM.highlightNodeList")) |
| return; |
| |
| if (this._hideDOMNodeHighlightTimeout) { |
| clearTimeout(this._hideDOMNodeHighlightTimeout); |
| this._hideDOMNodeHighlightTimeout = undefined; |
| } |
| |
| let nodeIds = []; |
| for (let node of nodes) { |
| console.assert(node instanceof WI.DOMNode, node); |
| console.assert(!node.destroyed, node); |
| if (node.destroyed) |
| continue; |
| nodeIds.push(node.id); |
| } |
| |
| target.DOMAgent.highlightNodeList(nodeIds, DOMManager.buildHighlightConfig(mode)); |
| } |
| |
| highlightSelector(selectorText, frameId, mode) |
| { |
| let target = WI.assumingMainTarget(); |
| |
| // COMPATIBILITY (iOS 8): DOM.highlightSelector did not exist. |
| if (!target.hasCommand("DOM.highlightSelector")) |
| return; |
| |
| if (this._hideDOMNodeHighlightTimeout) { |
| clearTimeout(this._hideDOMNodeHighlightTimeout); |
| this._hideDOMNodeHighlightTimeout = undefined; |
| } |
| |
| target.DOMAgent.highlightSelector(DOMManager.buildHighlightConfig(mode), selectorText, frameId); |
| } |
| |
| highlightRect(rect, usePageCoordinates) |
| { |
| let target = WI.assumingMainTarget(); |
| target.DOMAgent.highlightRect.invoke({ |
| x: rect.x, |
| y: rect.y, |
| width: rect.width, |
| height: rect.height, |
| color: {r: 111, g: 168, b: 220, a: 0.66}, |
| outlineColor: {r: 255, g: 229, b: 153, a: 0.66}, |
| usePageCoordinates |
| }); |
| } |
| |
| hideDOMNodeHighlight() |
| { |
| let target = WI.assumingMainTarget(); |
| target.DOMAgent.hideHighlight(); |
| } |
| |
| highlightDOMNodeForTwoSeconds(nodeId) |
| { |
| let node = this._idToDOMNode[nodeId]; |
| if (!node) |
| return; |
| |
| node.highlight(); |
| |
| this._hideDOMNodeHighlightTimeout = setTimeout(this.hideDOMNodeHighlight.bind(this), 2000); |
| } |
| |
| get inspectModeEnabled() |
| { |
| return this._inspectModeEnabled; |
| } |
| |
| set inspectModeEnabled(enabled) |
| { |
| if (enabled === this._inspectModeEnabled) |
| return; |
| |
| let target = WI.assumingMainTarget(); |
| let commandArguments = { |
| enabled, |
| highlightConfig: DOMManager.buildHighlightConfig(), |
| showRulers: WI.settings.showRulersDuringElementSelection.value, |
| }; |
| target.DOMAgent.setInspectModeEnabled.invoke(commandArguments, (error) => { |
| if (error) { |
| WI.reportInternalError(error); |
| return; |
| } |
| |
| this._inspectModeEnabled = enabled; |
| this.dispatchEventToListeners(WI.DOMManager.Event.InspectModeStateChanged); |
| }); |
| } |
| |
| setInspectedNode(node) |
| { |
| console.assert(node instanceof WI.DOMNode); |
| if (node === this._inspectedNode) |
| return; |
| |
| console.assert(!node.destroyed, node); |
| if (node.destroyed) |
| return; |
| |
| let callback = (error) => { |
| console.assert(!error, error); |
| if (error) |
| return; |
| |
| let lastInspectedNode = this._inspectedNode; |
| this._inspectedNode = node; |
| |
| this.dispatchEventToListeners(WI.DOMManager.Event.InspectedNodeChanged, {lastInspectedNode}); |
| }; |
| |
| let target = WI.assumingMainTarget(); |
| |
| // COMPATIBILITY (iOS 11): DOM.setInspectedNode did not exist. |
| if (!target.hasCommand("DOM.setInspectedNode")) { |
| target.ConsoleAgent.addInspectedNode(node.id, callback); |
| return; |
| } |
| |
| target.DOMAgent.setInspectedNode(node.id, callback); |
| } |
| |
| getSupportedEventNames(callback) |
| { |
| let target = WI.assumingMainTarget(); |
| if (!target.hasCommand("DOM.getSupportedEventNames")) |
| return Promise.resolve(new Set); |
| |
| if (!this._getSupportedEventNamesPromise) { |
| this._getSupportedEventNamesPromise = target.DOMAgent.getSupportedEventNames() |
| .then(({eventNames}) => new Set(eventNames)); |
| } |
| |
| return this._getSupportedEventNamesPromise; |
| } |
| |
| setEventListenerDisabled(eventListener, disabled) |
| { |
| let target = WI.assumingMainTarget(); |
| target.DOMAgent.setEventListenerDisabled(eventListener.eventListenerId, disabled); |
| } |
| |
| setBreakpointForEventListener(eventListener) |
| { |
| let breakpoint = this._breakpointsForEventListeners.get(eventListener.eventListenerId); |
| if (breakpoint) { |
| console.assert(breakpoint.disabled); |
| breakpoint.disabled = false; |
| return; |
| } |
| |
| breakpoint = new WI.EventBreakpoint(WI.EventBreakpoint.Type.Listener, {eventName: eventListener.type, eventListener}); |
| console.assert(!breakpoint.disabled); |
| |
| this._breakpointsForEventListeners.set(eventListener.eventListenerId, breakpoint); |
| |
| for (let target of WI.targets) { |
| if (target.hasDomain("DOM")) |
| this._updateEventBreakpoint(breakpoint, target); |
| } |
| |
| WI.domDebuggerManager.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointAdded, {breakpoint}); |
| } |
| |
| removeBreakpointForEventListener(eventListener) |
| { |
| let breakpoint = this._breakpointsForEventListeners.take(eventListener.eventListenerId); |
| console.assert(breakpoint); |
| |
| for (let target of WI.targets) { |
| if (target.hasDomain("DOM")) |
| target.DOMAgent.removeBreakpointForEventListener(eventListener.eventListenerId); |
| } |
| |
| WI.domDebuggerManager.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointRemoved, {breakpoint}); |
| } |
| |
| removeEventListenerBreakpointsForNode(domNode) |
| { |
| for (let breakpoint of Array.from(this._breakpointsForEventListeners.values())) { |
| let eventListener = breakpoint.eventListener; |
| if (eventListener.nodeId === domNode.id) |
| this.removeBreakpointForEventListener(eventListener); |
| } |
| } |
| |
| breakpointForEventListenerId(eventListenerId) |
| { |
| return this._breakpointsForEventListeners.get(eventListenerId) || null; |
| } |
| |
| // Private |
| |
| _updateEventBreakpoint(breakpoint, target) |
| { |
| let eventListener = breakpoint.eventListener; |
| console.assert(eventListener); |
| |
| if (breakpoint.disabled) |
| target.DOMAgent.removeBreakpointForEventListener(eventListener.eventListenerId); |
| else { |
| if (!WI.debuggerManager.breakpointsDisabledTemporarily) |
| WI.debuggerManager.breakpointsEnabled = true; |
| |
| target.DOMAgent.setBreakpointForEventListener(eventListener.eventListenerId); |
| } |
| } |
| |
| _handleEventBreakpointDisabledStateChanged(event) |
| { |
| let breakpoint = event.target; |
| |
| // Non-specific event listener breakpoints are handled by `DOMDebuggerManager`. |
| if (!breakpoint.eventListener) |
| return; |
| |
| for (let target of WI.targets) { |
| if (target.hasDomain("DOM")) |
| this._updateEventBreakpoint(breakpoint, target); |
| } |
| } |
| |
| _mainResourceDidChange(event) |
| { |
| if (!event.target.isMainFrame()) |
| return; |
| |
| this._restoreSelectedNodeIsAllowed = true; |
| |
| this.ensureDocument(); |
| } |
| }; |
| |
| WI.DOMManager.Event = { |
| AttributeModified: "dom-manager-attribute-modified", |
| AttributeRemoved: "dom-manager-attribute-removed", |
| CharacterDataModified: "dom-manager-character-data-modified", |
| NodeInserted: "dom-manager-node-inserted", |
| NodeRemoved: "dom-manager-node-removed", |
| CustomElementStateChanged: "dom-manager-custom-element-state-changed", |
| DocumentUpdated: "dom-manager-document-updated", |
| ChildNodeCountUpdated: "dom-manager-child-node-count-updated", |
| DOMNodeWasInspected: "dom-manager-dom-node-was-inspected", |
| InspectModeStateChanged: "dom-manager-inspect-mode-state-changed", |
| InspectedNodeChanged: "dom-manager-inspected-node-changed", |
| }; |