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