| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 var eventBindingsNatives = requireNative('event_bindings'); | 5 var eventBindingsNatives = requireNative('event_bindings'); |
| 6 var AttachEvent = eventBindingsNatives.AttachEvent; | 6 var AttachEvent = eventBindingsNatives.AttachEvent; |
| 7 var DetachEvent = eventBindingsNatives.DetachEvent; | 7 var DetachEvent = eventBindingsNatives.DetachEvent; |
| 8 var AttachFilteredEvent = eventBindingsNatives.AttachFilteredEvent; | |
| 9 var DetachFilteredEvent = eventBindingsNatives.DetachFilteredEvent; | |
| 10 var MatchAgainstEventFilter = eventBindingsNatives.MatchAgainstEventFilter; | |
| 11 var sendRequest = require('sendRequest').sendRequest; | 8 var sendRequest = require('sendRequest').sendRequest; |
| 12 var utils = require('utils'); | 9 var utils = require('utils'); |
| 13 var validate = require('schemaUtils').validate; | 10 var validate = require('schemaUtils').validate; |
| 14 | 11 |
| 15 var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); | 12 var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); |
| 16 var GetExtensionAPIDefinition = | 13 var GetExtensionAPIDefinition = |
| 17 requireNative('apiDefinitions').GetExtensionAPIDefinition; | 14 requireNative('apiDefinitions').GetExtensionAPIDefinition; |
| 18 | 15 |
| 19 // Schemas for the rule-style functions on the events API that | 16 // Schemas for the rule-style functions on the events API that |
| 20 // only need to be generated occasionally, so populate them lazily. | 17 // only need to be generated occasionally, so populate them lazily. |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 $Array.prototype.toJSON = customizedArrayToJSON; | 68 $Array.prototype.toJSON = customizedArrayToJSON; |
| 72 } | 69 } |
| 73 } | 70 } |
| 74 }; | 71 }; |
| 75 | 72 |
| 76 this.parse = function(thing) { | 73 this.parse = function(thing) { |
| 77 return $jsonParse(thing); | 74 return $jsonParse(thing); |
| 78 }; | 75 }; |
| 79 })(); | 76 })(); |
| 80 | 77 |
| 81 // A map of event names to the event object that is registered to that name. | |
| 82 var attachedNamedEvents = {}; | |
| 83 | |
| 84 // An array of all attached event objects, used for detaching on unload. | |
| 85 var allAttachedEvents = []; | |
| 86 | |
| 87 // A map of functions that massage event arguments before they are dispatched. | |
| 88 // Key is event name, value is function. | |
| 89 var eventArgumentMassagers = {}; | |
| 90 | |
| 91 // Handles adding/removing/dispatching listeners for unfiltered events. | |
| 92 var UnfilteredAttachmentStrategy = function(event) { | |
| 93 this.event_ = event; | |
| 94 }; | |
| 95 | |
| 96 UnfilteredAttachmentStrategy.prototype.onAddedListener = | |
| 97 function(listener) { | |
| 98 // Only attach / detach on the first / last listener removed. | |
| 99 if (this.event_.listeners_.length == 0) | |
| 100 AttachEvent(this.event_.eventName_); | |
| 101 }; | |
| 102 | |
| 103 UnfilteredAttachmentStrategy.prototype.onRemovedListener = | |
| 104 function(listener) { | |
| 105 if (this.event_.listeners_.length == 0) | |
| 106 this.detach(true); | |
| 107 }; | |
| 108 | |
| 109 UnfilteredAttachmentStrategy.prototype.detach = function(manual) { | |
| 110 DetachEvent(this.event_.eventName_, manual); | |
| 111 }; | |
| 112 | |
| 113 UnfilteredAttachmentStrategy.prototype.getListenersByIDs = function(ids) { | |
| 114 return this.event_.listeners_; | |
| 115 }; | |
| 116 | |
| 117 var FilteredAttachmentStrategy = function(event) { | |
| 118 this.event_ = event; | |
| 119 this.listenerMap_ = {}; | |
| 120 }; | |
| 121 | |
| 122 FilteredAttachmentStrategy.idToEventMap = {}; | |
| 123 | |
| 124 FilteredAttachmentStrategy.prototype.onAddedListener = function(listener) { | |
| 125 var id = AttachFilteredEvent(this.event_.eventName_, | |
| 126 listener.filters || {}); | |
| 127 if (id == -1) | |
| 128 throw new Error("Can't add listener"); | |
| 129 listener.id = id; | |
| 130 this.listenerMap_[id] = listener; | |
| 131 FilteredAttachmentStrategy.idToEventMap[id] = this.event_; | |
| 132 }; | |
| 133 | |
| 134 FilteredAttachmentStrategy.prototype.onRemovedListener = function(listener) { | |
| 135 this.detachListener(listener, true); | |
| 136 }; | |
| 137 | |
| 138 FilteredAttachmentStrategy.prototype.detachListener = | |
| 139 function(listener, manual) { | |
| 140 if (listener.id == undefined) | |
| 141 throw new Error("listener.id undefined - '" + listener + "'"); | |
| 142 var id = listener.id; | |
| 143 delete this.listenerMap_[id]; | |
| 144 delete FilteredAttachmentStrategy.idToEventMap[id]; | |
| 145 DetachFilteredEvent(id, manual); | |
| 146 }; | |
| 147 | |
| 148 FilteredAttachmentStrategy.prototype.detach = function(manual) { | |
| 149 for (var i in this.listenerMap_) | |
| 150 this.detachListener(this.listenerMap_[i], manual); | |
| 151 }; | |
| 152 | |
| 153 FilteredAttachmentStrategy.prototype.getListenersByIDs = function(ids) { | |
| 154 var result = []; | |
| 155 for (var i = 0; i < ids.length; i++) | |
| 156 result.push(this.listenerMap_[ids[i]]); | |
| 157 return result; | |
| 158 }; | |
| 159 | |
| 160 // Event object. If opt_eventName is provided, this object represents | 78 // Event object. If opt_eventName is provided, this object represents |
| 161 // the unique instance of that named event, and dispatching an event | 79 // the unique instance of that named event, and dispatching an event |
| 162 // with that name will route through this object's listeners. Note that | 80 // with that name will route through this object's listeners. Note that |
| 163 // opt_eventName is required for events that support rules. | 81 // opt_eventName is required for events that support rules. |
| 164 // | 82 // |
| 165 // Example: | 83 // Example: |
| 166 // chrome.tabs.onChanged = new chrome.Event("tab-changed"); | 84 // chrome.tabs.onChanged = new chrome.Event("tab-changed"); |
| 167 // chrome.tabs.onChanged.addListener(function(data) { alert(data); }); | 85 // chrome.tabs.onChanged.addListener(function(data) { alert(data); }); |
| 168 // chromeHidden.Event.dispatch("tab-changed", "hi"); | 86 // chromeHidden.Event.dispatch("tab-changed", "hi"); |
| 169 // will result in an alert dialog that says 'hi'. | 87 // will result in an alert dialog that says 'hi'. |
| 170 // | 88 // |
| 171 // If opt_eventOptions exists, it is a dictionary that contains the boolean | 89 // If opt_eventOptions exists, it is a dictionary that contains the boolean |
| 172 // entries "supportsListeners" and "supportsRules". | 90 // entries "supportsListeners" and "supportsRules". |
| 173 chrome.Event = function(opt_eventName, opt_argSchemas, opt_eventOptions) { | 91 chrome.Event = function(opt_eventName, opt_argSchemas, opt_eventOptions) { |
| 174 this.eventName_ = opt_eventName; | 92 this.eventName_ = opt_eventName; |
| 175 this.listeners_ = []; | 93 this.listeners_ = []; |
| 176 this.eventOptions_ = opt_eventOptions || | 94 this.eventOptions_ = opt_eventOptions || |
| 177 {supportsFilters: false, | 95 {"supportsListeners": true, "supportsRules": false}; |
| 178 supportsListeners: true, | |
| 179 supportsRules: false, | |
| 180 }; | |
| 181 | 96 |
| 182 if (this.eventOptions_.supportsRules && !opt_eventName) | 97 if (this.eventOptions_.supportsRules && !opt_eventName) |
| 183 throw new Error("Events that support rules require an event name."); | 98 throw new Error("Events that support rules require an event name."); |
| 184 | 99 |
| 185 if (this.eventOptions_.supportsFilters) { | |
| 186 this.attachmentStrategy_ = new FilteredAttachmentStrategy(this); | |
| 187 } else { | |
| 188 this.attachmentStrategy_ = new UnfilteredAttachmentStrategy(this); | |
| 189 } | |
| 190 | |
| 191 // Validate event arguments (the data that is passed to the callbacks) | 100 // Validate event arguments (the data that is passed to the callbacks) |
| 192 // if we are in debug. | 101 // if we are in debug. |
| 193 if (opt_argSchemas && | 102 if (opt_argSchemas && |
| 194 chromeHidden.validateCallbacks) { | 103 chromeHidden.validateCallbacks) { |
| 195 | 104 |
| 196 this.validateEventArgs_ = function(args) { | 105 this.validateEventArgs_ = function(args) { |
| 197 try { | 106 try { |
| 198 validate(args, opt_argSchemas); | 107 validate(args, opt_argSchemas); |
| 199 } catch (exception) { | 108 } catch (exception) { |
| 200 return "Event validation error during " + opt_eventName + " -- " + | 109 return "Event validation error during " + opt_eventName + " -- " + |
| 201 exception; | 110 exception; |
| 202 } | 111 } |
| 203 }; | 112 }; |
| 204 } else { | 113 } else { |
| 205 this.validateEventArgs_ = function() {} | 114 this.validateEventArgs_ = function() {} |
| 206 } | 115 } |
| 207 }; | 116 }; |
| 208 | 117 |
| 118 // A map of event names to the event object that is registered to that name. |
| 119 var attachedNamedEvents = {}; |
| 120 |
| 121 // An array of all attached event objects, used for detaching on unload. |
| 122 var allAttachedEvents = []; |
| 123 |
| 124 // A map of functions that massage event arguments before they are dispatched. |
| 125 // Key is event name, value is function. |
| 126 var eventArgumentMassagers = {}; |
| 127 |
| 209 chromeHidden.Event = {}; | 128 chromeHidden.Event = {}; |
| 210 | 129 |
| 211 chromeHidden.Event.registerArgumentMassager = function(name, fn) { | 130 chromeHidden.Event.registerArgumentMassager = function(name, fn) { |
| 212 if (eventArgumentMassagers[name]) | 131 if (eventArgumentMassagers[name]) |
| 213 throw new Error("Massager already registered for event: " + name); | 132 throw new Error("Massager already registered for event: " + name); |
| 214 eventArgumentMassagers[name] = fn; | 133 eventArgumentMassagers[name] = fn; |
| 215 }; | 134 }; |
| 216 | 135 |
| 217 // Dispatches a named event with the given JSON array, which is deserialized | 136 // Dispatches a named event with the given JSON array, which is deserialized |
| 218 // before dispatch. The JSON array is the list of arguments that will be | 137 // before dispatch. The JSON array is the list of arguments that will be |
| 219 // sent with the event callback. | 138 // sent with the event callback. |
| 220 chromeHidden.Event.dispatchJSON = function(name, args, filteringInfo) { | 139 chromeHidden.Event.dispatchJSON = function(name, args) { |
| 221 var listenerIDs = null; | |
| 222 | |
| 223 if (filteringInfo) { | |
| 224 listenerIDs = MatchAgainstEventFilter(name, filteringInfo); | |
| 225 } | |
| 226 if (attachedNamedEvents[name]) { | 140 if (attachedNamedEvents[name]) { |
| 227 if (args) { | 141 if (args) { |
| 228 // TODO(asargent): This is an antiquity. Until all callers of | 142 // TODO(asargent): This is an antiquity. Until all callers of |
| 229 // dispatchJSON use actual values, this must remain here to catch the | 143 // dispatchJSON use actual values, this must remain here to catch the |
| 230 // cases where a caller has hard-coded a JSON string to pass in. | 144 // cases where a caller has hard-coded a JSON string to pass in. |
| 231 if (typeof(args) == "string") { | 145 if (typeof(args) == "string") { |
| 232 args = chromeHidden.JSON.parse(args); | 146 args = chromeHidden.JSON.parse(args); |
| 233 } | 147 } |
| 234 if (eventArgumentMassagers[name]) | 148 if (eventArgumentMassagers[name]) |
| 235 eventArgumentMassagers[name](args); | 149 eventArgumentMassagers[name](args); |
| 236 } | 150 } |
| 237 | 151 var result = attachedNamedEvents[name].dispatch.apply( |
| 238 var event = attachedNamedEvents[name]; | 152 attachedNamedEvents[name], args); |
| 239 var result; | |
| 240 // TODO(koz): We have to do this differently for unfiltered events (which | |
| 241 // have listenerIDs = null) because some bindings write over | |
| 242 // event.dispatch (eg: experimental.app.custom_bindings.js) and so expect | |
| 243 // events to go through it. These places need to be fixed so that they | |
| 244 // expect a listenerIDs parameter. | |
| 245 if (listenerIDs) | |
| 246 result = event.dispatch_(args, listenerIDs); | |
| 247 else | |
| 248 result = event.dispatch.apply(event, args); | |
| 249 if (result && result.validationErrors) | 153 if (result && result.validationErrors) |
| 250 return result.validationErrors; | 154 return result.validationErrors; |
| 251 } | 155 } |
| 252 }; | 156 }; |
| 253 | 157 |
| 254 // Dispatches a named event with the given arguments, supplied as an array. | 158 // Dispatches a named event with the given arguments, supplied as an array. |
| 255 chromeHidden.Event.dispatch = function(name, args) { | 159 chromeHidden.Event.dispatch = function(name, args) { |
| 256 if (attachedNamedEvents[name]) { | 160 if (attachedNamedEvents[name]) { |
| 257 attachedNamedEvents[name].dispatch.apply( | 161 attachedNamedEvents[name].dispatch.apply( |
| 258 attachedNamedEvents[name], args); | 162 attachedNamedEvents[name], args); |
| 259 } | 163 } |
| 260 }; | 164 }; |
| 261 | 165 |
| 262 // Test if a named event has any listeners. | 166 // Test if a named event has any listeners. |
| 263 chromeHidden.Event.hasListener = function(name) { | 167 chromeHidden.Event.hasListener = function(name) { |
| 264 return (attachedNamedEvents[name] && | 168 return (attachedNamedEvents[name] && |
| 265 attachedNamedEvents[name].listeners_.length > 0); | 169 attachedNamedEvents[name].listeners_.length > 0); |
| 266 }; | 170 }; |
| 267 | 171 |
| 268 // Registers a callback to be called when this event is dispatched. | 172 // Registers a callback to be called when this event is dispatched. |
| 269 chrome.Event.prototype.addListener = function(cb, filters) { | 173 chrome.Event.prototype.addListener = function(cb) { |
| 270 if (!this.eventOptions_.supportsListeners) | 174 if (!this.eventOptions_.supportsListeners) |
| 271 throw new Error("This event does not support listeners."); | 175 throw new Error("This event does not support listeners."); |
| 272 if (filters) { | 176 if (this.listeners_.length == 0) { |
| 273 if (!this.eventOptions_.supportsFilters) | 177 this.attach_(); |
| 274 throw new Error("This event does not support filters."); | |
| 275 if (filters.url && !(filters.url instanceof Array)) | |
| 276 throw new Error("filters.url should be an array"); | |
| 277 } | 178 } |
| 278 var listener = {callback: cb, filters: filters}; | 179 this.listeners_.push(cb); |
| 279 this.attach_(listener); | |
| 280 this.listeners_.push(listener); | |
| 281 }; | |
| 282 | |
| 283 chrome.Event.prototype.attach_ = function(listener) { | |
| 284 this.attachmentStrategy_.onAddedListener(listener); | |
| 285 if (this.listeners_.length == 0) { | |
| 286 allAttachedEvents[allAttachedEvents.length] = this; | |
| 287 if (!this.eventName_) | |
| 288 return; | |
| 289 | |
| 290 if (attachedNamedEvents[this.eventName_]) { | |
| 291 throw new Error("chrome.Event '" + this.eventName_ + | |
| 292 "' is already attached."); | |
| 293 } | |
| 294 | |
| 295 attachedNamedEvents[this.eventName_] = this; | |
| 296 } | |
| 297 }; | 180 }; |
| 298 | 181 |
| 299 // Unregisters a callback. | 182 // Unregisters a callback. |
| 300 chrome.Event.prototype.removeListener = function(cb) { | 183 chrome.Event.prototype.removeListener = function(cb) { |
| 301 if (!this.eventOptions_.supportsListeners) | 184 if (!this.eventOptions_.supportsListeners) |
| 302 throw new Error("This event does not support listeners."); | 185 throw new Error("This event does not support listeners."); |
| 303 var idx = this.findListener_(cb); | 186 var idx = this.findListener_(cb); |
| 304 if (idx == -1) { | 187 if (idx == -1) { |
| 305 return; | 188 return; |
| 306 } | 189 } |
| 307 | 190 |
| 308 var removedListener = this.listeners_.splice(idx, 1)[0]; | 191 this.listeners_.splice(idx, 1); |
| 309 this.attachmentStrategy_.onRemovedListener(removedListener); | |
| 310 | |
| 311 if (this.listeners_.length == 0) { | 192 if (this.listeners_.length == 0) { |
| 312 var i = allAttachedEvents.indexOf(this); | 193 this.detach_(true); |
| 313 if (i >= 0) | |
| 314 delete allAttachedEvents[i]; | |
| 315 if (!this.eventName_) | |
| 316 return; | |
| 317 | |
| 318 if (!attachedNamedEvents[this.eventName_]) { | |
| 319 throw new Error("chrome.Event '" + this.eventName_ + | |
| 320 "' is not attached."); | |
| 321 } | |
| 322 | |
| 323 delete attachedNamedEvents[this.eventName_]; | |
| 324 } | 194 } |
| 325 }; | 195 }; |
| 326 | 196 |
| 327 // Test if the given callback is registered for this event. | 197 // Test if the given callback is registered for this event. |
| 328 chrome.Event.prototype.hasListener = function(cb) { | 198 chrome.Event.prototype.hasListener = function(cb) { |
| 329 if (!this.eventOptions_.supportsListeners) | 199 if (!this.eventOptions_.supportsListeners) |
| 330 throw new Error("This event does not support listeners."); | 200 throw new Error("This event does not support listeners."); |
| 331 return this.findListener_(cb) > -1; | 201 return this.findListener_(cb) > -1; |
| 332 }; | 202 }; |
| 333 | 203 |
| 334 // Test if any callbacks are registered for this event. | 204 // Test if any callbacks are registered for this event. |
| 335 chrome.Event.prototype.hasListeners = function() { | 205 chrome.Event.prototype.hasListeners = function() { |
| 336 if (!this.eventOptions_.supportsListeners) | 206 if (!this.eventOptions_.supportsListeners) |
| 337 throw new Error("This event does not support listeners."); | 207 throw new Error("This event does not support listeners."); |
| 338 return this.listeners_.length > 0; | 208 return this.listeners_.length > 0; |
| 339 }; | 209 }; |
| 340 | 210 |
| 341 // Returns the index of the given callback if registered, or -1 if not | 211 // Returns the index of the given callback if registered, or -1 if not |
| 342 // found. | 212 // found. |
| 343 chrome.Event.prototype.findListener_ = function(cb) { | 213 chrome.Event.prototype.findListener_ = function(cb) { |
| 344 for (var i = 0; i < this.listeners_.length; i++) { | 214 for (var i = 0; i < this.listeners_.length; i++) { |
| 345 if (this.listeners_[i].callback == cb) { | 215 if (this.listeners_[i] == cb) { |
| 346 return i; | 216 return i; |
| 347 } | 217 } |
| 348 } | 218 } |
| 349 | 219 |
| 350 return -1; | 220 return -1; |
| 351 }; | 221 }; |
| 352 | 222 |
| 353 chrome.Event.prototype.dispatch_ = function(args, listenerIDs) { | 223 // Dispatches this event object to all listeners, passing all supplied |
| 224 // arguments to this function each listener. |
| 225 chrome.Event.prototype.dispatch = function(varargs) { |
| 354 if (!this.eventOptions_.supportsListeners) | 226 if (!this.eventOptions_.supportsListeners) |
| 355 throw new Error("This event does not support listeners."); | 227 throw new Error("This event does not support listeners."); |
| 228 var args = Array.prototype.slice.call(arguments); |
| 356 var validationErrors = this.validateEventArgs_(args); | 229 var validationErrors = this.validateEventArgs_(args); |
| 357 if (validationErrors) { | 230 if (validationErrors) { |
| 358 console.error(validationErrors); | 231 console.error(validationErrors); |
| 359 return {validationErrors: validationErrors}; | 232 return {validationErrors: validationErrors}; |
| 360 } | 233 } |
| 361 | |
| 362 var listeners = this.attachmentStrategy_.getListenersByIDs(listenerIDs); | |
| 363 | |
| 364 var results = []; | 234 var results = []; |
| 365 for (var i = 0; i < listeners.length; i++) { | 235 for (var i = 0; i < this.listeners_.length; i++) { |
| 366 try { | 236 try { |
| 367 var result = listeners[i].callback.apply(null, args); | 237 var result = this.listeners_[i].apply(null, args); |
| 368 if (result !== undefined) | 238 if (result !== undefined) |
| 369 results.push(result); | 239 results.push(result); |
| 370 } catch (e) { | 240 } catch (e) { |
| 371 console.error("Error in event handler for '" + this.eventName_ + | 241 console.error("Error in event handler for '" + this.eventName_ + |
| 372 "': " + e.message + ' ' + e.stack); | 242 "': " + e.message + ' ' + e.stack); |
| 373 } | 243 } |
| 374 } | 244 } |
| 375 if (results.length) | 245 if (results.length) |
| 376 return {results: results}; | 246 return {results: results}; |
| 377 } | 247 }; |
| 378 | 248 |
| 379 // Dispatches this event object to all listeners, passing all supplied | 249 // Attaches this event object to its name. Only one object can have a given |
| 380 // arguments to this function each listener. | 250 // name. |
| 381 chrome.Event.prototype.dispatch = function(varargs) { | 251 chrome.Event.prototype.attach_ = function() { |
| 382 return this.dispatch_(Array.prototype.slice.call(arguments), undefined); | 252 AttachEvent(this.eventName_); |
| 253 allAttachedEvents[allAttachedEvents.length] = this; |
| 254 if (!this.eventName_) |
| 255 return; |
| 256 |
| 257 if (attachedNamedEvents[this.eventName_]) { |
| 258 throw new Error("chrome.Event '" + this.eventName_ + |
| 259 "' is already attached."); |
| 260 } |
| 261 |
| 262 attachedNamedEvents[this.eventName_] = this; |
| 383 }; | 263 }; |
| 384 | 264 |
| 385 // Detaches this event object from its name. | 265 // Detaches this event object from its name. |
| 386 chrome.Event.prototype.detach_ = function() { | 266 chrome.Event.prototype.detach_ = function(manual) { |
| 387 this.attachmentStrategy_.detach(false); | 267 var i = allAttachedEvents.indexOf(this); |
| 268 if (i >= 0) |
| 269 delete allAttachedEvents[i]; |
| 270 DetachEvent(this.eventName_, manual); |
| 271 if (!this.eventName_) |
| 272 return; |
| 273 |
| 274 if (!attachedNamedEvents[this.eventName_]) { |
| 275 throw new Error("chrome.Event '" + this.eventName_ + |
| 276 "' is not attached."); |
| 277 } |
| 278 |
| 279 delete attachedNamedEvents[this.eventName_]; |
| 388 }; | 280 }; |
| 389 | 281 |
| 390 chrome.Event.prototype.destroy_ = function() { | 282 chrome.Event.prototype.destroy_ = function() { |
| 391 this.listeners_ = []; | 283 this.listeners_ = []; |
| 392 this.validateEventArgs_ = []; | 284 this.validateEventArgs_ = []; |
| 393 this.detach_(false); | 285 this.detach_(false); |
| 394 }; | 286 }; |
| 395 | 287 |
| 396 chrome.Event.prototype.addRules = function(rules, opt_cb) { | 288 chrome.Event.prototype.addRules = function(rules, opt_cb) { |
| 397 if (!this.eventOptions_.supportsRules) | 289 if (!this.eventOptions_.supportsRules) |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 464 chromeHidden.onUnload = new chrome.Event(); | 356 chromeHidden.onUnload = new chrome.Event(); |
| 465 | 357 |
| 466 chromeHidden.dispatchOnLoad = | 358 chromeHidden.dispatchOnLoad = |
| 467 chromeHidden.onLoad.dispatch.bind(chromeHidden.onLoad); | 359 chromeHidden.onLoad.dispatch.bind(chromeHidden.onLoad); |
| 468 | 360 |
| 469 chromeHidden.dispatchOnUnload = function() { | 361 chromeHidden.dispatchOnUnload = function() { |
| 470 chromeHidden.onUnload.dispatch(); | 362 chromeHidden.onUnload.dispatch(); |
| 471 for (var i = 0; i < allAttachedEvents.length; ++i) { | 363 for (var i = 0; i < allAttachedEvents.length; ++i) { |
| 472 var event = allAttachedEvents[i]; | 364 var event = allAttachedEvents[i]; |
| 473 if (event) | 365 if (event) |
| 474 event.detach_(); | 366 event.detach_(false); |
| 475 } | 367 } |
| 476 }; | 368 }; |
| 477 | 369 |
| 478 chromeHidden.dispatchError = function(msg) { | 370 chromeHidden.dispatchError = function(msg) { |
| 479 console.error(msg); | 371 console.error(msg); |
| 480 }; | 372 }; |
| 481 | 373 |
| 482 exports.Event = chrome.Event; | 374 exports.Event = chrome.Event; |
| OLD | NEW |