OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 exceptionHandler = require('uncaught_exception_handler'); | 5 var exceptionHandler = require('uncaught_exception_handler'); |
6 var eventNatives = requireNative('event_natives'); | 6 var eventNatives = requireNative('event_natives'); |
7 var logging = requireNative('logging'); | 7 var logging = requireNative('logging'); |
8 var schemaRegistry = requireNative('schema_registry'); | 8 var schemaRegistry = requireNative('schema_registry'); |
9 var sendRequest = require('sendRequest').sendRequest; | 9 var sendRequest = require('sendRequest').sendRequest; |
10 var utils = require('utils'); | 10 var utils = require('utils'); |
11 var validate = require('schemaUtils').validate; | 11 var validate = require('schemaUtils').validate; |
| 12 var unloadEvent = require('unload_event'); |
12 | 13 |
13 // Schemas for the rule-style functions on the events API that | 14 // Schemas for the rule-style functions on the events API that |
14 // only need to be generated occasionally, so populate them lazily. | 15 // only need to be generated occasionally, so populate them lazily. |
15 var ruleFunctionSchemas = { | 16 var ruleFunctionSchemas = { |
16 // These values are set lazily: | 17 // These values are set lazily: |
17 // addRules: {}, | 18 // addRules: {}, |
18 // getRules: {}, | 19 // getRules: {}, |
19 // removeRules: {} | 20 // removeRules: {} |
20 }; | 21 }; |
21 | 22 |
22 // This function ensures that |ruleFunctionSchemas| is populated. | 23 // This function ensures that |ruleFunctionSchemas| is populated. |
23 function ensureRuleSchemasLoaded() { | 24 function ensureRuleSchemasLoaded() { |
24 if (ruleFunctionSchemas.addRules) | 25 if (ruleFunctionSchemas.addRules) |
25 return; | 26 return; |
26 var eventsSchema = schemaRegistry.GetSchema("events"); | 27 var eventsSchema = schemaRegistry.GetSchema("events"); |
27 var eventType = utils.lookup(eventsSchema.types, 'id', 'events.Event'); | 28 var eventType = utils.lookup(eventsSchema.types, 'id', 'events.Event'); |
28 | 29 |
29 ruleFunctionSchemas.addRules = | 30 ruleFunctionSchemas.addRules = |
30 utils.lookup(eventType.functions, 'name', 'addRules'); | 31 utils.lookup(eventType.functions, 'name', 'addRules'); |
31 ruleFunctionSchemas.getRules = | 32 ruleFunctionSchemas.getRules = |
32 utils.lookup(eventType.functions, 'name', 'getRules'); | 33 utils.lookup(eventType.functions, 'name', 'getRules'); |
33 ruleFunctionSchemas.removeRules = | 34 ruleFunctionSchemas.removeRules = |
34 utils.lookup(eventType.functions, 'name', 'removeRules'); | 35 utils.lookup(eventType.functions, 'name', 'removeRules'); |
35 } | 36 } |
36 | 37 |
37 // A map of event names to the event object that is registered to that name. | 38 // A map of event names to the event object that is registered to that name. |
38 var attachedNamedEvents = {}; | 39 var attachedNamedEvents = {}; |
39 | 40 |
| 41 // An array of all attached event objects, used for detaching on unload. |
| 42 var allAttachedEvents = []; |
| 43 |
40 // A map of functions that massage event arguments before they are dispatched. | 44 // A map of functions that massage event arguments before they are dispatched. |
41 // Key is event name, value is function. | 45 // Key is event name, value is function. |
42 var eventArgumentMassagers = {}; | 46 var eventArgumentMassagers = {}; |
43 | 47 |
44 // An attachment strategy for events that aren't attached to the browser. | 48 // An attachment strategy for events that aren't attached to the browser. |
45 // This applies to events with the "unmanaged" option and events without | 49 // This applies to events with the "unmanaged" option and events without |
46 // names. | 50 // names. |
47 var NullAttachmentStrategy = function(event) { | 51 var NullAttachmentStrategy = function(event) { |
48 this.event_ = event; | 52 this.event_ = event; |
49 }; | 53 }; |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 } | 276 } |
273 var listener = {callback: cb, filters: filters}; | 277 var listener = {callback: cb, filters: filters}; |
274 this.attach_(listener); | 278 this.attach_(listener); |
275 $Array.push(this.listeners, listener); | 279 $Array.push(this.listeners, listener); |
276 }; | 280 }; |
277 | 281 |
278 EventImpl.prototype.attach_ = function(listener) { | 282 EventImpl.prototype.attach_ = function(listener) { |
279 this.attachmentStrategy.onAddedListener(listener); | 283 this.attachmentStrategy.onAddedListener(listener); |
280 | 284 |
281 if (this.listeners.length == 0) { | 285 if (this.listeners.length == 0) { |
| 286 allAttachedEvents[allAttachedEvents.length] = this; |
282 if (this.eventName) { | 287 if (this.eventName) { |
283 if (attachedNamedEvents[this.eventName]) { | 288 if (attachedNamedEvents[this.eventName]) { |
284 throw new Error("Event '" + this.eventName + | 289 throw new Error("Event '" + this.eventName + |
285 "' is already attached."); | 290 "' is already attached."); |
286 } | 291 } |
287 attachedNamedEvents[this.eventName] = this; | 292 attachedNamedEvents[this.eventName] = this; |
288 } | 293 } |
289 } | 294 } |
290 }; | 295 }; |
291 | 296 |
292 // Unregisters a callback. | 297 // Unregisters a callback. |
293 EventImpl.prototype.removeListener = function(cb) { | 298 EventImpl.prototype.removeListener = function(cb) { |
294 if (!this.eventOptions.supportsListeners) | 299 if (!this.eventOptions.supportsListeners) |
295 throw new Error("This event does not support listeners."); | 300 throw new Error("This event does not support listeners."); |
296 | 301 |
297 var idx = this.findListener_(cb); | 302 var idx = this.findListener_(cb); |
298 if (idx == -1) | 303 if (idx == -1) |
299 return; | 304 return; |
300 | 305 |
301 var removedListener = $Array.splice(this.listeners, idx, 1)[0]; | 306 var removedListener = $Array.splice(this.listeners, idx, 1)[0]; |
302 this.attachmentStrategy.onRemovedListener(removedListener); | 307 this.attachmentStrategy.onRemovedListener(removedListener); |
303 | 308 |
304 if (this.listeners.length == 0) { | 309 if (this.listeners.length == 0) { |
| 310 var i = $Array.indexOf(allAttachedEvents, this); |
| 311 if (i >= 0) |
| 312 delete allAttachedEvents[i]; |
305 if (this.eventName) { | 313 if (this.eventName) { |
306 if (!attachedNamedEvents[this.eventName]) { | 314 if (!attachedNamedEvents[this.eventName]) { |
307 throw new Error( | 315 throw new Error( |
308 "Event '" + this.eventName + "' is not attached."); | 316 "Event '" + this.eventName + "' is not attached."); |
309 } | 317 } |
310 delete attachedNamedEvents[this.eventName]; | 318 delete attachedNamedEvents[this.eventName]; |
311 } | 319 } |
312 } | 320 } |
313 }; | 321 }; |
314 | 322 |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
483 validate([this.webViewInstanceId, ruleIdentifiers, cb], | 491 validate([this.webViewInstanceId, ruleIdentifiers, cb], |
484 $Array.splice( | 492 $Array.splice( |
485 $Array.slice(ruleFunctionSchemas.getRules.parameters), 1)); | 493 $Array.slice(ruleFunctionSchemas.getRules.parameters), 1)); |
486 | 494 |
487 sendRequest( | 495 sendRequest( |
488 "events.getRules", | 496 "events.getRules", |
489 [this.eventName, this.webViewInstanceId, ruleIdentifiers, cb], | 497 [this.eventName, this.webViewInstanceId, ruleIdentifiers, cb], |
490 ruleFunctionSchemas.getRules.parameters); | 498 ruleFunctionSchemas.getRules.parameters); |
491 } | 499 } |
492 | 500 |
| 501 unloadEvent.addListener(function() { |
| 502 for (var i = 0; i < allAttachedEvents.length; ++i) { |
| 503 var event = allAttachedEvents[i]; |
| 504 if (event) |
| 505 event.detach_(); |
| 506 } |
| 507 }); |
| 508 |
493 var Event = utils.expose('Event', EventImpl, { functions: [ | 509 var Event = utils.expose('Event', EventImpl, { functions: [ |
494 'addListener', | 510 'addListener', |
495 'removeListener', | 511 'removeListener', |
496 'hasListener', | 512 'hasListener', |
497 'hasListeners', | 513 'hasListeners', |
498 'dispatchToListener', | 514 'dispatchToListener', |
499 'dispatch', | 515 'dispatch', |
500 'addRules', | 516 'addRules', |
501 'removeRules', | 517 'removeRules', |
502 'getRules' | 518 'getRules' |
503 ] }); | 519 ] }); |
504 | 520 |
505 // NOTE: Event is (lazily) exposed as chrome.Event from dispatcher.cc. | 521 // NOTE: Event is (lazily) exposed as chrome.Event from dispatcher.cc. |
506 exports.Event = Event; | 522 exports.Event = Event; |
507 | 523 |
508 exports.dispatchEvent = dispatchEvent; | 524 exports.dispatchEvent = dispatchEvent; |
509 exports.parseEventOptions = parseEventOptions; | 525 exports.parseEventOptions = parseEventOptions; |
510 exports.registerArgumentMassager = registerArgumentMassager; | 526 exports.registerArgumentMassager = registerArgumentMassager; |
OLD | NEW |