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 26WebInspector.Object = function() 27{ 28} 29 30WebInspector.Object.addConstructorFunctions = function(subclassConstructor) 31{ 32 // Copies the relevant functions the subclass constructor. 33 for (var property in WebInspector.Object) { 34 var value = WebInspector.Object[property]; 35 if (typeof value !== "function") 36 continue; 37 if (value === arguments.callee) 38 continue; 39 subclassConstructor[property] = value; 40 } 41} 42 43WebInspector.Object.addEventListener = function(eventType, listener, thisObject) 44{ 45 thisObject = thisObject || null; 46 47 console.assert(eventType, "Object.addEventListener: invalid event type ", eventType, "(listener: ", listener, "thisObject: ", thisObject, ")"); 48 if (!eventType) 49 return; 50 51 console.assert(listener, "Object.addEventListener: invalid listener ", listener, "(event type: ", eventType, "thisObject: ", thisObject, ")"); 52 if (!listener) 53 return; 54 55 if (!this._listeners) 56 this._listeners = {}; 57 58 var listeners = this._listeners[eventType]; 59 if (!listeners) 60 listeners = this._listeners[eventType] = []; 61 62 // Prevent registering multiple times. 63 for (var i = 0; i < listeners.length; ++i) { 64 if (listeners[i].listener === listener && listeners[i].thisObject === thisObject) 65 return; 66 } 67 68 listeners.push({thisObject: thisObject, listener: listener}); 69}; 70 71WebInspector.Object.removeEventListener = function(eventType, listener, thisObject) 72{ 73 eventType = eventType || null; 74 listener = listener || null; 75 thisObject = thisObject || null; 76 77 if (!this._listeners) 78 return; 79 80 if (!eventType) { 81 for (eventType in this._listeners) 82 this.removeEventListener(eventType, listener, thisObject); 83 return; 84 } 85 86 var listeners = this._listeners[eventType]; 87 if (!listeners) 88 return; 89 90 for (var i = listeners.length - 1; i >= 0; --i) { 91 if (listener && listeners[i].listener === listener && listeners[i].thisObject === thisObject) 92 listeners.splice(i, 1); 93 else if (!listener && thisObject && listeners[i].thisObject === thisObject) 94 listeners.splice(i, 1); 95 } 96 97 if (!listeners.length) 98 delete this._listeners[eventType]; 99 100 if (!Object.keys(this._listeners).length) 101 delete this._listeners; 102}; 103 104WebInspector.Object.removeAllListeners = function() 105{ 106 delete this._listeners; 107}; 108 109WebInspector.Object.hasEventListeners = function(eventType) 110{ 111 if (!this._listeners || !this._listeners[eventType]) 112 return false; 113 return true; 114}; 115 116WebInspector.Object.prototype = { 117 constructor: WebInspector.Object, 118 119 addEventListener: WebInspector.Object.addEventListener, 120 121 removeEventListener: WebInspector.Object.removeEventListener, 122 123 removeAllListeners: WebInspector.Object.removeAllListeners, 124 125 hasEventListeners: WebInspector.Object.hasEventListeners, 126 127 dispatchEventToListeners: function(eventType, eventData) 128 { 129 var event = new WebInspector.Event(this, eventType, eventData); 130 131 function dispatch(object) 132 { 133 if (!object || !object._listeners || !object._listeners[eventType] || event._stoppedPropagation) 134 return; 135 136 // Make a copy with slice so mutations during the loop doesn't affect us. 137 var listenersForThisEvent = object._listeners[eventType].slice(0); 138 139 // Iterate over the listeners and call them. Stop if stopPropagation is called. 140 for (var i = 0; i < listenersForThisEvent.length; ++i) { 141 listenersForThisEvent[i].listener.call(listenersForThisEvent[i].thisObject, event); 142 if (event._stoppedPropagation) 143 break; 144 } 145 } 146 147 // Dispatch to listeners of this specific object. 148 dispatch(this); 149 150 // Allow propagation again so listeners on the constructor always have a crack at the event. 151 event._stoppedPropagation = false; 152 153 // Dispatch to listeners on all constructors up the prototype chain, including the immediate constructor. 154 var constructor = this.constructor; 155 while (constructor) { 156 dispatch(constructor); 157 158 if (!constructor.prototype.__proto__) 159 break; 160 161 constructor = constructor.prototype.__proto__.constructor; 162 } 163 164 return event.defaultPrevented; 165 } 166} 167 168WebInspector.Event = function(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 177WebInspector.Event.prototype = { 178 constructor: WebInspector.Event, 179 180 stopPropagation: function() 181 { 182 this._stoppedPropagation = true; 183 }, 184 185 preventDefault: function() 186 { 187 this.defaultPrevented = true; 188 } 189} 190 191WebInspector.notifications = new WebInspector.Object; 192