Diff
Modified: trunk/LayoutTests/ChangeLog (142626 => 142627)
--- trunk/LayoutTests/ChangeLog 2013-02-12 15:56:28 UTC (rev 142626)
+++ trunk/LayoutTests/ChangeLog 2013-02-12 16:01:27 UTC (rev 142627)
@@ -1,3 +1,15 @@
+2013-02-12 Peter Rybin <[email protected]>
+
+ Web Inspector: for event listener provide handler function value in protocol and in UI
+ https://bugs.webkit.org/show_bug.cgi?id=109284
+
+ Reviewed by Yury Semikhatsky.
+
+ Test is rebased.
+
+ * inspector/elements/event-listener-sidebar-expected.txt:
+ * inspector/elements/event-listeners-about-blank-expected.txt:
+
2013-02-12 Andrey Lushnikov <[email protected]>
Web Inspector: refactor some reusable functionality from BraceHighlighter
Modified: trunk/LayoutTests/inspector/elements/event-listener-sidebar-expected.txt (142626 => 142627)
--- trunk/LayoutTests/inspector/elements/event-listener-sidebar-expected.txt 2013-02-12 15:56:28 UTC (rev 142626)
+++ trunk/LayoutTests/inspector/elements/event-listener-sidebar-expected.txt 2013-02-12 16:01:27 UTC (rev 142627)
@@ -4,6 +4,7 @@
======== click ========
[expanded] document event-listener-sidebar.html:19
+ handler: function (event) { console.log("click - document - capturing"); }
isAttribute: false
lineNumber: 19
listenerBody: function (event) { console.log("click - document - capturing"); }
@@ -12,12 +13,14 @@
type: click
useCapture: true
[expanded] document (anonymous function)
+ handler: ObjectHandler
isAttribute: false
listenerBody: ObjectHandler
node: #document
type: click
useCapture: true
[expanded] button#node event-listener-sidebar.html:15
+ handler: function (event) { console.log("click - button - capturing"); }
isAttribute: false
lineNumber: 15
listenerBody: function (event) { console.log("click - button - capturing"); }
@@ -26,6 +29,7 @@
type: click
useCapture: true
[expanded] button#node event-listener-sidebar.html:12
+ handler: function clickHandler(event) { console.log("click - button - bubbling (registered before attribute)"); }
isAttribute: false
lineNumber: 12
listenerBody: function clickHandler(event) { console.log("click - button - bubbling (registered before attribute)"); }
@@ -34,6 +38,7 @@
type: click
useCapture: false
[expanded] button#node event-listener-sidebar.html:16
+ handler: function (event) { console.log("click - button - attribute"); }
isAttribute: true
lineNumber: 16
listenerBody: function (event) { console.log("click - button - attribute"); }
@@ -42,6 +47,7 @@
type: click
useCapture: false
[expanded] button#node event-listener-sidebar.html:17
+ handler: function (event) { console.log("click - button - bubbling (registered after attribute)"); }
isAttribute: false
lineNumber: 17
listenerBody: function (event) { console.log("click - button - bubbling (registered after attribute)"); }
@@ -50,6 +56,7 @@
type: click
useCapture: false
[expanded] document event-listener-sidebar.html:6
+ handler: function documentClickHandler(event) { console.log("click - document - attribute"); }
isAttribute: true
lineNumber: 6
listenerBody: function documentClickHandler(event) { console.log("click - document - attribute"); }
@@ -60,6 +67,7 @@
======== custom event ========
[expanded] body event-listener-sidebar.html:10
+ handler: function f() {}
isAttribute: false
lineNumber: 10
listenerBody: function f() {}
@@ -70,6 +78,7 @@
======== hover ========
[expanded] button#node event-listener-sidebar.html:14
+ handler: function hoverHandler(event) { console.log("hover - button - bubbling"); }
isAttribute: false
lineNumber: 14
listenerBody: function hoverHandler(event) { console.log("hover - button - bubbling"); }
@@ -80,6 +89,7 @@
======== click ========
[expanded] document event-listener-sidebar.html:19
+ handler: function (event) { console.log("click - document - capturing"); }
isAttribute: false
lineNumber: 19
listenerBody: function (event) { console.log("click - document - capturing"); }
@@ -88,12 +98,14 @@
type: click
useCapture: true
[expanded] document (anonymous function)
+ handler: ObjectHandler
isAttribute: false
listenerBody: ObjectHandler
node: #document
type: click
useCapture: true
[expanded] document event-listener-sidebar.html:6
+ handler: function documentClickHandler(event) { console.log("click - document - attribute"); }
isAttribute: true
lineNumber: 6
listenerBody: function documentClickHandler(event) { console.log("click - document - attribute"); }
@@ -104,6 +116,7 @@
======== custom event ========
[expanded] body event-listener-sidebar.html:10
+ handler: function f() {}
isAttribute: false
lineNumber: 10
listenerBody: function f() {}
Modified: trunk/LayoutTests/inspector/elements/event-listeners-about-blank-expected.txt (142626 => 142627)
--- trunk/LayoutTests/inspector/elements/event-listeners-about-blank-expected.txt 2013-02-12 15:56:28 UTC (rev 142626)
+++ trunk/LayoutTests/inspector/elements/event-listeners-about-blank-expected.txt 2013-02-12 16:01:27 UTC (rev 142627)
@@ -4,6 +4,7 @@
======== click ========
[expanded] body event-listeners-about-blank.html:9
+ handler: function f() {}
isAttribute: false
lineNumber: 9
listenerBody: function f() {}
@@ -14,6 +15,7 @@
======== hover ========
[expanded] div#div-in-iframe event-listeners-about-blank.html:9
+ handler: function f() {}
isAttribute: false
lineNumber: 9
listenerBody: function f() {}
Modified: trunk/Source/WebCore/ChangeLog (142626 => 142627)
--- trunk/Source/WebCore/ChangeLog 2013-02-12 15:56:28 UTC (rev 142626)
+++ trunk/Source/WebCore/ChangeLog 2013-02-12 16:01:27 UTC (rev 142627)
@@ -1,3 +1,37 @@
+2013-02-12 Peter Rybin <[email protected]>
+
+ Web Inspector: for event listener provide handler function value in protocol and in UI
+ https://bugs.webkit.org/show_bug.cgi?id=109284
+
+ Reviewed by Yury Semikhatsky.
+
+ The feature implies that we include a real handler function value into event listener description.
+ Protocol description, inspector DOM agent (with V8 and JSC backends) and front-end is patched accordingly.
+
+ * bindings/js/ScriptEventListener.cpp:
+ (WebCore::eventListenerHandler):
+ (WebCore):
+ (WebCore::eventListenerHandlerScriptState):
+ * bindings/js/ScriptEventListener.h:
+ (WebCore):
+ * bindings/v8/ScriptEventListener.cpp:
+ (WebCore::eventListenerHandler):
+ (WebCore):
+ (WebCore::eventListenerHandlerScriptState):
+ * bindings/v8/ScriptEventListener.h:
+ (WebCore):
+ * inspector/Inspector.json:
+ * inspector/InspectorDOMAgent.cpp:
+ (WebCore::InspectorDOMAgent::getEventListenersForNode):
+ (WebCore::InspectorDOMAgent::buildObjectForEventListener):
+ * inspector/InspectorDOMAgent.h:
+ (InspectorDOMAgent):
+ * inspector/front-end/DOMAgent.js:
+ (WebInspector.DOMNode.prototype.eventListeners):
+ * inspector/front-end/EventListenersSidebarPane.js:
+ (WebInspector.EventListenersSidebarPane.prototype.update):
+ (.):
+
2013-02-12 Yury Semikhatsky <[email protected]>
Web Inspector: add initial implementation of native memory graph to Timeline
Modified: trunk/Source/WebCore/bindings/js/ScriptEventListener.cpp (142626 => 142627)
--- trunk/Source/WebCore/bindings/js/ScriptEventListener.cpp 2013-02-12 15:56:28 UTC (rev 142626)
+++ trunk/Source/WebCore/bindings/js/ScriptEventListener.cpp 2013-02-12 16:01:27 UTC (rev 142627)
@@ -106,6 +106,31 @@
return jsFunction->toString(scriptState)->value(scriptState);
}
+ScriptValue eventListenerHandler(Document* document, EventListener* eventListener)
+{
+ const JSEventListener* jsListener = JSEventListener::cast(eventListener);
+ ASSERT(jsListener);
+ if (!jsListener)
+ return ScriptValue();
+ JSLockHolder lock(jsListener->isolatedWorld()->globalData());
+ JSC::JSObject* jsFunction = jsListener->jsFunction(document);
+ if (!jsFunction)
+ return ScriptValue();
+ return ScriptValue(*jsListener->isolatedWorld()->globalData(), jsFunction);
+}
+
+ScriptState* eventListenerHandlerScriptState(Frame* frame, EventListener* eventListener)
+{
+ const JSEventListener* jsListener = JSEventListener::cast(eventListener);
+ ASSERT(jsListener);
+ if (!jsListener)
+ return 0;
+ if (!frame->script()->canExecuteScripts(NotAboutToExecuteScript))
+ return 0;
+ DOMWrapperWorld* world = jsListener->isolatedWorld();
+ return frame->script()->globalObject(world)->globalExec();
+}
+
bool eventListenerHandlerLocation(Document* document, EventListener* eventListener, String& sourceName, String& scriptId, int& lineNumber)
{
const JSEventListener* jsListener = JSEventListener::cast(eventListener);
Modified: trunk/Source/WebCore/bindings/js/ScriptEventListener.h (142626 => 142627)
--- trunk/Source/WebCore/bindings/js/ScriptEventListener.h 2013-02-12 15:56:28 UTC (rev 142626)
+++ trunk/Source/WebCore/bindings/js/ScriptEventListener.h 2013-02-12 16:01:27 UTC (rev 142627)
@@ -33,6 +33,7 @@
#include "JSLazyEventListener.h"
#include "ScriptState.h"
+#include "ScriptValue.h"
#include <wtf/PassRefPtr.h>
@@ -46,6 +47,8 @@
PassRefPtr<JSLazyEventListener> createAttributeEventListener(Node*, const QualifiedName&, const AtomicString& value);
PassRefPtr<JSLazyEventListener> createAttributeEventListener(Frame*, const QualifiedName&, const AtomicString& value);
String eventListenerHandlerBody(Document*, EventListener*);
+ ScriptValue eventListenerHandler(Document*, EventListener*);
+ ScriptState* eventListenerHandlerScriptState(Frame*, EventListener*);
bool eventListenerHandlerLocation(Document*, EventListener*, String& sourceName, String& scriptId, int& lineNumber);
} // namespace WebCore
Modified: trunk/Source/WebCore/bindings/v8/ScriptEventListener.cpp (142626 => 142627)
--- trunk/Source/WebCore/bindings/v8/ScriptEventListener.cpp 2013-02-12 15:56:28 UTC (rev 142626)
+++ trunk/Source/WebCore/bindings/v8/ScriptEventListener.cpp 2013-02-12 16:01:27 UTC (rev 142627)
@@ -103,6 +103,31 @@
return toWebCoreStringWithNullCheck(function);
}
+ScriptValue eventListenerHandler(Document* document, EventListener* listener)
+{
+ if (listener->type() != EventListener::JSEventListenerType)
+ return ScriptValue();
+
+ v8::HandleScope scope;
+ V8AbstractEventListener* v8Listener = static_cast<V8AbstractEventListener*>(listener);
+ v8::Handle<v8::Context> context = toV8Context(document, v8Listener->worldContext());
+ v8::Context::Scope contextScope(context);
+ v8::Handle<v8::Object> function = v8Listener->getListenerObject(document);
+ if (function.IsEmpty())
+ return ScriptValue();
+ return ScriptValue(function);
+}
+
+ScriptState* eventListenerHandlerScriptState(Frame* frame, EventListener* listener)
+{
+ if (listener->type() != EventListener::JSEventListenerType)
+ return 0;
+ V8AbstractEventListener* v8Listener = static_cast<V8AbstractEventListener*>(listener);
+ v8::HandleScope scope;
+ v8::Handle<v8::Context> v8Context = v8Listener->worldContext().adjustedContext(frame->script());
+ return ScriptState::forContext(*v8Context);
+}
+
bool eventListenerHandlerLocation(Document* document, EventListener* listener, String& sourceName, String& scriptId, int& lineNumber)
{
if (listener->type() != EventListener::JSEventListenerType)
Modified: trunk/Source/WebCore/bindings/v8/ScriptEventListener.h (142626 => 142627)
--- trunk/Source/WebCore/bindings/v8/ScriptEventListener.h 2013-02-12 15:56:28 UTC (rev 142626)
+++ trunk/Source/WebCore/bindings/v8/ScriptEventListener.h 2013-02-12 16:01:27 UTC (rev 142627)
@@ -31,6 +31,7 @@
#ifndef ScriptEventListener_h
#define ScriptEventListener_h
+#include "ScriptValue.h"
#include "V8LazyEventListener.h"
#include <wtf/PassRefPtr.h>
@@ -46,6 +47,8 @@
PassRefPtr<V8LazyEventListener> createAttributeEventListener(Node*, const QualifiedName&, const AtomicString& value);
PassRefPtr<V8LazyEventListener> createAttributeEventListener(Frame*, const QualifiedName&, const AtomicString& value);
String eventListenerHandlerBody(Document*, EventListener*);
+ ScriptValue eventListenerHandler(Document*, EventListener*);
+ ScriptState* eventListenerHandlerScriptState(Frame*, EventListener*);
bool eventListenerHandlerLocation(Document*, EventListener*, String& sourceName, String& scriptId, int& lineNumber);
} // namespace WebCore
Modified: trunk/Source/WebCore/inspector/Inspector.json (142626 => 142627)
--- trunk/Source/WebCore/inspector/Inspector.json 2013-02-12 15:56:28 UTC (rev 142626)
+++ trunk/Source/WebCore/inspector/Inspector.json 2013-02-12 16:01:27 UTC (rev 142627)
@@ -1755,7 +1755,8 @@
{ "name": "nodeId", "$ref": "NodeId", "description": "Target <code>DOMNode</code> id." },
{ "name": "handlerBody", "type": "string", "description": "Event handler function body." },
{ "name": "location", "$ref": "Debugger.Location", "optional": true, "description": "Handler code location." },
- { "name": "sourceName", "type": "string", "optional": true, "description": "Source script URL." }
+ { "name": "sourceName", "type": "string", "optional": true, "description": "Source script URL." },
+ { "name": "handler", "$ref": "Runtime.RemoteObject", "optional": true, "description": "Event handler function value." }
],
"description": "DOM interaction is implemented in terms of mirror objects that represent the actual DOM nodes. DOMNode is a base node mirror type."
},
@@ -1876,7 +1877,8 @@
{
"name": "getEventListenersForNode",
"parameters": [
- { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to get listeners for." }
+ { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to get listeners for." },
+ { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name for handler value. Handler value is not returned without this parameter specified." }
],
"returns": [
{ "name": "listeners", "type": "array", "items": { "$ref": "EventListener"}, "description": "Array of relevant listeners." }
Modified: trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp (142626 => 142627)
--- trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp 2013-02-12 15:56:28 UTC (rev 142626)
+++ trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp 2013-02-12 16:01:27 UTC (rev 142627)
@@ -762,7 +762,7 @@
m_domEditor->replaceWholeText(toText(node), value, errorString);
}
-void InspectorDOMAgent::getEventListenersForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::DOM::EventListener> >& listenersArray)
+void InspectorDOMAgent::getEventListenersForNode(ErrorString* errorString, int nodeId, const String* objectGroup, RefPtr<TypeBuilder::Array<TypeBuilder::DOM::EventListener> >& listenersArray)
{
listenersArray = TypeBuilder::Array<TypeBuilder::DOM::EventListener>::create();
Node* node = assertNode(errorString, nodeId);
@@ -779,7 +779,7 @@
for (size_t j = 0; j < vector.size(); ++j) {
const RegisteredEventListener& listener = vector[j];
if (listener.useCapture)
- listenersArray->addItem(buildObjectForEventListener(listener, info.eventType, info.node));
+ listenersArray->addItem(buildObjectForEventListener(listener, info.eventType, info.node, objectGroup));
}
}
@@ -790,7 +790,7 @@
for (size_t j = 0; j < vector.size(); ++j) {
const RegisteredEventListener& listener = vector[j];
if (!listener.useCapture)
- listenersArray->addItem(buildObjectForEventListener(listener, info.eventType, info.node));
+ listenersArray->addItem(buildObjectForEventListener(listener, info.eventType, info.node, objectGroup));
}
}
}
@@ -1376,15 +1376,32 @@
return children.release();
}
-PassRefPtr<TypeBuilder::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node)
+PassRefPtr<TypeBuilder::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node, const String* objectGroupId)
{
RefPtr<EventListener> eventListener = registeredEventListener.listener;
+ Document* document = node->document();
RefPtr<TypeBuilder::DOM::EventListener> value = TypeBuilder::DOM::EventListener::create()
.setType(eventType)
.setUseCapture(registeredEventListener.useCapture)
.setIsAttribute(eventListener->isAttribute())
.setNodeId(pushNodePathToFrontend(node))
- .setHandlerBody(eventListenerHandlerBody(node->document(), eventListener.get()));
+ .setHandlerBody(eventListenerHandlerBody(document, eventListener.get()));
+ if (objectGroupId) {
+ ScriptValue functionValue = eventListenerHandler(document, eventListener.get());
+ if (!functionValue.hasNoValue()) {
+ Frame* frame = document->frame();
+ if (frame) {
+ ScriptState* scriptState = eventListenerHandlerScriptState(frame, eventListener.get());
+ if (scriptState) {
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState);
+ if (!injectedScript.hasNoValue()) {
+ RefPtr<TypeBuilder::Runtime::RemoteObject> valueJson = injectedScript.wrapObject(functionValue, *objectGroupId, true);
+ value->setHandler(valueJson);
+ }
+ }
+ }
+ }
+ }
String sourceName;
String scriptId;
int lineNumber;
Modified: trunk/Source/WebCore/inspector/InspectorDOMAgent.h (142626 => 142627)
--- trunk/Source/WebCore/inspector/InspectorDOMAgent.h 2013-02-12 15:56:28 UTC (rev 142626)
+++ trunk/Source/WebCore/inspector/InspectorDOMAgent.h 2013-02-12 16:01:27 UTC (rev 142627)
@@ -131,7 +131,7 @@
virtual void getOuterHTML(ErrorString*, int nodeId, WTF::String* outerHTML);
virtual void setOuterHTML(ErrorString*, int nodeId, const String& outerHTML);
virtual void setNodeValue(ErrorString*, int nodeId, const String& value);
- virtual void getEventListenersForNode(ErrorString*, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::DOM::EventListener> >& listenersArray);
+ virtual void getEventListenersForNode(ErrorString*, int nodeId, const WTF::String* objectGroup, RefPtr<TypeBuilder::Array<TypeBuilder::DOM::EventListener> >& listenersArray);
virtual void performSearch(ErrorString*, const String& whitespaceTrimmedQuery, String* searchId, int* resultCount);
virtual void getSearchResults(ErrorString*, const String& searchId, int fromIndex, int toIndex, RefPtr<TypeBuilder::Array<int> >&);
virtual void discardSearchResults(ErrorString*, const String& searchId);
@@ -227,7 +227,7 @@
PassRefPtr<TypeBuilder::DOM::Node> buildObjectForNode(Node*, int depth, NodeToIdMap*);
PassRefPtr<TypeBuilder::Array<String> > buildArrayForElementAttributes(Element*);
PassRefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap);
- PassRefPtr<TypeBuilder::DOM::EventListener> buildObjectForEventListener(const RegisteredEventListener&, const AtomicString& eventType, Node*);
+ PassRefPtr<TypeBuilder::DOM::EventListener> buildObjectForEventListener(const RegisteredEventListener&, const AtomicString& eventType, Node*, const String* objectGroupId);
Node* nodeForPath(const String& path);
Modified: trunk/Source/WebCore/inspector/front-end/DOMAgent.js (142626 => 142627)
--- trunk/Source/WebCore/inspector/front-end/DOMAgent.js 2013-02-12 15:56:28 UTC (rev 142626)
+++ trunk/Source/WebCore/inspector/front-end/DOMAgent.js 2013-02-12 16:01:27 UTC (rev 142627)
@@ -363,11 +363,12 @@
},
/**
+ * @param {string} objectGroupId
* @param {function(?Protocol.Error)=} callback
*/
- eventListeners: function(callback)
+ eventListeners: function(objectGroupId, callback)
{
- DOMAgent.getEventListenersForNode(this.id, callback);
+ DOMAgent.getEventListenersForNode(this.id, objectGroupId, callback);
},
/**
Modified: trunk/Source/WebCore/inspector/front-end/EventListenersSidebarPane.js (142626 => 142627)
--- trunk/Source/WebCore/inspector/front-end/EventListenersSidebarPane.js 2013-02-12 15:56:28 UTC (rev 142626)
+++ trunk/Source/WebCore/inspector/front-end/EventListenersSidebarPane.js 2013-02-12 16:01:27 UTC (rev 142627)
@@ -119,7 +119,7 @@
}
if (node)
- node.eventListeners(callback);
+ node.eventListeners(WebInspector.EventListenersSidebarPane._objectGroupName, callback);
this._selectedNode = node;
},
@@ -202,6 +202,10 @@
properties.push(WebInspector.RemoteObjectProperty.fromPrimitiveValue("isAttribute", this.eventListener.isAttribute));
if (nodeObject)
properties.push(new WebInspector.RemoteObjectProperty("node", nodeObject));
+ if (typeof this.eventListener.handler !== "undefined") {
+ var remoteObject = WebInspector.RemoteObject.fromPayload(this.eventListener.handler);
+ properties.push(new WebInspector.RemoteObjectProperty("handler", remoteObject));
+ }
if (typeof this.eventListener.handlerBody !== "undefined")
properties.push(WebInspector.RemoteObjectProperty.fromPrimitiveValue("listenerBody", this.eventListener.handlerBody));
if (this.eventListener.sourceName)