Changeset 223321 in webkit
- Timestamp:
- Oct 14, 2017 11:56:32 AM (7 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r223320 r223321 1 2017-10-14 Devin Rousso <webkit@devinrousso.com> 2 3 Web Inspector: provide a way to enable/disable event listeners 4 https://bugs.webkit.org/show_bug.cgi?id=177451 5 6 Reviewed by Joseph Pecoraro. 7 8 * inspector/dom/setEventListenerDisabled-expected.txt: Added. 9 * inspector/dom/setEventListenerDisabled.html: Added. 10 1 11 2017-10-14 Per Arne Vollan <pvollan@apple.com> 2 12 -
trunk/Source/JavaScriptCore/ChangeLog
r223318 r223321 1 2017-10-14 Devin Rousso <webkit@devinrousso.com> 2 3 Web Inspector: provide a way to enable/disable event listeners 4 https://bugs.webkit.org/show_bug.cgi?id=177451 5 6 Reviewed by Joseph Pecoraro. 7 8 * inspector/protocol/DOM.json: 9 Add `setEventListenerDisabled` command that enables/disables a specific event listener 10 during event dispatch. When a disabled event listener is fired, the listener's callback will 11 not be called. 12 1 13 2017-10-14 Yusuke Suzuki <utatane.tea@gmail.com> 2 14 -
trunk/Source/JavaScriptCore/inspector/protocol/DOM.json
r222486 r223321 13 13 "type": "integer", 14 14 "description": "Unique DOM node identifier used to reference a node that may not have been pushed to the front-end." 15 }, 16 { 17 "id": "EventListenerId", 18 "type": "integer", 19 "description": "Unique event listener identifier." 15 20 }, 16 21 { … … 75 80 "description": "A structure holding event listener properties.", 76 81 "properties": [ 82 { "name": "eventListenerId", "$ref": "EventListenerId" }, 77 83 { "name": "type", "type": "string", "description": "<code>EventListener</code>'s type." }, 78 84 { "name": "useCapture", "type": "boolean", "description": "<code>EventListener</code>'s useCapture." }, … … 84 90 { "name": "handler", "$ref": "Runtime.RemoteObject", "optional": true, "description": "Event handler function value." }, 85 91 { "name": "passive", "type": "boolean", "optional": true, "description": "<code>EventListener</code>'s passive." }, 86 { "name": "once", "type": "boolean", "optional": true, "description": "<code>EventListener</code>'s once." } 92 { "name": "once", "type": "boolean", "optional": true, "description": "<code>EventListener</code>'s once." }, 93 { "name": "disabled", "type": "boolean", "optional": true } 87 94 ] 88 95 }, … … 260 267 }, 261 268 { 269 "name": "setEventListenerDisabled", 270 "description": "Enable/disable the given event listener. A disabled event listener will not fire.", 271 "parameters": [ 272 { "name": "eventListenerId", "$ref": "EventListenerId" }, 273 { "name": "disabled", "type": "boolean" } 274 ] 275 }, 276 { 262 277 "name": "getAccessibilityPropertiesForNode", 263 278 "description": "Returns a dictionary of accessibility properties for the node.", -
trunk/Source/WebCore/ChangeLog
r223317 r223321 1 2017-10-14 Devin Rousso <webkit@devinrousso.com> 2 3 Web Inspector: provide a way to enable/disable event listeners 4 https://bugs.webkit.org/show_bug.cgi?id=177451 5 6 Reviewed by Joseph Pecoraro. 7 8 Test: inspector/dom/setEventListenerDisabled.html 9 10 * dom/EventTarget.cpp: 11 (WebCore::EventTarget::fireEventListeners): 12 Add InspectorInstrumentation call to isEventListenerDisabled. If true, the event listener's 13 callback will not be called. 14 15 * inspector/InspectorDOMAgent.h: 16 * inspector/InspectorDOMAgent.cpp: 17 (WebCore::InspectorDOMAgent::discardBindings): 18 (WebCore::InspectorDOMAgent::getEventListenersForNode): 19 (WebCore::InspectorDOMAgent::setEventListenerDisabled): 20 (WebCore::InspectorDOMAgent::buildObjectForEventListener): 21 (WebCore::InspectorDOMAgent::willRemoveEventListener): 22 (WebCore::InspectorDOMAgent::isEventListenerDisabled): 23 Introduce a mapping of `EventListener*` to `InspectorEventListener`, a struct for uniquely 24 identifying event listeners so they can be referenced from the frontend. We only add items 25 to this mapping when `getEventListenersForNode` is called, as that is when EventListener 26 data is sent to the frontend. This allows us to defer creating an Inspector "mirror" object 27 for each EventListener until it is needed. Items are removed whenever an event listener is 28 removed or when the document changes. 29 30 * inspector/InspectorInstrumentation.h: 31 (WebCore::InspectorInstrumentation::isEventListenerDisabled): 32 * inspector/InspectorInstrumentation.cpp: 33 (WebCore::InspectorInstrumentation::willRemoveEventListenerImpl): 34 (WebCore::InspectorInstrumentation::isEventListenerDisabledImpl): 35 Pass additional parameters to InspectorDOMAgent so it can determine if the event listener 36 actually exists. If not, don't dispatch an event to the frontend as nothing will change. 37 1 38 2017-10-14 Sam Weinig <sam@webkit.org> 2 39 -
trunk/Source/WebCore/dom/EventTarget.cpp
r222064 r223321 279 279 continue; 280 280 281 if (InspectorInstrumentation::isEventListenerDisabled(*this, event.type(), registeredListener->callback(), registeredListener->useCapture())) 282 continue; 283 281 284 // If stopImmediatePropagation has been called, we just break out immediately, without 282 285 // handling any more events on this target. -
trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp
r222486 r223321 487 487 m_documentNodeToIdMap.clear(); 488 488 m_idToNode.clear(); 489 m_eventListenerEntries.clear(); 489 490 releaseDanglingNodes(); 490 491 m_childrenRequested.clear(); … … 831 832 getEventListeners(node, eventInformation, true); 832 833 834 auto addListener = [&] (RegisteredEventListener& listener, const EventListenerInfo& info) { 835 int identifier = 0; 836 bool disabled = false; 837 838 auto it = m_eventListenerEntries.find(&listener.callback()); 839 if (it == m_eventListenerEntries.end()) { 840 InspectorEventListener inspectorEventListener(m_lastEventListenerId++, *info.node, info.eventType, listener.useCapture()); 841 m_eventListenerEntries.add(&listener.callback(), inspectorEventListener); 842 843 identifier = inspectorEventListener.identifier; 844 disabled = inspectorEventListener.disabled; 845 } else { 846 identifier = it->value.identifier; 847 disabled = it->value.disabled; 848 } 849 850 listenersArray->addItem(buildObjectForEventListener(listener, identifier, info.eventType, info.node, objectGroup, disabled)); 851 }; 852 833 853 // Get Capturing Listeners (in this order) 834 854 size_t eventInformationLength = eventInformation.size(); … … 836 856 for (auto& listener : info.eventListenerVector) { 837 857 if (listener->useCapture()) 838 listenersArray->addItem(buildObjectForEventListener(*listener, info.eventType, info.node, objectGroup));858 addListener(*listener, info); 839 859 } 840 860 } … … 845 865 for (auto& listener : info.eventListenerVector) { 846 866 if (!listener->useCapture()) 847 listenersArray->addItem(buildObjectForEventListener(*listener, info.eventType, info.node, objectGroup));867 addListener(*listener, info); 848 868 } 849 869 } … … 880 900 } 881 901 } 902 } 903 904 void InspectorDOMAgent::setEventListenerDisabled(ErrorString& errorString, int eventListenerId, bool disabled) 905 { 906 for (InspectorEventListener& inspectorEventListener : m_eventListenerEntries.values()) { 907 if (inspectorEventListener.identifier == eventListenerId) { 908 inspectorEventListener.disabled = disabled; 909 return; 910 } 911 } 912 913 errorString = ASCIILiteral("No event listener for given identifier."); 882 914 } 883 915 … … 1555 1587 } 1556 1588 1557 Ref<Inspector::Protocol::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node, const String* objectGroupId)1589 Ref<Inspector::Protocol::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, int identifier, const AtomicString& eventType, Node* node, const String* objectGroupId, bool disabled) 1558 1590 { 1559 1591 Ref<EventListener> eventListener = registeredEventListener.callback(); … … 1586 1618 1587 1619 auto value = Inspector::Protocol::DOM::EventListener::create() 1620 .setEventListenerId(identifier) 1588 1621 .setType(eventType) 1589 1622 .setUseCapture(registeredEventListener.useCapture()) … … 1611 1644 if (registeredEventListener.isOnce()) 1612 1645 value->setOnce(true); 1646 if (disabled) 1647 value->setDisabled(disabled); 1613 1648 return value; 1614 1649 } … … 2221 2256 } 2222 2257 2223 void InspectorDOMAgent::willRemoveEventListener(EventTarget& target )2258 void InspectorDOMAgent::willRemoveEventListener(EventTarget& target, const AtomicString& eventType, EventListener& listener, bool capture) 2224 2259 { 2225 2260 Node* node = target.toNode(); … … 2231 2266 return; 2232 2267 2268 bool listenerExists = false; 2269 for (const RefPtr<RegisteredEventListener>& item : node->eventListeners(eventType)) { 2270 if (item->callback() == listener && item->useCapture() == capture) { 2271 listenerExists = true; 2272 break; 2273 } 2274 } 2275 2276 if (!listenerExists) 2277 return; 2278 2279 m_eventListenerEntries.remove(&listener); 2280 2233 2281 m_frontendDispatcher->willRemoveEventListener(nodeId); 2282 } 2283 2284 bool InspectorDOMAgent::isEventListenerDisabled(EventTarget& target, const AtomicString& eventType, EventListener& listener, bool capture) 2285 { 2286 auto it = m_eventListenerEntries.find(&listener); 2287 if (it == m_eventListenerEntries.end()) 2288 return false; 2289 2290 if (!it->value.disabled) 2291 return false; 2292 2293 return it->value.eventTarget.get() == &target && it->value.eventType == eventType && it->value.useCapture == capture; 2234 2294 } 2235 2295 -
trunk/Source/WebCore/inspector/InspectorDOMAgent.h
r222486 r223321 124 124 void setNodeValue(ErrorString&, int nodeId, const String& value) override; 125 125 void getEventListenersForNode(ErrorString&, int nodeId, const WTF::String* const objectGroup, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::DOM::EventListener>>& listenersArray) override; 126 void setEventListenerDisabled(ErrorString&, int eventListenerId, bool disabled) override; 126 127 void getAccessibilityPropertiesForNode(ErrorString&, int nodeId, RefPtr<Inspector::Protocol::DOM::AccessibilityProperties>& axProperties) override; 127 128 void performSearch(ErrorString&, const String& whitespaceTrimmedQuery, const Inspector::InspectorArray* nodeIds, String* searchId, int* resultCount) override; … … 169 170 void pseudoElementDestroyed(PseudoElement&); 170 171 void didAddEventListener(EventTarget&); 171 void willRemoveEventListener(EventTarget&); 172 void willRemoveEventListener(EventTarget&, const AtomicString& eventType, EventListener&, bool capture); 173 bool isEventListenerDisabled(EventTarget&, const AtomicString& eventType, EventListener&, bool capture); 172 174 173 175 // Callbacks that don't directly correspond to an instrumentation entry point. … … 233 235 Ref<Inspector::Protocol::Array<Inspector::Protocol::DOM::Node>> buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap); 234 236 RefPtr<Inspector::Protocol::Array<Inspector::Protocol::DOM::Node>> buildArrayForPseudoElements(const Element&, NodeToIdMap* nodesMap); 235 Ref<Inspector::Protocol::DOM::EventListener> buildObjectForEventListener(const RegisteredEventListener&, const AtomicString& eventType, Node*, const String* objectGroupId);237 Ref<Inspector::Protocol::DOM::EventListener> buildObjectForEventListener(const RegisteredEventListener&, int identifier, const AtomicString& eventType, Node*, const String* objectGroupId, bool disabled = false); 236 238 RefPtr<Inspector::Protocol::DOM::AccessibilityProperties> buildObjectForAccessibilityProperties(Node*); 237 239 void processAccessibilityChildren(RefPtr<AccessibilityObject>&&, RefPtr<Inspector::Protocol::Array<int>>&&); … … 274 276 bool m_suppressAttributeModifiedEvent { false }; 275 277 bool m_documentRequested { false }; 278 279 struct InspectorEventListener { 280 int identifier { 1 }; 281 RefPtr<EventTarget> eventTarget; 282 AtomicString eventType; 283 bool useCapture { false }; 284 bool disabled { false }; 285 286 InspectorEventListener() { } 287 288 InspectorEventListener(int identifier, EventTarget& eventTarget, const AtomicString& eventType, bool useCapture) 289 : identifier(identifier) 290 , eventTarget(&eventTarget) 291 , eventType(eventType) 292 , useCapture(useCapture) 293 { 294 } 295 }; 296 297 HashMap<EventListener*, InspectorEventListener> m_eventListenerEntries; 298 int m_lastEventListenerId { 1 }; 276 299 }; 277 300 -
trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp
r222739 r223321 328 328 pageDebuggerAgent->willRemoveEventListener(target, eventType, listener, capture); 329 329 if (InspectorDOMAgent* domAgent = instrumentingAgents.inspectorDOMAgent()) 330 domAgent->willRemoveEventListener(target); 330 domAgent->willRemoveEventListener(target, eventType, listener, capture); 331 } 332 333 bool InspectorInstrumentation::isEventListenerDisabledImpl(InstrumentingAgents& instrumentingAgents, EventTarget& target, const AtomicString& eventType, EventListener& listener, bool capture) 334 { 335 if (InspectorDOMAgent* domAgent = instrumentingAgents.inspectorDOMAgent()) 336 return domAgent->isEventListenerDisabled(target, eventType, listener, capture); 337 return false; 331 338 } 332 339 -
trunk/Source/WebCore/inspector/InspectorInstrumentation.h
r222739 r223321 147 147 static void didAddEventListener(EventTarget&, const AtomicString& eventType); 148 148 static void willRemoveEventListener(EventTarget&, const AtomicString& eventType, EventListener&, bool capture); 149 static bool isEventListenerDisabled(EventTarget&, const AtomicString& eventType, EventListener&, bool capture); 149 150 static InspectorInstrumentationCookie willDispatchEvent(Document&, const Event&, bool hasEventListeners); 150 151 static void didDispatchEvent(const InspectorInstrumentationCookie&); … … 324 325 static void didAddEventListenerImpl(InstrumentingAgents&, EventTarget&, const AtomicString& eventType); 325 326 static void willRemoveEventListenerImpl(InstrumentingAgents&, EventTarget&, const AtomicString& eventType, EventListener&, bool capture); 327 static bool isEventListenerDisabledImpl(InstrumentingAgents&, EventTarget&, const AtomicString& eventType, EventListener&, bool capture); 326 328 static InspectorInstrumentationCookie willDispatchEventImpl(InstrumentingAgents&, Document&, const Event&, bool hasEventListeners); 327 329 static void willHandleEventImpl(InstrumentingAgents&, const Event&, const RegisteredEventListener&); … … 688 690 } 689 691 692 inline bool InspectorInstrumentation::isEventListenerDisabled(EventTarget& target, const AtomicString& eventType, EventListener& listener, bool capture) 693 { 694 FAST_RETURN_IF_NO_FRONTENDS(false); 695 if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(target.scriptExecutionContext())) 696 return isEventListenerDisabledImpl(*instrumentingAgents, target, eventType, listener, capture); 697 return false; 698 } 699 690 700 inline void InspectorInstrumentation::didPostMessage(Frame& frame, TimerBase& timer, JSC::ExecState& state) 691 701 { -
trunk/Source/WebInspectorUI/ChangeLog
r223310 r223321 1 2017-10-14 Devin Rousso <webkit@devinrousso.com> 2 3 Web Inspector: provide a way to enable/disable event listeners 4 https://bugs.webkit.org/show_bug.cgi?id=177451 5 6 Reviewed by Joseph Pecoraro. 7 8 * Localizations/en.lproj/localizedStrings.js: 9 10 * UserInterface/Controllers/DOMTreeManager.js: 11 (WI.DOMTreeManager.prototype.setEventListenerDisabled): 12 13 * UserInterface/Views/DOMNodeDetailsSidebarPanel.js: 14 (WI.DOMNodeDetailsSidebarPanel.prototype.attached): 15 (WI.DOMNodeDetailsSidebarPanel.prototype.detached): 16 (WI.DOMNodeDetailsSidebarPanel.prototype._eventListenersChanged): 17 (WI.DOMNodeDetailsSidebarPanel.prototype.addEventListeners): Deleted. 18 (WI.DOMNodeDetailsSidebarPanel.prototype.removeEventListeners): Deleted. 19 Listen for `WI.DOMNode.Event.EventListenersChanged` on all instances of WI.DOMNode, since we 20 will still want to refresh the event listeners section in the event that an event listener 21 is removed from a parent node. 22 23 * UserInterface/Views/EventListenerSectionGroup.js: 24 (WI.EventListenerSectionGroup): 25 (WI.EventListenerSectionGroup.prototype._eventText): 26 (WI.EventListenerSectionGroup.prototype._nodeTextOrLink): 27 (WI.EventListenerSectionGroup.prototype._createDisabledToggleElement): 28 (WI.EventListenerSectionGroup.prototype._createDisabledToggleElement.updateTitle): 29 * UserInterface/Views/EventListenerSectionGroup.css: 30 (.event-listener-section > .content input[type="checkbox"]): 31 32 * UserInterface/Views/DetailsSectionSimpleRow.js: 33 (WI.DetailsSectionSimpleRow.prototype.get label): 34 (WI.DetailsSectionSimpleRow.prototype.set label): 35 1 36 2017-10-13 Devin Rousso <webkit@devinrousso.com> 2 37 -
trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
r223078 r223321 294 294 localizedStrings["Disable Breakpoint"] = "Disable Breakpoint"; 295 295 localizedStrings["Disable Breakpoints"] = "Disable Breakpoints"; 296 localizedStrings["Disable Event Listener"] = "Disable Event Listener"; 296 297 localizedStrings["Disable Program"] = "Disable Program"; 297 298 localizedStrings["Disable all breakpoints (%s)"] = "Disable all breakpoints (%s)"; … … 359 360 localizedStrings["Enable Breakpoints"] = "Enable Breakpoints"; 360 361 localizedStrings["Enable Canvas Tab"] = "Enable Canvas Tab"; 362 localizedStrings["Enable Event Listener"] = "Enable Event Listener"; 361 363 localizedStrings["Enable Layers Tab"] = "Enable Layers Tab"; 362 364 localizedStrings["Enable Program"] = "Enable Program"; … … 364 366 localizedStrings["Enable breakpoints"] = "Enable breakpoints"; 365 367 localizedStrings["Enable paint flashing"] = "Enable paint flashing"; 368 localizedStrings["Enabled"] = "Enabled"; 366 369 localizedStrings["Encoded"] = "Encoded"; 367 370 localizedStrings["Encoding"] = "Encoding"; -
trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMTreeManager.js
r222486 r223321 527 527 } 528 528 529 setEventListenerDisabled(eventListenerId, disabled) 530 { 531 DOMAgent.setEventListenerDisabled(eventListenerId, disabled); 532 } 533 529 534 _buildHighlightConfig(mode = "all") 530 535 { -
trunk/Source/WebInspectorUI/UserInterface/Views/DOMNodeDetailsSidebarPanel.js
r223137 r223321 44 44 45 45 super.closed(); 46 }47 48 addEventListeners()49 {50 this.domNode.addEventListener(WI.DOMNode.Event.EventListenersChanged, this._eventListenersChanged, this);51 }52 53 removeEventListeners()54 {55 this.domNode.removeEventListener(WI.DOMNode.Event.EventListenersChanged, this._eventListenersChanged, this);56 46 } 57 47 … … 168 158 // FIXME: <https://webkit.org/b/152269> Web Inspector: Convert DetailsSection classes to use View 169 159 this._attributesDataGridRow.sizeDidChange(); 160 } 161 162 attached() 163 { 164 super.attached(); 165 166 WI.DOMNode.addEventListener(WI.DOMNode.Event.EventListenersChanged, this._eventListenersChanged, this); 167 } 168 169 detached() 170 { 171 WI.DOMNode.removeEventListener(WI.DOMNode.Event.EventListenersChanged, this._eventListenersChanged, this); 172 173 super.detached(); 170 174 } 171 175 … … 754 758 _eventListenersChanged(event) 755 759 { 756 this._refreshEventListeners(); 760 if (event.target === this.domNode || event.target.isAncestor(this.domNode)) 761 this._refreshEventListeners(); 757 762 } 758 763 -
trunk/Source/WebInspectorUI/UserInterface/Views/DetailsSectionSimpleRow.js
r220119 r223321 74 74 get label() 75 75 { 76 return this._label Element.textContent;76 return this._label; 77 77 } 78 78 79 79 set label(label) 80 80 { 81 this._labelElement.textContent = label; 81 this._label = label || ""; 82 83 if (this._label instanceof Node) { 84 this._labelElement.removeChildren(); 85 this._labelElement.appendChild(this._label); 86 } else 87 this._labelElement.textContent = this._label; 82 88 } 83 89 -
trunk/Source/WebInspectorUI/UserInterface/Views/EventListenerSectionGroup.css
r164543 r223321 29 29 text-overflow: ellipsis; 30 30 } 31 32 .event-listener-section > .content input[type="checkbox"] { 33 width: 12px; 34 height: 12px; 35 margin: 0; 36 } -
trunk/Source/WebInspectorUI/UserInterface/Views/EventListenerSectionGroup.js
r220119 r223321 53 53 rows.push(new WI.DetailsSectionSimpleRow(WI.UIString("Once"), WI.UIString("Yes"))); 54 54 55 if (DOMAgent.setEventListenerDisabled) 56 rows.push(this._createDisabledToggleRow()); 57 55 58 this.rows = rows; 56 59 } … … 105 108 return fragment; 106 109 } 110 111 _createDisabledToggleRow() 112 { 113 let toggleElement = document.createElement("input"); 114 toggleElement.type = "checkbox"; 115 toggleElement.checked = !this._eventListener.disabled; 116 117 let updateTitle = () => { 118 if (this._eventListener.disabled) 119 toggleElement.title = WI.UIString("Enable Event Listener"); 120 else 121 toggleElement.title = WI.UIString("Disable Event Listener"); 122 }; 123 124 updateTitle(); 125 126 toggleElement.addEventListener("change", (event) => { 127 this._eventListener.disabled = !toggleElement.checked; 128 WI.domTreeManager.setEventListenerDisabled(this._eventListener.eventListenerId, this._eventListener.disabled); 129 updateTitle(); 130 }); 131 132 let toggleLabel = document.createElement("span"); 133 toggleLabel.textContent = WI.UIString("Enabled"); 134 toggleLabel.addEventListener("click", (event) => { 135 toggleElement.click(); 136 }); 137 138 return new WI.DetailsSectionSimpleRow(toggleLabel, toggleElement); 139 } 107 140 };
Note: See TracChangeset
for help on using the changeset viewer.