15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) var eventNatives = requireNative('event_natives'); 6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) var logging = requireNative('logging'); 7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) var schemaRegistry = requireNative('schema_registry'); 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var sendRequest = require('sendRequest').sendRequest; 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var utils = require('utils'); 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var validate = require('schemaUtils').validate; 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) var unloadEvent = require('unload_event'); 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Schemas for the rule-style functions on the events API that 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // only need to be generated occasionally, so populate them lazily. 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var ruleFunctionSchemas = { 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // These values are set lazily: 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // addRules: {}, 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // getRules: {}, 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // removeRules: {} 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This function ensures that |ruleFunctionSchemas| is populated. 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function ensureRuleSchemasLoaded() { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ruleFunctionSchemas.addRules) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var eventsSchema = schemaRegistry.GetSchema("events"); 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var eventType = utils.lookup(eventsSchema.types, 'id', 'events.Event'); 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ruleFunctionSchemas.addRules = 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) utils.lookup(eventType.functions, 'name', 'addRules'); 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ruleFunctionSchemas.getRules = 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) utils.lookup(eventType.functions, 'name', 'getRules'); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ruleFunctionSchemas.removeRules = 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) utils.lookup(eventType.functions, 'name', 'removeRules'); 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A map of event names to the event object that is registered to that name. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var attachedNamedEvents = {}; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // An array of all attached event objects, used for detaching on unload. 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var allAttachedEvents = []; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A map of functions that massage event arguments before they are dispatched. 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Key is event name, value is function. 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var eventArgumentMassagers = {}; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 47ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // An attachment strategy for events that aren't attached to the browser. 48ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // This applies to events with the "unmanaged" option and events without 49ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // names. 50ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch var NullAttachmentStrategy = function(event) { 51ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch this.event_ = event; 52ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch }; 53ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch NullAttachmentStrategy.prototype.onAddedListener = 54ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch function(listener) { 55ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch }; 56ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch NullAttachmentStrategy.prototype.onRemovedListener = 57ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch function(listener) { 58ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch }; 59ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch NullAttachmentStrategy.prototype.detach = function(manual) { 60ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch }; 61ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch NullAttachmentStrategy.prototype.getListenersByIDs = function(ids) { 62ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // |ids| is for filtered events only. 63ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch return this.event_.listeners_; 64ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch }; 65ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Handles adding/removing/dispatching listeners for unfiltered events. 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var UnfilteredAttachmentStrategy = function(event) { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.event_ = event; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnfilteredAttachmentStrategy.prototype.onAddedListener = 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function(listener) { 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only attach / detach on the first / last listener removed. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.event_.listeners_.length == 0) 75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) eventNatives.AttachEvent(privates(this.event_).eventName); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnfilteredAttachmentStrategy.prototype.onRemovedListener = 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function(listener) { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.event_.listeners_.length == 0) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.detach(true); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnfilteredAttachmentStrategy.prototype.detach = function(manual) { 85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) eventNatives.DetachEvent(privates(this.event_).eventName, manual); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnfilteredAttachmentStrategy.prototype.getListenersByIDs = function(ids) { 89ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // |ids| is for filtered events only. 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return this.event_.listeners_; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var FilteredAttachmentStrategy = function(event) { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.event_ = event; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.listenerMap_ = {}; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FilteredAttachmentStrategy.idToEventMap = {}; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FilteredAttachmentStrategy.prototype.onAddedListener = function(listener) { 101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) var id = eventNatives.AttachFilteredEvent(privates(this.event_).eventName, 102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) listener.filters || {}); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (id == -1) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error("Can't add listener"); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listener.id = id; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.listenerMap_[id] = listener; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FilteredAttachmentStrategy.idToEventMap[id] = this.event_; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FilteredAttachmentStrategy.prototype.onRemovedListener = function(listener) { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.detachListener(listener, true); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FilteredAttachmentStrategy.prototype.detachListener = 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function(listener, manual) { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (listener.id == undefined) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error("listener.id undefined - '" + listener + "'"); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var id = listener.id; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete this.listenerMap_[id]; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete FilteredAttachmentStrategy.idToEventMap[id]; 121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) eventNatives.DetachFilteredEvent(id, manual); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FilteredAttachmentStrategy.prototype.detach = function(manual) { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var i in this.listenerMap_) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.detachListener(this.listenerMap_[i], manual); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FilteredAttachmentStrategy.prototype.getListenersByIDs = function(ids) { 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var result = []; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var i = 0; i < ids.length; i++) 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch $Array.push(result, this.listenerMap_[ids[i]]); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) function parseEventOptions(opt_eventOptions) { 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function merge(dest, src) { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var k in src) { 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!$Object.hasOwnProperty(dest, k)) { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[k] = src[k]; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var options = opt_eventOptions || {}; 146ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch merge(options, { 147ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // Event supports adding listeners with filters ("filtered events"), for 148ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // example as used in the webNavigation API. 149ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // 150ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // event.addListener(listener, [filter1, filter2]); 151ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch supportsFilters: false, 152ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 153ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // Events supports vanilla events. Most APIs use these. 154ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // 155ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // event.addListener(listener); 156ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch supportsListeners: true, 157ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 158ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // Event supports adding rules ("declarative events") rather than 159ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // listeners, for example as used in the declarativeWebRequest API. 160ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // 161ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // event.addRules([rule1, rule2]); 162ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch supportsRules: false, 163ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 164ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // Event is unmanaged in that the browser has no knowledge of its 165ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // existence; it's never invoked, doesn't keep the renderer alive, and 166ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // the bindings system has no knowledge of it. 167ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // 168ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // Both events created by user code (new chrome.Event()) and messaging 169ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // events are unmanaged, though in the latter case the browser *does* 170ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // interact indirectly with them via IPCs written by hand. 171ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch unmanaged: false, 172ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch }); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return options; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Event object. If opt_eventName is provided, this object represents 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the unique instance of that named event, and dispatching an event 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // with that name will route through this object's listeners. Note that 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // opt_eventName is required for events that support rules. 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Example: 182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // var Event = require('event_bindings').Event; 183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // chrome.tabs.onChanged = new Event("tab-changed"); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // chrome.tabs.onChanged.addListener(function(data) { alert(data); }); 185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Event.dispatch("tab-changed", "hi"); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will result in an alert dialog that says 'hi'. 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If opt_eventOptions exists, it is a dictionary that contains the boolean 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // entries "supportsListeners" and "supportsRules". 190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // If opt_webViewInstanceId exists, it is an integer uniquely identifying a 191f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // <webview> tag within the embedder. If it does not exist, then this is an 192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // extension event rather than a <webview> event. 193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) var Event = function(opt_eventName, opt_argSchemas, opt_eventOptions, 194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) opt_webViewInstanceId) { 195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) privates(this).eventName = opt_eventName; 196ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch this.argSchemas_ = opt_argSchemas; 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.listeners_ = []; 198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) this.eventOptions_ = parseEventOptions(opt_eventOptions); 199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) this.webViewInstanceId_ = opt_webViewInstanceId || 0; 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 201a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!privates(this).eventName) { 202ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (this.eventOptions_.supportsRules) 203ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch throw new Error("Events that support rules require an event name."); 204ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // Events without names cannot be managed by the browser by definition 205ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // (the browser has no way of identifying them). 206ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch this.eventOptions_.unmanaged = true; 207ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 208ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 2097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // Track whether the event has been destroyed to help track down the cause 2107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // of http://crbug.com/258526. 211ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // This variable will eventually hold the stack trace of the destroy call. 2127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // TODO(kalman): Delete this and replace with more sound logic that catches 2137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // when events are used without being *attached*. 214ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch this.destroyed_ = null; 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 216ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (this.eventOptions_.unmanaged) 217ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch this.attachmentStrategy_ = new NullAttachmentStrategy(this); 218ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch else if (this.eventOptions_.supportsFilters) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.attachmentStrategy_ = new FilteredAttachmentStrategy(this); 220ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch else 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.attachmentStrategy_ = new UnfilteredAttachmentStrategy(this); 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // callback is a function(args, dispatch). args are the args we receive from 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // dispatchEvent(), and dispatch is a function(args) that dispatches args to 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // its listeners. 227868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) function registerArgumentMassager(name, callback) { 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (eventArgumentMassagers[name]) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error("Massager already registered for event: " + name); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) eventArgumentMassagers[name] = callback; 231868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Dispatches a named event with the given argument array. The args array is 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the list of arguments that will be sent to the event callback. 235868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) function dispatchEvent(name, args, filteringInfo) { 23658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) var listenerIDs = []; 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (filteringInfo) 239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) listenerIDs = eventNatives.MatchAgainstEventFilter(name, filteringInfo); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var event = attachedNamedEvents[name]; 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!event) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var dispatchArgs = function(args) { 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var result = event.dispatch_(args, listenerIDs); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result) 248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) logging.DCHECK(!result.validationErrors, result.validationErrors); 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return result; 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (eventArgumentMassagers[name]) 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) eventArgumentMassagers[name](args, dispatchArgs); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dispatchArgs(args); 256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Registers a callback to be called when this event is dispatched. 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Event.prototype.addListener = function(cb, filters) { 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!this.eventOptions_.supportsListeners) 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error("This event does not support listeners."); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.eventOptions_.maxListeners && 263ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch this.getListenerCount() >= this.eventOptions_.maxListeners) { 264a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) throw new Error("Too many listeners for " + privates(this).eventName); 265ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (filters) { 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!this.eventOptions_.supportsFilters) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error("This event does not support filters."); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (filters.url && !(filters.url instanceof Array)) 27058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) throw new Error("filters.url should be an array."); 27158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (filters.serviceType && 27258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) !(typeof filters.serviceType === 'string')) { 27358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) throw new Error("filters.serviceType should be a string.") 27458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var listener = {callback: cb, filters: filters}; 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.attach_(listener); 278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch $Array.push(this.listeners_, listener); 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Event.prototype.attach_ = function(listener) { 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.attachmentStrategy_.onAddedListener(listener); 283ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.listeners_.length == 0) { 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allAttachedEvents[allAttachedEvents.length] = this; 286a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (privates(this).eventName) { 287a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (attachedNamedEvents[privates(this).eventName]) { 288a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) throw new Error("Event '" + privates(this).eventName + 289ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch "' is already attached."); 290ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 291a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) attachedNamedEvents[privates(this).eventName] = this; 292ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Unregisters a callback. 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Event.prototype.removeListener = function(cb) { 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!this.eventOptions_.supportsListeners) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error("This event does not support listeners."); 300ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var idx = this.findListener_(cb); 302868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (idx == -1) 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch var removedListener = $Array.splice(this.listeners_, idx, 1)[0]; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.attachmentStrategy_.onRemovedListener(removedListener); 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.listeners_.length == 0) { 309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) var i = $Array.indexOf(allAttachedEvents, this); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i >= 0) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete allAttachedEvents[i]; 312a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (privates(this).eventName) { 313a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!attachedNamedEvents[privates(this).eventName]) { 314a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) throw new Error( 315a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Event '" + privates(this).eventName + "' is not attached."); 316a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 317a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) delete attachedNamedEvents[privates(this).eventName]; 318ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Test if the given callback is registered for this event. 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Event.prototype.hasListener = function(cb) { 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!this.eventOptions_.supportsListeners) 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error("This event does not support listeners."); 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return this.findListener_(cb) > -1; 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Test if any callbacks are registered for this event. 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Event.prototype.hasListeners = function() { 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return this.getListenerCount() > 0; 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return the number of listeners on this event. 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Event.prototype.getListenerCount = function() { 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!this.eventOptions_.supportsListeners) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error("This event does not support listeners."); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return this.listeners_.length; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns the index of the given callback if registered, or -1 if not 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // found. 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Event.prototype.findListener_ = function(cb) { 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var i = 0; i < this.listeners_.length; i++) { 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.listeners_[i].callback == cb) { 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return i; 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Event.prototype.dispatch_ = function(args, listenerIDs) { 3547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (this.destroyed_) { 355a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) throw new Error(privates(this).eventName + ' was already destroyed at: ' + 356ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch this.destroyed_); 3577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!this.eventOptions_.supportsListeners) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error("This event does not support listeners."); 360ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 361ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (this.argSchemas_ && logging.DCHECK_IS_ON()) { 362ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch try { 363ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch validate(args, this.argSchemas_); 364ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } catch (e) { 365a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) e.message += ' in ' + privates(this).eventName; 366ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch throw e; 367ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Make a copy of the listeners in case the listener list is modified 3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // while dispatching the event. 372eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch var listeners = $Array.slice( 373eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch this.attachmentStrategy_.getListenersByIDs(listenerIDs)); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var results = []; 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var i = 0; i < listeners.length; i++) { 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try { 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var result = this.dispatchToListener(listeners[i].callback, args); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result !== undefined) 380eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch $Array.push(results, result); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } catch (e) { 382a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) console.error( 383a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 'Error in event handler for ' + 384a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) (privates(this).eventName ? privates(this).eventName : '(unknown)') + 385a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ': ' + e.stack); 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (results.length) 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return {results: results}; 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Can be overridden to support custom dispatching. 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Event.prototype.dispatchToListener = function(callback, args) { 394eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return $Function.apply(callback, null, args); 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Dispatches this event object to all listeners, passing all supplied 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // arguments to this function each listener. 3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Event.prototype.dispatch = function(varargs) { 400eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return this.dispatch_($Array.slice(arguments), undefined); 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Detaches this event object from its name. 4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Event.prototype.detach_ = function() { 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.attachmentStrategy_.detach(false); 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Event.prototype.destroy_ = function() { 4097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch this.listeners_.length = 0; 4107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch this.detach_(); 411ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch this.destroyed_ = new Error().stack; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Event.prototype.addRules = function(rules, opt_cb) { 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!this.eventOptions_.supportsRules) 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error("This event does not support rules."); 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Takes a list of JSON datatype identifiers and returns a schema fragment 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that verifies that a JSON object corresponds to an array of only these 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // data types. 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function buildArrayOfChoicesSchema(typesList) { 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return { 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'type': 'array', 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'items': { 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'choices': typesList.map(function(el) {return {'$ref': el};}) 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Validate conditions and actions against specific schemas of this 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // event object type. 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |rules| is an array of JSON objects that follow the Rule type of the 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // declarative extension APIs. |conditions| is an array of JSON type 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // identifiers that are allowed to occur in the conditions attribute of each 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // rule. Likewise, |actions| is an array of JSON type identifiers that are 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // allowed to occur in the actions attribute of each rule. 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function validateRules(rules, conditions, actions) { 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var conditionsSchema = buildArrayOfChoicesSchema(conditions); 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var actionsSchema = buildArrayOfChoicesSchema(actions); 4407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) $Array.forEach(rules, function(rule) { 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validate([rule.conditions], [conditionsSchema]); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validate([rule.actions], [actionsSchema]); 443868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) }); 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!this.eventOptions_.conditions || !this.eventOptions_.actions) { 447a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) throw new Error('Event ' + privates(this).eventName + ' misses ' + 448a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 'conditions or actions in the API specification.'); 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) validateRules(rules, 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.eventOptions_.conditions, 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.eventOptions_.actions); 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ensureRuleSchemasLoaded(); 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We remove the first parameter from the validation to give the user more 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // meaningful error messages. 458f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) validate([this.webViewInstanceId_, rules, opt_cb], 459eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch $Array.splice( 460eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch $Array.slice(ruleFunctionSchemas.addRules.parameters), 1)); 461a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sendRequest( 462a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "events.addRules", 463a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) [privates(this).eventName, this.webViewInstanceId_, rules, opt_cb], 464a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ruleFunctionSchemas.addRules.parameters); 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Event.prototype.removeRules = function(ruleIdentifiers, opt_cb) { 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!this.eventOptions_.supportsRules) 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error("This event does not support rules."); 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ensureRuleSchemasLoaded(); 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We remove the first parameter from the validation to give the user more 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // meaningful error messages. 473f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) validate([this.webViewInstanceId_, ruleIdentifiers, opt_cb], 474eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch $Array.splice( 475eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch $Array.slice(ruleFunctionSchemas.removeRules.parameters), 1)); 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sendRequest("events.removeRules", 477a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) [privates(this).eventName, 478f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) this.webViewInstanceId_, 479f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ruleIdentifiers, 480f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) opt_cb], 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ruleFunctionSchemas.removeRules.parameters); 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Event.prototype.getRules = function(ruleIdentifiers, cb) { 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!this.eventOptions_.supportsRules) 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throw new Error("This event does not support rules."); 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ensureRuleSchemasLoaded(); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We remove the first parameter from the validation to give the user more 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // meaningful error messages. 490f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) validate([this.webViewInstanceId_, ruleIdentifiers, cb], 491eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch $Array.splice( 492eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch $Array.slice(ruleFunctionSchemas.getRules.parameters), 1)); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 494a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sendRequest( 495a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "events.getRules", 496a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) [privates(this).eventName, this.webViewInstanceId_, ruleIdentifiers, cb], 497a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ruleFunctionSchemas.getRules.parameters); 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 500868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) unloadEvent.addListener(function() { 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var i = 0; i < allAttachedEvents.length; ++i) { 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var event = allAttachedEvents[i]; 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event) 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event.detach_(); 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 506868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) }); 507868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 508868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // NOTE: Event is (lazily) exposed as chrome.Event from dispatcher.cc. 509868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) exports.Event = Event; 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 511868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) exports.dispatchEvent = dispatchEvent; 512868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) exports.parseEventOptions = parseEventOptions; 513868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) exports.registerArgumentMassager = registerArgumentMassager; 514