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