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 DCHECK = requireNative('logging').DCHECK; | 5 var eventNatives = requireNative('event_natives'); |
6 // TODO(cduvall/kalman): json_schema shouldn't put things on chromeHidden. | 6 var logging = requireNative('logging'); |
7 require('json_schema'); | 7 var onUnload = require('on_unload'); |
8 var eventBindingsNatives = requireNative('event_bindings'); | 8 var schemaRegistry = requireNative('schema_registry'); |
9 var AttachEvent = eventBindingsNatives.AttachEvent; | |
10 var DetachEvent = eventBindingsNatives.DetachEvent; | |
11 var AttachFilteredEvent = eventBindingsNatives.AttachFilteredEvent; | |
12 var DetachFilteredEvent = eventBindingsNatives.DetachFilteredEvent; | |
13 var MatchAgainstEventFilter = eventBindingsNatives.MatchAgainstEventFilter; | |
14 var forEach = require('utils').forEach; | |
15 var sendRequest = require('sendRequest').sendRequest; | 9 var sendRequest = require('sendRequest').sendRequest; |
16 var utils = require('utils'); | 10 var utils = require('utils'); |
17 var validate = require('schemaUtils').validate; | 11 var validate = require('schemaUtils').validate; |
18 | 12 |
19 var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); | |
20 var chrome = requireNative('chrome').GetChrome(); | |
21 var schemaRegistry = requireNative('schema_registry'); | |
22 | |
23 // Schemas for the rule-style functions on the events API that | 13 // Schemas for the rule-style functions on the events API that |
24 // only need to be generated occasionally, so populate them lazily. | 14 // only need to be generated occasionally, so populate them lazily. |
25 var ruleFunctionSchemas = { | 15 var ruleFunctionSchemas = { |
26 // These values are set lazily: | 16 // These values are set lazily: |
27 // addRules: {}, | 17 // addRules: {}, |
28 // getRules: {}, | 18 // getRules: {}, |
29 // removeRules: {} | 19 // removeRules: {} |
30 }; | 20 }; |
31 | 21 |
32 // This function ensures that |ruleFunctionSchemas| is populated. | 22 // This function ensures that |ruleFunctionSchemas| is populated. |
(...skipping 23 matching lines...) Expand all Loading... |
56 | 46 |
57 // Handles adding/removing/dispatching listeners for unfiltered events. | 47 // Handles adding/removing/dispatching listeners for unfiltered events. |
58 var UnfilteredAttachmentStrategy = function(event) { | 48 var UnfilteredAttachmentStrategy = function(event) { |
59 this.event_ = event; | 49 this.event_ = event; |
60 }; | 50 }; |
61 | 51 |
62 UnfilteredAttachmentStrategy.prototype.onAddedListener = | 52 UnfilteredAttachmentStrategy.prototype.onAddedListener = |
63 function(listener) { | 53 function(listener) { |
64 // Only attach / detach on the first / last listener removed. | 54 // Only attach / detach on the first / last listener removed. |
65 if (this.event_.listeners_.length == 0) | 55 if (this.event_.listeners_.length == 0) |
66 AttachEvent(this.event_.eventName_); | 56 eventNatives.AttachEvent(this.event_.eventName_); |
67 }; | 57 }; |
68 | 58 |
69 UnfilteredAttachmentStrategy.prototype.onRemovedListener = | 59 UnfilteredAttachmentStrategy.prototype.onRemovedListener = |
70 function(listener) { | 60 function(listener) { |
71 if (this.event_.listeners_.length == 0) | 61 if (this.event_.listeners_.length == 0) |
72 this.detach(true); | 62 this.detach(true); |
73 }; | 63 }; |
74 | 64 |
75 UnfilteredAttachmentStrategy.prototype.detach = function(manual) { | 65 UnfilteredAttachmentStrategy.prototype.detach = function(manual) { |
76 DetachEvent(this.event_.eventName_, manual); | 66 eventNatives.DetachEvent(this.event_.eventName_, manual); |
77 }; | 67 }; |
78 | 68 |
79 UnfilteredAttachmentStrategy.prototype.getListenersByIDs = function(ids) { | 69 UnfilteredAttachmentStrategy.prototype.getListenersByIDs = function(ids) { |
80 return this.event_.listeners_; | 70 return this.event_.listeners_; |
81 }; | 71 }; |
82 | 72 |
83 var FilteredAttachmentStrategy = function(event) { | 73 var FilteredAttachmentStrategy = function(event) { |
84 this.event_ = event; | 74 this.event_ = event; |
85 this.listenerMap_ = {}; | 75 this.listenerMap_ = {}; |
86 }; | 76 }; |
87 | 77 |
88 FilteredAttachmentStrategy.idToEventMap = {}; | 78 FilteredAttachmentStrategy.idToEventMap = {}; |
89 | 79 |
90 FilteredAttachmentStrategy.prototype.onAddedListener = function(listener) { | 80 FilteredAttachmentStrategy.prototype.onAddedListener = function(listener) { |
91 var id = AttachFilteredEvent(this.event_.eventName_, | 81 var id = eventNatives.AttachFilteredEvent(this.event_.eventName_, |
92 listener.filters || {}); | 82 listener.filters || {}); |
93 if (id == -1) | 83 if (id == -1) |
94 throw new Error("Can't add listener"); | 84 throw new Error("Can't add listener"); |
95 listener.id = id; | 85 listener.id = id; |
96 this.listenerMap_[id] = listener; | 86 this.listenerMap_[id] = listener; |
97 FilteredAttachmentStrategy.idToEventMap[id] = this.event_; | 87 FilteredAttachmentStrategy.idToEventMap[id] = this.event_; |
98 }; | 88 }; |
99 | 89 |
100 FilteredAttachmentStrategy.prototype.onRemovedListener = function(listener) { | 90 FilteredAttachmentStrategy.prototype.onRemovedListener = function(listener) { |
101 this.detachListener(listener, true); | 91 this.detachListener(listener, true); |
102 }; | 92 }; |
103 | 93 |
104 FilteredAttachmentStrategy.prototype.detachListener = | 94 FilteredAttachmentStrategy.prototype.detachListener = |
105 function(listener, manual) { | 95 function(listener, manual) { |
106 if (listener.id == undefined) | 96 if (listener.id == undefined) |
107 throw new Error("listener.id undefined - '" + listener + "'"); | 97 throw new Error("listener.id undefined - '" + listener + "'"); |
108 var id = listener.id; | 98 var id = listener.id; |
109 delete this.listenerMap_[id]; | 99 delete this.listenerMap_[id]; |
110 delete FilteredAttachmentStrategy.idToEventMap[id]; | 100 delete FilteredAttachmentStrategy.idToEventMap[id]; |
111 DetachFilteredEvent(id, manual); | 101 eventNatives.DetachFilteredEvent(id, manual); |
112 }; | 102 }; |
113 | 103 |
114 FilteredAttachmentStrategy.prototype.detach = function(manual) { | 104 FilteredAttachmentStrategy.prototype.detach = function(manual) { |
115 for (var i in this.listenerMap_) | 105 for (var i in this.listenerMap_) |
116 this.detachListener(this.listenerMap_[i], manual); | 106 this.detachListener(this.listenerMap_[i], manual); |
117 }; | 107 }; |
118 | 108 |
119 FilteredAttachmentStrategy.prototype.getListenersByIDs = function(ids) { | 109 FilteredAttachmentStrategy.prototype.getListenersByIDs = function(ids) { |
120 var result = []; | 110 var result = []; |
121 for (var i = 0; i < ids.length; i++) | 111 for (var i = 0; i < ids.length; i++) |
122 result.push(this.listenerMap_[ids[i]]); | 112 result.push(this.listenerMap_[ids[i]]); |
123 return result; | 113 return result; |
124 }; | 114 }; |
125 | 115 |
126 chromeHidden.parseEventOptions = function(opt_eventOptions) { | 116 function parseEventOptions(opt_eventOptions) { |
127 function merge(dest, src) { | 117 function merge(dest, src) { |
128 for (var k in src) { | 118 for (var k in src) { |
129 if (!dest.hasOwnProperty(k)) { | 119 if (!dest.hasOwnProperty(k)) { |
130 dest[k] = src[k]; | 120 dest[k] = src[k]; |
131 } | 121 } |
132 } | 122 } |
133 } | 123 } |
134 | 124 |
135 var options = opt_eventOptions || {}; | 125 var options = opt_eventOptions || {}; |
136 merge(options, | 126 merge(options, |
137 {supportsFilters: false, | 127 {supportsFilters: false, |
138 supportsListeners: true, | 128 supportsListeners: true, |
139 supportsRules: false, | 129 supportsRules: false, |
140 }); | 130 }); |
141 return options; | 131 return options; |
142 }; | 132 }; |
143 | 133 |
144 // Event object. If opt_eventName is provided, this object represents | 134 // Event object. If opt_eventName is provided, this object represents |
145 // the unique instance of that named event, and dispatching an event | 135 // the unique instance of that named event, and dispatching an event |
146 // with that name will route through this object's listeners. Note that | 136 // with that name will route through this object's listeners. Note that |
147 // opt_eventName is required for events that support rules. | 137 // opt_eventName is required for events that support rules. |
148 // | 138 // |
149 // Example: | 139 // Example: |
150 // chrome.tabs.onChanged = new chrome.Event("tab-changed"); | 140 // var Event = require('event_bindings').Event; |
| 141 // chrome.tabs.onChanged = new Event("tab-changed"); |
151 // chrome.tabs.onChanged.addListener(function(data) { alert(data); }); | 142 // chrome.tabs.onChanged.addListener(function(data) { alert(data); }); |
152 // chromeHidden.Event.dispatch("tab-changed", "hi"); | 143 // Event.dispatch("tab-changed", "hi"); |
153 // will result in an alert dialog that says 'hi'. | 144 // will result in an alert dialog that says 'hi'. |
154 // | 145 // |
155 // If opt_eventOptions exists, it is a dictionary that contains the boolean | 146 // If opt_eventOptions exists, it is a dictionary that contains the boolean |
156 // entries "supportsListeners" and "supportsRules". | 147 // entries "supportsListeners" and "supportsRules". |
157 var Event = function(opt_eventName, opt_argSchemas, opt_eventOptions) { | 148 var Event = function(opt_eventName, opt_argSchemas, opt_eventOptions) { |
158 this.eventName_ = opt_eventName; | 149 this.eventName_ = opt_eventName; |
159 this.listeners_ = []; | 150 this.listeners_ = []; |
160 this.eventOptions_ = chromeHidden.parseEventOptions(opt_eventOptions); | 151 this.eventOptions_ = parseEventOptions(opt_eventOptions); |
161 | 152 |
162 if (this.eventOptions_.supportsRules && !opt_eventName) | 153 if (this.eventOptions_.supportsRules && !opt_eventName) |
163 throw new Error("Events that support rules require an event name."); | 154 throw new Error("Events that support rules require an event name."); |
164 | 155 |
165 if (this.eventOptions_.supportsFilters) { | 156 if (this.eventOptions_.supportsFilters) { |
166 this.attachmentStrategy_ = new FilteredAttachmentStrategy(this); | 157 this.attachmentStrategy_ = new FilteredAttachmentStrategy(this); |
167 } else { | 158 } else { |
168 this.attachmentStrategy_ = new UnfilteredAttachmentStrategy(this); | 159 this.attachmentStrategy_ = new UnfilteredAttachmentStrategy(this); |
169 } | 160 } |
170 | 161 |
171 // Validate event arguments (the data that is passed to the callbacks) | 162 // Validate event arguments (the data that is passed to the callbacks) |
172 // if we are in debug. | 163 // if we are in debug. |
173 if (opt_argSchemas && | 164 if (opt_argSchemas && logging.DCHECK_IS_ON()) { |
174 chromeHidden.validateCallbacks) { | |
175 | |
176 this.validateEventArgs_ = function(args) { | 165 this.validateEventArgs_ = function(args) { |
177 try { | 166 try { |
178 validate(args, opt_argSchemas); | 167 validate(args, opt_argSchemas); |
179 } catch (exception) { | 168 } catch (exception) { |
180 return "Event validation error during " + opt_eventName + " -- " + | 169 return "Event validation error during " + opt_eventName + " -- " + |
181 exception; | 170 exception; |
182 } | 171 } |
183 }; | 172 }; |
184 } else { | 173 } else { |
185 this.validateEventArgs_ = function() {} | 174 this.validateEventArgs_ = function() {} |
186 } | 175 } |
187 }; | 176 }; |
188 | 177 |
189 | |
190 chromeHidden.Event = {}; | |
191 | |
192 // callback is a function(args, dispatch). args are the args we receive from | 178 // callback is a function(args, dispatch). args are the args we receive from |
193 // dispatchEvent(), and dispatch is a function(args) that dispatches args to | 179 // dispatchEvent(), and dispatch is a function(args) that dispatches args to |
194 // its listeners. | 180 // its listeners. |
195 chromeHidden.Event.registerArgumentMassager = function(name, callback) { | 181 function registerArgumentMassager(name, callback) { |
196 if (eventArgumentMassagers[name]) | 182 if (eventArgumentMassagers[name]) |
197 throw new Error("Massager already registered for event: " + name); | 183 throw new Error("Massager already registered for event: " + name); |
198 eventArgumentMassagers[name] = callback; | 184 eventArgumentMassagers[name] = callback; |
199 }; | 185 } |
200 | 186 |
201 // Dispatches a named event with the given argument array. The args array is | 187 // Dispatches a named event with the given argument array. The args array is |
202 // the list of arguments that will be sent to the event callback. | 188 // the list of arguments that will be sent to the event callback. |
203 chromeHidden.Event.dispatchEvent = function(name, args, filteringInfo) { | 189 function dispatchEvent(name, args, filteringInfo) { |
204 var listenerIDs = null; | 190 var listenerIDs = null; |
205 | 191 |
206 if (filteringInfo) | 192 if (filteringInfo) |
207 listenerIDs = MatchAgainstEventFilter(name, filteringInfo); | 193 listenerIDs = eventNatives.MatchAgainstEventFilter(name, filteringInfo); |
208 | 194 |
209 var event = attachedNamedEvents[name]; | 195 var event = attachedNamedEvents[name]; |
210 if (!event) | 196 if (!event) |
211 return; | 197 return; |
212 | 198 |
213 var dispatchArgs = function(args) { | 199 var dispatchArgs = function(args) { |
214 var result = event.dispatch_(args, listenerIDs); | 200 var result = event.dispatch_(args, listenerIDs); |
215 if (result) | 201 if (result) |
216 DCHECK(!result.validationErrors, result.validationErrors); | 202 logging.DCHECK(!result.validationErrors, result.validationErrors); |
217 return result; | 203 return result; |
218 }; | 204 }; |
219 | 205 |
220 if (eventArgumentMassagers[name]) | 206 if (eventArgumentMassagers[name]) |
221 eventArgumentMassagers[name](args, dispatchArgs); | 207 eventArgumentMassagers[name](args, dispatchArgs); |
222 else | 208 else |
223 dispatchArgs(args); | 209 dispatchArgs(args); |
224 }; | 210 } |
225 | |
226 // Test if a named event has any listeners. | |
227 chromeHidden.Event.hasListener = function(name) { | |
228 return (attachedNamedEvents[name] && | |
229 attachedNamedEvents[name].listeners_.length > 0); | |
230 }; | |
231 | 211 |
232 // Registers a callback to be called when this event is dispatched. | 212 // Registers a callback to be called when this event is dispatched. |
233 Event.prototype.addListener = function(cb, filters) { | 213 Event.prototype.addListener = function(cb, filters) { |
234 if (!this.eventOptions_.supportsListeners) | 214 if (!this.eventOptions_.supportsListeners) |
235 throw new Error("This event does not support listeners."); | 215 throw new Error("This event does not support listeners."); |
236 if (this.eventOptions_.maxListeners && | 216 if (this.eventOptions_.maxListeners && |
237 this.getListenerCount() >= this.eventOptions_.maxListeners) | 217 this.getListenerCount() >= this.eventOptions_.maxListeners) |
238 throw new Error("Too many listeners for " + this.eventName_); | 218 throw new Error("Too many listeners for " + this.eventName_); |
239 if (filters) { | 219 if (filters) { |
240 if (!this.eventOptions_.supportsFilters) | 220 if (!this.eventOptions_.supportsFilters) |
241 throw new Error("This event does not support filters."); | 221 throw new Error("This event does not support filters."); |
242 if (filters.url && !(filters.url instanceof Array)) | 222 if (filters.url && !(filters.url instanceof Array)) |
243 throw new Error("filters.url should be an array"); | 223 throw new Error("filters.url should be an array"); |
244 } | 224 } |
245 var listener = {callback: cb, filters: filters}; | 225 var listener = {callback: cb, filters: filters}; |
246 this.attach_(listener); | 226 this.attach_(listener); |
247 this.listeners_.push(listener); | 227 this.listeners_.push(listener); |
248 }; | 228 }; |
249 | 229 |
250 Event.prototype.attach_ = function(listener) { | 230 Event.prototype.attach_ = function(listener) { |
251 this.attachmentStrategy_.onAddedListener(listener); | 231 this.attachmentStrategy_.onAddedListener(listener); |
252 if (this.listeners_.length == 0) { | 232 if (this.listeners_.length == 0) { |
253 allAttachedEvents[allAttachedEvents.length] = this; | 233 allAttachedEvents[allAttachedEvents.length] = this; |
254 if (!this.eventName_) | 234 if (!this.eventName_) |
255 return; | 235 return; |
256 | 236 |
257 if (attachedNamedEvents[this.eventName_]) { | 237 if (attachedNamedEvents[this.eventName_]) { |
258 throw new Error("chrome.Event '" + this.eventName_ + | 238 throw new Error("Event '" + this.eventName_ + "' is already attached."); |
259 "' is already attached."); | |
260 } | 239 } |
261 | 240 |
262 attachedNamedEvents[this.eventName_] = this; | 241 attachedNamedEvents[this.eventName_] = this; |
263 } | 242 } |
264 }; | 243 }; |
265 | 244 |
266 // Unregisters a callback. | 245 // Unregisters a callback. |
267 Event.prototype.removeListener = function(cb) { | 246 Event.prototype.removeListener = function(cb) { |
268 if (!this.eventOptions_.supportsListeners) | 247 if (!this.eventOptions_.supportsListeners) |
269 throw new Error("This event does not support listeners."); | 248 throw new Error("This event does not support listeners."); |
270 var idx = this.findListener_(cb); | 249 var idx = this.findListener_(cb); |
271 if (idx == -1) { | 250 if (idx == -1) { |
272 return; | 251 return; |
273 } | 252 } |
274 | 253 |
275 var removedListener = this.listeners_.splice(idx, 1)[0]; | 254 var removedListener = this.listeners_.splice(idx, 1)[0]; |
276 this.attachmentStrategy_.onRemovedListener(removedListener); | 255 this.attachmentStrategy_.onRemovedListener(removedListener); |
277 | 256 |
278 if (this.listeners_.length == 0) { | 257 if (this.listeners_.length == 0) { |
279 var i = allAttachedEvents.indexOf(this); | 258 var i = allAttachedEvents.indexOf(this); |
280 if (i >= 0) | 259 if (i >= 0) |
281 delete allAttachedEvents[i]; | 260 delete allAttachedEvents[i]; |
282 if (!this.eventName_) | 261 if (!this.eventName_) |
283 return; | 262 return; |
284 | 263 |
285 if (!attachedNamedEvents[this.eventName_]) { | 264 if (!attachedNamedEvents[this.eventName_]) { |
286 throw new Error("chrome.Event '" + this.eventName_ + | 265 throw new Error("Event '" + this.eventName_ + "' is not attached."); |
287 "' is not attached."); | |
288 } | 266 } |
289 | 267 |
290 delete attachedNamedEvents[this.eventName_]; | 268 delete attachedNamedEvents[this.eventName_]; |
291 } | 269 } |
292 }; | 270 }; |
293 | 271 |
294 // Test if the given callback is registered for this event. | 272 // Test if the given callback is registered for this event. |
295 Event.prototype.hasListener = function(cb) { | 273 Event.prototype.hasListener = function(cb) { |
296 if (!this.eventOptions_.supportsListeners) | 274 if (!this.eventOptions_.supportsListeners) |
297 throw new Error("This event does not support listeners."); | 275 throw new Error("This event does not support listeners."); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
336 var listeners = | 314 var listeners = |
337 this.attachmentStrategy_.getListenersByIDs(listenerIDs).slice(); | 315 this.attachmentStrategy_.getListenersByIDs(listenerIDs).slice(); |
338 | 316 |
339 var results = []; | 317 var results = []; |
340 for (var i = 0; i < listeners.length; i++) { | 318 for (var i = 0; i < listeners.length; i++) { |
341 try { | 319 try { |
342 var result = this.dispatchToListener(listeners[i].callback, args); | 320 var result = this.dispatchToListener(listeners[i].callback, args); |
343 if (result !== undefined) | 321 if (result !== undefined) |
344 results.push(result); | 322 results.push(result); |
345 } catch (e) { | 323 } catch (e) { |
346 console.error("Error in event handler for '" + this.eventName_ + | 324 var errorMessage = "Error in event handler"; |
347 "': " + e.message + ' ' + e.stack); | 325 if (this.eventName_) |
| 326 errorMessage += " for " + this.eventName_; |
| 327 errorMessage += ": " + e; |
| 328 console.error(errorMessage); |
348 } | 329 } |
349 } | 330 } |
350 if (results.length) | 331 if (results.length) |
351 return {results: results}; | 332 return {results: results}; |
352 } | 333 } |
353 | 334 |
354 // Can be overridden to support custom dispatching. | 335 // Can be overridden to support custom dispatching. |
355 Event.prototype.dispatchToListener = function(callback, args) { | 336 Event.prototype.dispatchToListener = function(callback, args) { |
356 return callback.apply(null, args); | 337 return callback.apply(null, args); |
357 } | 338 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
392 // Validate conditions and actions against specific schemas of this | 373 // Validate conditions and actions against specific schemas of this |
393 // event object type. | 374 // event object type. |
394 // |rules| is an array of JSON objects that follow the Rule type of the | 375 // |rules| is an array of JSON objects that follow the Rule type of the |
395 // declarative extension APIs. |conditions| is an array of JSON type | 376 // declarative extension APIs. |conditions| is an array of JSON type |
396 // identifiers that are allowed to occur in the conditions attribute of each | 377 // identifiers that are allowed to occur in the conditions attribute of each |
397 // rule. Likewise, |actions| is an array of JSON type identifiers that are | 378 // rule. Likewise, |actions| is an array of JSON type identifiers that are |
398 // allowed to occur in the actions attribute of each rule. | 379 // allowed to occur in the actions attribute of each rule. |
399 function validateRules(rules, conditions, actions) { | 380 function validateRules(rules, conditions, actions) { |
400 var conditionsSchema = buildArrayOfChoicesSchema(conditions); | 381 var conditionsSchema = buildArrayOfChoicesSchema(conditions); |
401 var actionsSchema = buildArrayOfChoicesSchema(actions); | 382 var actionsSchema = buildArrayOfChoicesSchema(actions); |
402 forEach(rules, function(i, rule) { | 383 for (var i = 0; i < rules.length; ++i) { |
| 384 var rule = rules[i]; |
403 validate([rule.conditions], [conditionsSchema]); | 385 validate([rule.conditions], [conditionsSchema]); |
404 validate([rule.actions], [actionsSchema]); | 386 validate([rule.actions], [actionsSchema]); |
405 }) | 387 } |
406 }; | 388 }; |
407 | 389 |
408 if (!this.eventOptions_.conditions || !this.eventOptions_.actions) { | 390 if (!this.eventOptions_.conditions || !this.eventOptions_.actions) { |
409 throw new Error('Event ' + this.eventName_ + ' misses conditions or ' + | 391 throw new Error('Event ' + this.eventName_ + ' misses conditions or ' + |
410 'actions in the API specification.'); | 392 'actions in the API specification.'); |
411 } | 393 } |
412 | 394 |
413 validateRules(rules, | 395 validateRules(rules, |
414 this.eventOptions_.conditions, | 396 this.eventOptions_.conditions, |
415 this.eventOptions_.actions); | 397 this.eventOptions_.actions); |
(...skipping 27 matching lines...) Expand all Loading... |
443 // We remove the first parameter from the validation to give the user more | 425 // We remove the first parameter from the validation to give the user more |
444 // meaningful error messages. | 426 // meaningful error messages. |
445 validate([ruleIdentifiers, cb], | 427 validate([ruleIdentifiers, cb], |
446 ruleFunctionSchemas.getRules.parameters.slice().splice(1)); | 428 ruleFunctionSchemas.getRules.parameters.slice().splice(1)); |
447 | 429 |
448 sendRequest("events.getRules", | 430 sendRequest("events.getRules", |
449 [this.eventName_, ruleIdentifiers, cb], | 431 [this.eventName_, ruleIdentifiers, cb], |
450 ruleFunctionSchemas.getRules.parameters); | 432 ruleFunctionSchemas.getRules.parameters); |
451 } | 433 } |
452 | 434 |
453 // Special load events: we don't use the DOM unload because that slows | 435 onUnload.addListener(function() { |
454 // down tab shutdown. On the other hand, onUnload might not always fire, | |
455 // since Chrome will terminate renderers on shutdown (SuddenTermination). | |
456 chromeHidden.onUnload = new Event(); | |
457 | |
458 chromeHidden.dispatchOnUnload = function() { | |
459 chromeHidden.onUnload.dispatch(); | |
460 chromeHidden.wasUnloaded = true; | |
461 | |
462 for (var i = 0; i < allAttachedEvents.length; ++i) { | 436 for (var i = 0; i < allAttachedEvents.length; ++i) { |
463 var event = allAttachedEvents[i]; | 437 var event = allAttachedEvents[i]; |
464 if (event) | 438 if (event) |
465 event.detach_(); | 439 event.detach_(); |
466 } | 440 } |
467 }; | 441 }); |
468 | 442 |
469 chrome.Event = Event; | 443 exports.Event = Event; |
| 444 exports.dispatchEvent = dispatchEvent; |
| 445 exports.parseEventOptions = parseEventOptions; |
| 446 exports.registerArgumentMassager = registerArgumentMassager; |
OLD | NEW |