Title: [172396] trunk
Revision
172396
Author
[email protected]
Date
2014-08-11 11:10:25 -0700 (Mon, 11 Aug 2014)

Log Message

Web Inspector: Add a helper to avoid leaking single-fire event listeners in Promise chains
https://bugs.webkit.org/show_bug.cgi?id=135772

Reviewed by Timothy Hatcher.

Source/WebInspectorUI:

A common pattern when working with promise chains is to convert an event
handler into a promise by using a single-fire event listener with the
resolve continuation as the callback. This is fine if the event fires;
if it doesn't fire, then the event emitter permanently keeps a reference to the
this-object and the callback.

This patch adds EventListener, a proxy object for events that can be manipulated
from multiple promise callback functions. If a promise is rejected, the catch
block can disconnect any event listeners set up earlier in the promise chain.

This patch also reimplements EventListenerSet to use multiple EventListeners,
since they share the same logic to uniformly handle Inspector and DOM events.

Test: inspector/event-listener.html
Test: inspector/event-listener-set.html

* UserInterface/Base/EventListener.js: Added.
(WebInspector.EventListener):
(WebInspector.EventListener.prototype.this._callback):
(WebInspector.EventListener.prototype.connect):
(WebInspector.EventListener.prototype.disconnect):
* UserInterface/Base/EventListenerSet.js: Update license block.
(WebInspector.EventListenerSet.prototype.register):
(WebInspector.EventListenerSet.prototype.install):
(WebInspector.EventListenerSet.prototype.uninstall):
* UserInterface/Main.html: Include EventListener.
* UserInterface/Test.html: Include EventListener and EventListenerSet.

LayoutTests:

* inspector/event-listener-expected.txt: Added.
* inspector/event-listener-set-expected.txt: Added.
* inspector/event-listener-set.html: Added.
* inspector/event-listener.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (172395 => 172396)


--- trunk/LayoutTests/ChangeLog	2014-08-11 17:52:15 UTC (rev 172395)
+++ trunk/LayoutTests/ChangeLog	2014-08-11 18:10:25 UTC (rev 172396)
@@ -1,3 +1,15 @@
+2014-08-11  Brian J. Burg  <[email protected]>
+
+        Web Inspector: Add a helper to avoid leaking single-fire event listeners in Promise chains
+        https://bugs.webkit.org/show_bug.cgi?id=135772
+
+        Reviewed by Timothy Hatcher.
+
+        * inspector/event-listener-expected.txt: Added.
+        * inspector/event-listener-set-expected.txt: Added.
+        * inspector/event-listener-set.html: Added.
+        * inspector/event-listener.html: Added.
+
 2014-08-10  Oliver Hunt  <[email protected]>
 
         Destructuring assignment in a var declaration list incorrectly consumes subsequent variable initialisers

Added: trunk/LayoutTests/inspector/event-listener-expected.txt (0 => 172396)


--- trunk/LayoutTests/inspector/event-listener-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/inspector/event-listener-expected.txt	2014-08-11 18:10:25 UTC (rev 172396)
@@ -0,0 +1,16 @@
+Testing basic functionality of WebInspector.EventListener.
+
+Connecting the listener.
+Invoked callback for kaboom event.
+Invoked callback for kaboom event.
+Disconnecting the listener.
+Connecting the listener.
+Invoked callback for kaboom event.
+Disconnecting the listener.
+Connecting the listener.
+Disconnecting the listener.
+Connecting the single-fire listener.
+Invoked callback for kaboom event.
+Disconnecting the single-fire listener.
+Invoked callback for kaboom event.
+

Added: trunk/LayoutTests/inspector/event-listener-set-expected.txt (0 => 172396)


--- trunk/LayoutTests/inspector/event-listener-set-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/inspector/event-listener-set-expected.txt	2014-08-11 18:10:25 UTC (rev 172396)
@@ -0,0 +1,25 @@
+Testing basic functionality of WebInspector.EventListenerSet.
+
+Registering listeners.
+Installing listeners.
+Dispatching events.
+Invoked callback for foo event.
+Invoked callback for bar event.
+Invoked callback for baz event.
+Uninstalling and disconnecting listeners.
+Registering listeners.
+Dispatching events.
+Invoked callback for foo event.
+Invoked callback for bar event.
+Invoked callback for baz event.
+Uninstalling listeners.
+Installing listeners.
+Dispatching events.
+Invoked callback for foo event.
+Invoked callback for bar event.
+Invoked callback for baz event.
+Unregistering everything.
+Dispatching events.
+Unintalling and disconnecting listeners.
+Dispatching events.
+

Added: trunk/LayoutTests/inspector/event-listener-set.html (0 => 172396)


--- trunk/LayoutTests/inspector/event-listener-set.html	                        (rev 0)
+++ trunk/LayoutTests/inspector/event-listener-set.html	2014-08-11 18:10:25 UTC (rev 172396)
@@ -0,0 +1,117 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/_javascript_" src=""
+<script>
+function test()
+{
+    const FooEvent = "foo";
+    const BarEvent = "bar";
+    const BazEvent = "baz";
+    var emitter1 = new WebInspector.Object();
+    var emitter2 = new WebInspector.Object();
+    var context1 = new WebInspector.Object();
+    var context2 = new WebInspector.Object();
+    var data1 = [1, 2, 3];
+    var data2 = [4, 6, 8];
+
+    function fooCallback(event)
+    {
+        InspectorTest.assert(this === context1, "Callback invoked with wrong |this| binding.");
+        InspectorTest.assert(event.target === emitter1, "Callback invoked with wrong event emitter.");
+        InspectorTest.assert(event.data ="" data1, "Callback invoked with wrong event data.");
+
+        InspectorTest.log("Invoked callback for foo event.");
+    }
+
+    function barCallback(event)
+    {
+        InspectorTest.assert(this === context1, "Callback invoked with wrong |this| binding.");
+        InspectorTest.assert(event.target === emitter1, "Callback invoked with wrong event emitter.");
+        InspectorTest.assert(event.data ="" data2, "Callback invoked with wrong event data.");
+
+        InspectorTest.log("Invoked callback for bar event.");
+    }
+
+    function bazCallback(event)
+    {
+        InspectorTest.assert(this === context2, "Callback invoked with wrong |this| binding.");
+        InspectorTest.assert(event.target === emitter2, "Callback invoked with wrong event emitter.");
+        InspectorTest.assert(event.data ="" data2, "Callback invoked with wrong event data.");
+
+        InspectorTest.log("Invoked callback for baz event.");
+    }
+
+    // Test for multiple firings of listeners in the set.
+
+    var listenerSet = new WebInspector.EventListenerSet(context1);
+    InspectorTest.assert(!emitter1.hasEventListeners(FooEvent), "Emitter should not have any listeners.");
+    emitter1.dispatchEventToListeners(FooEvent, data1); // Should not fire anything.
+
+    InspectorTest.log("Registering listeners.");
+    listenerSet.register(emitter1, FooEvent, fooCallback);
+    listenerSet.register(emitter1, BarEvent, barCallback);
+    listenerSet.register(emitter2, BazEvent, bazCallback, context2);
+    InspectorTest.assert(!emitter1.hasEventListeners(FooEvent), "Emitter should not have a listener.");
+    InspectorTest.assert(!emitter1.hasEventListeners(BarEvent), "Emitter should not have a listener.");
+    InspectorTest.assert(!emitter2.hasEventListeners(BazEvent), "Emitter should not have a listener.");
+
+    InspectorTest.log("Installing listeners.");
+    listenerSet.install();
+    InspectorTest.assert(emitter1.hasEventListeners(FooEvent), "Emitter should have a listener.");
+    InspectorTest.assert(emitter1.hasEventListeners(BarEvent), "Emitter should have a listener.");
+    InspectorTest.assert(emitter2.hasEventListeners(BazEvent), "Emitter should have a listener.");
+
+    InspectorTest.log("Dispatching events.");
+    emitter1.dispatchEventToListeners(FooEvent, data1); // Should fire.
+    emitter1.dispatchEventToListeners(BarEvent, data2); // Should fire.
+    emitter2.dispatchEventToListeners(BazEvent, data2); // Should fire.
+    InspectorTest.log("Uninstalling and disconnecting listeners.");
+    listenerSet.uninstall(true);
+
+    InspectorTest.log("Registering listeners.");
+    listenerSet.register(emitter1, FooEvent, fooCallback);
+    listenerSet.register(emitter1, BarEvent, barCallback);
+    listenerSet.register(emitter2, BazEvent, bazCallback, context2);
+
+    listenerSet.install();
+    InspectorTest.log("Dispatching events.");
+    emitter1.dispatchEventToListeners(FooEvent, data1); // Should fire.
+    emitter1.dispatchEventToListeners(BarEvent, data2); // Should fire.
+    emitter2.dispatchEventToListeners(BazEvent, data2); // Should fire.
+    InspectorTest.log("Uninstalling listeners.");
+    listenerSet.uninstall();
+
+    InspectorTest.log("Installing listeners.");
+    listenerSet.install();
+    InspectorTest.log("Dispatching events.");
+    emitter1.dispatchEventToListeners(FooEvent, data1); // Should fire.
+    emitter1.dispatchEventToListeners(BarEvent, data2); // Should fire.
+    emitter2.dispatchEventToListeners(BazEvent, data2); // Should fire.
+
+    InspectorTest.log("Unregistering everything.");
+    listenerSet.unregister();
+    InspectorTest.log("Dispatching events.");
+    emitter1.dispatchEventToListeners(FooEvent, data1); // Should not fire.
+    emitter1.dispatchEventToListeners(BarEvent, data2); // Should not fire.
+    emitter2.dispatchEventToListeners(BazEvent, data2); // Should not fire.
+
+    InspectorTest.log("Unintalling and disconnecting listeners.");
+    listenerSet.uninstall(true);
+    InspectorTest.log("Dispatching events.");
+    emitter1.dispatchEventToListeners(FooEvent, data1); // Should not fire.
+    emitter1.dispatchEventToListeners(BarEvent, data2); // Should not fire.
+    emitter2.dispatchEventToListeners(BazEvent, data2); // Should not fire.
+
+    InspectorTest.assert(!emitter1.hasEventListeners(FooEvent), "Emitter should not have a listener.");
+    InspectorTest.assert(!emitter1.hasEventListeners(BarEvent), "Emitter should not have a listener.");
+    InspectorTest.assert(!emitter2.hasEventListeners(BazEvent), "Emitter should not have a listener.");
+
+    InspectorTest.completeTest();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+    <p>Testing basic functionality of WebInspector.EventListenerSet.</p>
+</body>
+</html>

Added: trunk/LayoutTests/inspector/event-listener.html (0 => 172396)


--- trunk/LayoutTests/inspector/event-listener.html	                        (rev 0)
+++ trunk/LayoutTests/inspector/event-listener.html	2014-08-11 18:10:25 UTC (rev 172396)
@@ -0,0 +1,93 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/_javascript_" src=""
+<script>
+function test()
+{
+    const KaboomEvent = "kaboom";
+    var emitter = new WebInspector.Object();
+    var context = new WebInspector.Object();
+    var data = "" 2, 3];
+
+    function kaboomCallback(event) {
+        InspectorTest.assert(this === context, "Callback invoked with wrong |this| binding.");
+        InspectorTest.assert(event.target === emitter, "Callback invoked with wrong event emitter.");
+        InspectorTest.assert(event.data ="" data, "Callback invoked with wrong event data.");
+
+        InspectorTest.log("Invoked callback for kaboom event.");
+    }
+
+    // Test for multiple firings of the listener.
+
+    var listener = new WebInspector.EventListener(context);
+    InspectorTest.assert(!emitter.hasEventListeners(KaboomEvent), "Emitter should not have any listeners.");
+    emitter.dispatchEventToListeners(KaboomEvent, data); // Should not fire anything.
+
+    InspectorTest.log("Connecting the listener.");
+    listener.connect(emitter, KaboomEvent, kaboomCallback);
+    InspectorTest.assert(emitter.hasEventListeners(KaboomEvent), "Emitter should have a listener.");
+    emitter.dispatchEventToListeners(KaboomEvent, data); // Should fire.
+    emitter.dispatchEventToListeners(KaboomEvent, data); // Should fire.
+    InspectorTest.log("Disconnecting the listener.");
+    listener.disconnect();
+
+    emitter.dispatchEventToListeners(KaboomEvent, data); // Should not fire anything.
+    InspectorTest.assert(!emitter.hasEventListeners(KaboomEvent), "Emitter should not have any listeners.");
+
+    // Test reconnection.
+
+    InspectorTest.log("Connecting the listener.");
+    listener.connect(emitter, KaboomEvent, kaboomCallback);
+    emitter.dispatchEventToListeners(KaboomEvent, data); // Should fire.
+    InspectorTest.log("Disconnecting the listener.");
+    listener.disconnect();
+
+    // Test unused listener.
+
+    InspectorTest.log("Connecting the listener.");
+    listener.connect(emitter, KaboomEvent, kaboomCallback);
+    InspectorTest.log("Disconnecting the listener.");
+    listener.disconnect();
+
+    // Test for single firing of the listener.
+
+    var singleListener = new WebInspector.EventListener(context, true);
+    InspectorTest.assert(!emitter.hasEventListeners(KaboomEvent), "Emitter should not have any listeners.");
+    emitter.dispatchEventToListeners(KaboomEvent, data); // Should not fire anything.
+
+    InspectorTest.log("Connecting the single-fire listener.");
+    singleListener.connect(emitter, KaboomEvent, kaboomCallback);
+    InspectorTest.assert(emitter.hasEventListeners(KaboomEvent), "Emitter should have a listener.");
+    emitter.dispatchEventToListeners(KaboomEvent, data); // Should fire.
+    InspectorTest.assert(!emitter.hasEventListeners(KaboomEvent), "Emitter should not have any listeners.");
+    emitter.dispatchEventToListeners(KaboomEvent, data); // Should not fire.
+    InspectorTest.log("Disconnecting the single-fire listener.");
+    singleListener.disconnect(); // Should cause an error.
+    emitter.dispatchEventToListeners(KaboomEvent, data); // Should not fire.
+
+    // Test for various error cases and abuse.
+
+    var badListener = new WebInspector.EventListener(context);
+    badListener.connect(data, data, data); // Should complain about non-callable callback.
+    badListener.connect(null, KaboomEvent, kaboomCallback); // Should complain about non-callable callback.
+    badListener.connect(emitter, KaboomEvent, null); // Should complain about non-callable callback.
+    badListener.connect(emitter, null, kaboomCallback); // Should complain about null event.
+
+    var badListener2 = new WebInspector.EventListener(context);
+    badListener2.disconnect(); // Should complain about already disconnected.
+    badListener2.connect(emitter, KaboomEvent, kaboomCallback);
+    badListener2.connect(emitter, KaboomEvent, kaboomCallback); // Should complain about already connected.
+    emitter.dispatchEventToListeners(KaboomEvent, data); // Should fire.
+    badListener2.connect(emitter, KaboomEvent, kaboomCallback); // Should complain about already connected.
+    badListener2.disconnect();
+    badListener2.disconnect(); // Should complain about already disconnected.
+
+    InspectorTest.completeTest();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+    <p>Testing basic functionality of WebInspector.EventListener.</p>
+</body>
+</html>

Modified: trunk/Source/WebInspectorUI/ChangeLog (172395 => 172396)


--- trunk/Source/WebInspectorUI/ChangeLog	2014-08-11 17:52:15 UTC (rev 172395)
+++ trunk/Source/WebInspectorUI/ChangeLog	2014-08-11 18:10:25 UTC (rev 172396)
@@ -1,3 +1,38 @@
+2014-08-11  Brian J. Burg  <[email protected]>
+
+        Web Inspector: Add a helper to avoid leaking single-fire event listeners in Promise chains
+        https://bugs.webkit.org/show_bug.cgi?id=135772
+
+        Reviewed by Timothy Hatcher.
+
+        A common pattern when working with promise chains is to convert an event
+        handler into a promise by using a single-fire event listener with the
+        resolve continuation as the callback. This is fine if the event fires;
+        if it doesn't fire, then the event emitter permanently keeps a reference to the
+        this-object and the callback.
+
+        This patch adds EventListener, a proxy object for events that can be manipulated
+        from multiple promise callback functions. If a promise is rejected, the catch
+        block can disconnect any event listeners set up earlier in the promise chain.
+
+        This patch also reimplements EventListenerSet to use multiple EventListeners,
+        since they share the same logic to uniformly handle Inspector and DOM events.
+
+        Test: inspector/event-listener.html
+        Test: inspector/event-listener-set.html
+
+        * UserInterface/Base/EventListener.js: Added.
+        (WebInspector.EventListener):
+        (WebInspector.EventListener.prototype.this._callback):
+        (WebInspector.EventListener.prototype.connect):
+        (WebInspector.EventListener.prototype.disconnect):
+        * UserInterface/Base/EventListenerSet.js: Update license block.
+        (WebInspector.EventListenerSet.prototype.register):
+        (WebInspector.EventListenerSet.prototype.install):
+        (WebInspector.EventListenerSet.prototype.uninstall):
+        * UserInterface/Main.html: Include EventListener.
+        * UserInterface/Test.html: Include EventListener and EventListenerSet.
+
 2014-08-10  Timothy Hatcher  <[email protected]>
 
         Web Inspector: new glyphs are visible on OS X 10.9 builds

Added: trunk/Source/WebInspectorUI/UserInterface/Base/EventListener.js (0 => 172396)


--- trunk/Source/WebInspectorUI/UserInterface/Base/EventListener.js	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/EventListener.js	2014-08-11 18:10:25 UTC (rev 172396)
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2013, 2014 University of Washington. All rights reserved.
+ * Copyright (C) 2014 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. ``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
+ * 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.EventListener = function(thisObject, fireOnce)
+{
+    this._thisObject = thisObject;
+    this._emitter = null;
+    this._callback = null;
+    this._fireOnce = fireOnce;
+}
+
+WebInspector.EventListener.prototype = {
+    connect: function(emitter, type, callback, usesCapture)
+    {
+        console.assert(!this._emitter && !this._callback, "EventListener already bound to a callback.", this);
+        console.assert(callback, "Missing callback for event: " + type);
+        console.assert(emitter, "Missing event emitter for event: " + type);
+        var emitterIsValid = emitter && (emitter instanceof WebInspector.Object || emitter instanceof Node || (typeof emitter.addEventListener === "function"));
+        console.assert(emitterIsValid,  "Event emitter ", emitter, " (type:" + type + ") is null or does not implement Node or WebInspector.Object!");
+
+        if (!emitterIsValid || !type || !callback)
+            return;
+
+        this._emitter = emitter;
+        this._type = type;
+        this._usesCapture = !!usesCapture;
+
+        if (emitter instanceof Node)
+            callback = callback.bind(this._thisObject);
+
+        if (this._fireOnce) {
+            var listener = this;
+            this._callback = function() {
+                listener.disconnect();
+                callback.apply(this, arguments);
+            }
+        } else
+            this._callback = callback;
+
+        if (this._emitter instanceof Node)
+            this._emitter.addEventListener(this._type, this._callback, this._usesCapture);
+        else
+            this._emitter.addEventListener(this._type, this._callback, this._thisObject);
+    },
+
+    disconnect: function()
+    {
+        console.assert(this._emitter && this._callback, "EventListener is not bound to a callback.", this);
+
+        if (!this._emitter || !this._callback)
+            return;
+
+        if (this._emitter instanceof Node)
+            this._emitter.removeEventListener(this._type, this._callback, this._usesCapture);
+        else
+            this._emitter.removeEventListener(this._type, this._callback, this._thisObject);
+
+        if (this._fireOnce)
+            delete this._thisObject;
+        delete this._emitter;
+        delete this._type;
+        delete this._callback;
+    }
+};

Modified: trunk/Source/WebInspectorUI/UserInterface/Base/EventListenerSet.js (172395 => 172396)


--- trunk/Source/WebInspectorUI/UserInterface/Base/EventListenerSet.js	2014-08-11 17:52:15 UTC (rev 172395)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/EventListenerSet.js	2014-08-11 18:10:25 UTC (rev 172396)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 University of Washington. All rights reserved.
+ * Copyright (C) 2013, 2014 University of Washington. All rights reserved.
  * Copyright (C) 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -11,15 +11,15 @@
  *    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 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
- * HOLDER 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
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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
+ * 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.
  */
@@ -38,16 +38,17 @@
 }
 
 WebInspector.EventListenerSet.prototype = {
-    register: function(emitter, type, listener, thisObject, useCapture)
+    register: function(emitter, type, callback, thisObject, usesCapture)
     {
-        console.assert(listener, "Missing listener for event: " + type);
-        console.assert(emitter, "Missing event emitter for event: " + type);
-        console.assert(emitter instanceof WebInspector.Object || emitter instanceof Node || (typeof emitter.addEventListener === "function"), "Event emitter", emitter, " (type:" + type + ") does not implement Node or WebInspector.Object!");
+        console.assert(callback, "Missing callback for event: " + type);
+        console.assert(type, "Tried to register listener for unknown event: " + type);
+        var emitterIsValid = emitter && (emitter instanceof WebInspector.Object || emitter instanceof Node || (typeof emitter.addEventListener === "function"));
+        console.assert(emitterIsValid,  "Event emitter ", emitter, " (type:" + type + ") is null or does not implement Node or WebInspector.Object!");
 
-        if (emitter instanceof Node)
-            listener = listener.bind(thisObject || this._defaultThisObject);
+        if (!emitterIsValid || !type || !callback)
+            return;
 
-        this._listeners.push({emitter: emitter, type: type, listener: listener, thisObject: thisObject, useCapture: useCapture});
+        this._listeners.push({listener: new WebInspector.EventListener(thisObject || this._defaultThisObject), emitter: emitter, type: type, callback: callback, usesCapture: usesCapture});
     },
 
     unregister: function()
@@ -60,33 +61,27 @@
     install: function()
     {
         console.assert(!this._installed, "Already installed listener group: " + this.name);
+        if (this._installed)
+            return;
 
         this._installed = true;
 
-        for (var listenerData of this._listeners) {
-            if (listenerData.emitter instanceof Node)
-                listenerData.emitter.addEventListener(listenerData.type, listenerData.listener, listenerData.useCapture);
-            else
-                listenerData.emitter.addEventListener(listenerData.type, listenerData.listener, listenerData.thisObject || this._defaultThisObject);
-        }
+        for (var data of this._listeners)
+            data.listener.connect(data.emitter, data.type, data.callback, data.usesCapture);
     },
 
     uninstall: function(unregisterListeners)
     {
         console.assert(this._installed, "Trying to uninstall listener group " + this.name + ", but it isn't installed.");
+        if (!this._installed)
+            return;
 
         this._installed = false;
 
-        for (var listenerData of this._listeners) {
-            if (listenerData.emitter instanceof Node)
-                listenerData.emitter.removeEventListener(listenerData.type, listenerData.listener, listenerData.useCapture);
-            else
-                listenerData.emitter.removeEventListener(listenerData.type, listenerData.listener, listenerData.thisObject || this._defaultThisObject);
-        }
+        for (var data of this._listeners)
+            data.listener.disconnect();
 
-        if (unregisterListeners) {
+        if (unregisterListeners)
             this._listeners = [];
-            delete this._defaultThisObject;
-        }
     },
 }

Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (172395 => 172396)


--- trunk/Source/WebInspectorUI/UserInterface/Main.html	2014-08-11 17:52:15 UTC (rev 172395)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html	2014-08-11 18:10:25 UTC (rev 172396)
@@ -165,6 +165,7 @@
     <script src=""
 
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""

Modified: trunk/Source/WebInspectorUI/UserInterface/Test.html (172395 => 172396)


--- trunk/Source/WebInspectorUI/UserInterface/Test.html	2014-08-11 17:52:15 UTC (rev 172395)
+++ trunk/Source/WebInspectorUI/UserInterface/Test.html	2014-08-11 18:10:25 UTC (rev 172396)
@@ -35,6 +35,8 @@
     <script src=""
 
     <script src=""
+    <script src=""
+    <script src=""
     <script src=""
     <script src=""
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to