ES6 Classes: Runtime error in JIT'd class calling super() with arguments and supercla...
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Base / Object.js
1 /*
2  * Copyright (C) 2008, 2013 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WebInspector.Object = class Object
27 {
28     // Static
29
30     static addEventListener(eventType, listener, thisObject)
31     {
32         thisObject = thisObject || null;
33
34         console.assert(eventType, "Object.addEventListener: invalid event type ", eventType, "(listener: ", listener, "thisObject: ", thisObject, ")");
35         if (!eventType)
36             return;
37
38         console.assert(listener, "Object.addEventListener: invalid listener ", listener, "(event type: ", eventType, "thisObject: ", thisObject, ")");
39         if (!listener)
40             return;
41
42         if (!this._listeners)
43             this._listeners = {};
44
45         var listeners = this._listeners[eventType];
46         if (!listeners)
47             listeners = this._listeners[eventType] = [];
48
49         // Prevent registering multiple times.
50         for (var i = 0; i < listeners.length; ++i) {
51             if (listeners[i].listener === listener && listeners[i].thisObject === thisObject)
52                 return;
53         }
54
55         listeners.push({thisObject, listener});
56     }
57
58     static removeEventListener(eventType, listener, thisObject)
59     {
60         eventType = eventType || null;
61         listener = listener || null;
62         thisObject = thisObject || null;
63
64         if (!this._listeners)
65             return;
66
67         if (!eventType) {
68             for (eventType in this._listeners)
69                 this.removeEventListener(eventType, listener, thisObject);
70             return;
71         }
72
73         var listeners = this._listeners[eventType];
74         if (!listeners)
75             return;
76
77         for (var i = listeners.length - 1; i >= 0; --i) {
78             if (listener && listeners[i].listener === listener && listeners[i].thisObject === thisObject)
79                 listeners.splice(i, 1);
80             else if (!listener && thisObject && listeners[i].thisObject === thisObject)
81                 listeners.splice(i, 1);
82         }
83
84         if (!listeners.length)
85             delete this._listeners[eventType];
86
87         if (!Object.keys(this._listeners).length)
88             delete this._listeners;
89     }
90
91     static removeAllListeners()
92     {
93         delete this._listeners;
94     }
95
96     static hasEventListeners(eventType)
97     {
98         if (!this._listeners || !this._listeners[eventType])
99             return false;
100         return true;
101     }
102
103     // Public
104
105     addEventListener() { return WebInspector.Object.addEventListener.apply(this, arguments); }
106     removeEventListener() { return WebInspector.Object.removeEventListener.apply(this, arguments); }
107     removeAllListeners() { return WebInspector.Object.removeAllListeners.apply(this, arguments); }
108     hasEventListeners() { return WebInspector.Object.hasEventListeners.apply(this, arguments); }
109
110     dispatchEventToListeners(eventType, eventData)
111     {
112         var event = new WebInspector.Event(this, eventType, eventData);
113
114         function dispatch(object)
115         {
116             if (!object || !object._listeners || !object._listeners[eventType] || event._stoppedPropagation)
117                 return;
118
119             // Make a copy with slice so mutations during the loop doesn't affect us.
120             var listenersForThisEvent = object._listeners[eventType].slice(0);
121
122             // Iterate over the listeners and call them. Stop if stopPropagation is called.
123             for (var i = 0; i < listenersForThisEvent.length; ++i) {
124                 listenersForThisEvent[i].listener.call(listenersForThisEvent[i].thisObject, event);
125                 if (event._stoppedPropagation)
126                     break;
127             }
128         }
129
130         // Dispatch to listeners of this specific object.
131         dispatch(this);
132
133         // Allow propagation again so listeners on the constructor always have a crack at the event.
134         event._stoppedPropagation = false;
135
136         // Dispatch to listeners on all constructors up the prototype chain, including the immediate constructor.
137         var constructor = this.constructor;
138         while (constructor) {
139             dispatch(constructor);
140
141             if (!constructor.prototype.__proto__)
142                 break;
143
144             constructor = constructor.prototype.__proto__.constructor;
145         }
146
147         return event.defaultPrevented;
148     }
149 };
150
151 // FIXME: Uses arguments.callee, so it cannot be in the class.
152 WebInspector.Object.deprecatedAddConstructorFunctions = function(subclassConstructor)
153 {
154     // Copies the relevant functions to the subclass constructor.
155     var list = ["addEventListener", "removeEventListener", "removeAllListeners", "hasEventListeners"];
156     for (var property of list) {
157         var value = WebInspector.Object[property];
158         if (typeof value !== "function")
159             continue;
160         if (value === arguments.callee)
161             continue;
162         subclassConstructor[property] = value;
163     }
164 };
165
166 WebInspector.Event = class Event
167 {
168     constructor(target, type, data)
169     {
170         this.target = target;
171         this.type = type;
172         this.data = data;
173         this.defaultPrevented = false;
174         this._stoppedPropagation = false;
175     }
176
177     stopPropagation()
178     {
179         this._stoppedPropagation = true;
180     }
181
182     preventDefault()
183     {
184         this.defaultPrevented = true;
185     }
186 };
187
188 WebInspector.notifications = new WebInspector.Object;
189
190 WebInspector.Notification = {
191     GlobalModifierKeysDidChange: "global-modifiers-did-change",
192     PageArchiveStarted: "page-archive-started",
193     PageArchiveEnded: "page-archive-ended",
194     ExtraDomainsActivated: "extra-domains-activated",
195 };