Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: chrome/renderer/resources/extensions/event.js

Issue 10704073: Plumb listenerIDs correctly for events that clobber chrome.Event.prototype.dispatch. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: respond to commens Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 eventBindingsNatives = requireNative('event_bindings'); 6 var eventBindingsNatives = requireNative('event_bindings');
6 var AttachEvent = eventBindingsNatives.AttachEvent; 7 var AttachEvent = eventBindingsNatives.AttachEvent;
7 var DetachEvent = eventBindingsNatives.DetachEvent; 8 var DetachEvent = eventBindingsNatives.DetachEvent;
8 var AttachFilteredEvent = eventBindingsNatives.AttachFilteredEvent; 9 var AttachFilteredEvent = eventBindingsNatives.AttachFilteredEvent;
9 var DetachFilteredEvent = eventBindingsNatives.DetachFilteredEvent; 10 var DetachFilteredEvent = eventBindingsNatives.DetachFilteredEvent;
10 var MatchAgainstEventFilter = eventBindingsNatives.MatchAgainstEventFilter; 11 var MatchAgainstEventFilter = eventBindingsNatives.MatchAgainstEventFilter;
11 var sendRequest = require('sendRequest').sendRequest; 12 var sendRequest = require('sendRequest').sendRequest;
12 var utils = require('utils'); 13 var utils = require('utils');
13 var validate = require('schemaUtils').validate; 14 var validate = require('schemaUtils').validate;
14 15
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 exception; 202 exception;
202 } 203 }
203 }; 204 };
204 } else { 205 } else {
205 this.validateEventArgs_ = function() {} 206 this.validateEventArgs_ = function() {}
206 } 207 }
207 }; 208 };
208 209
209 chromeHidden.Event = {}; 210 chromeHidden.Event = {};
210 211
211 chromeHidden.Event.registerArgumentMassager = function(name, fn) { 212 // callback is a function(args, dispatch). args are the args we recieve from
213 // dispatchJSON(), and dispatch is a function(args) that dispatches args to
214 // its listeners.
215 chromeHidden.Event.registerArgumentMassager = function(name, callback) {
212 if (eventArgumentMassagers[name]) 216 if (eventArgumentMassagers[name])
213 throw new Error("Massager already registered for event: " + name); 217 throw new Error("Massager already registered for event: " + name);
214 eventArgumentMassagers[name] = fn; 218 eventArgumentMassagers[name] = callback;
215 }; 219 };
216 220
217 // Dispatches a named event with the given JSON array, which is deserialized 221 // Dispatches a named event with the given JSON array, which is deserialized
218 // before dispatch. The JSON array is the list of arguments that will be 222 // before dispatch. The JSON array is the list of arguments that will be
219 // sent with the event callback. 223 // sent with the event callback.
220 chromeHidden.Event.dispatchJSON = function(name, args, filteringInfo) { 224 chromeHidden.Event.dispatchJSON = function(name, args, filteringInfo) {
221 var listenerIDs = null; 225 var listenerIDs = null;
222 226
223 if (filteringInfo) { 227 if (filteringInfo)
224 listenerIDs = MatchAgainstEventFilter(name, filteringInfo); 228 listenerIDs = MatchAgainstEventFilter(name, filteringInfo);
225 }
226 if (attachedNamedEvents[name]) {
227 if (args) {
228 // TODO(asargent): This is an antiquity. Until all callers of
229 // dispatchJSON use actual values, this must remain here to catch the
230 // cases where a caller has hard-coded a JSON string to pass in.
231 if (typeof(args) == "string") {
232 args = chromeHidden.JSON.parse(args);
233 }
234 if (eventArgumentMassagers[name])
235 eventArgumentMassagers[name](args);
236 }
237 229
238 var event = attachedNamedEvents[name]; 230 var event = attachedNamedEvents[name];
239 var result; 231 if (!event)
240 // TODO(koz): We have to do this differently for unfiltered events (which 232 return;
241 // have listenerIDs = null) because some bindings write over
242 // event.dispatch (eg: experimental.app.custom_bindings.js) and so expect
243 // events to go through it. These places need to be fixed so that they
244 // expect a listenerIDs parameter.
245 if (listenerIDs)
246 result = event.dispatch_(args, listenerIDs);
247 else
248 result = event.dispatch.apply(event, args);
249 if (result && result.validationErrors)
250 return result.validationErrors;
251 }
252 };
253 233
254 // Dispatches a named event with the given arguments, supplied as an array. 234 // TODO(asargent): This is an antiquity. Until all callers of
255 chromeHidden.Event.dispatch = function(name, args) { 235 // dispatchJSON use actual values, this must remain here to catch the
256 if (attachedNamedEvents[name]) { 236 // cases where a caller has hard-coded a JSON string to pass in.
257 attachedNamedEvents[name].dispatch.apply( 237 if (typeof(args) == "string")
258 attachedNamedEvents[name], args); 238 args = chromeHidden.JSON.parse(args);
259 } 239
240 var dispatchArgs = function(args) {
241 result = event.dispatch_(args, listenerIDs);
242 if (result)
243 DCHECK(!result.validationErrors, result.validationErrors);
244 };
245
246 if (eventArgumentMassagers[name])
247 eventArgumentMassagers[name](args, dispatchArgs);
248 else
249 dispatchArgs(args);
260 }; 250 };
261 251
262 // Test if a named event has any listeners. 252 // Test if a named event has any listeners.
263 chromeHidden.Event.hasListener = function(name) { 253 chromeHidden.Event.hasListener = function(name) {
264 return (attachedNamedEvents[name] && 254 return (attachedNamedEvents[name] &&
265 attachedNamedEvents[name].listeners_.length > 0); 255 attachedNamedEvents[name].listeners_.length > 0);
266 }; 256 };
267 257
268 // Registers a callback to be called when this event is dispatched. 258 // Registers a callback to be called when this event is dispatched.
269 chrome.Event.prototype.addListener = function(cb, filters) { 259 chrome.Event.prototype.addListener = function(cb, filters) {
270 if (!this.eventOptions_.supportsListeners) 260 if (!this.eventOptions_.supportsListeners)
271 throw new Error("This event does not support listeners."); 261 throw new Error("This event does not support listeners.");
262 if (this.eventOptions_.maxListeners &&
263 this.getListenerCount() >= this.eventOptions_.maxListeners)
264 throw new Error("Too many listeners for " + this.eventName_);
272 if (filters) { 265 if (filters) {
273 if (!this.eventOptions_.supportsFilters) 266 if (!this.eventOptions_.supportsFilters)
274 throw new Error("This event does not support filters."); 267 throw new Error("This event does not support filters.");
275 if (filters.url && !(filters.url instanceof Array)) 268 if (filters.url && !(filters.url instanceof Array))
276 throw new Error("filters.url should be an array"); 269 throw new Error("filters.url should be an array");
277 } 270 }
278 var listener = {callback: cb, filters: filters}; 271 var listener = {callback: cb, filters: filters};
279 this.attach_(listener); 272 this.attach_(listener);
280 this.listeners_.push(listener); 273 this.listeners_.push(listener);
281 }; 274 };
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 319
327 // Test if the given callback is registered for this event. 320 // Test if the given callback is registered for this event.
328 chrome.Event.prototype.hasListener = function(cb) { 321 chrome.Event.prototype.hasListener = function(cb) {
329 if (!this.eventOptions_.supportsListeners) 322 if (!this.eventOptions_.supportsListeners)
330 throw new Error("This event does not support listeners."); 323 throw new Error("This event does not support listeners.");
331 return this.findListener_(cb) > -1; 324 return this.findListener_(cb) > -1;
332 }; 325 };
333 326
334 // Test if any callbacks are registered for this event. 327 // Test if any callbacks are registered for this event.
335 chrome.Event.prototype.hasListeners = function() { 328 chrome.Event.prototype.hasListeners = function() {
329 return this.getListenerCount() > 0;
330 };
331
332 // Return the number of listeners on this event.
333 chrome.Event.prototype.getListenerCount = function() {
336 if (!this.eventOptions_.supportsListeners) 334 if (!this.eventOptions_.supportsListeners)
337 throw new Error("This event does not support listeners."); 335 throw new Error("This event does not support listeners.");
338 return this.listeners_.length > 0; 336 return this.listeners_.length;
339 }; 337 };
340 338
341 // Returns the index of the given callback if registered, or -1 if not 339 // Returns the index of the given callback if registered, or -1 if not
342 // found. 340 // found.
343 chrome.Event.prototype.findListener_ = function(cb) { 341 chrome.Event.prototype.findListener_ = function(cb) {
344 for (var i = 0; i < this.listeners_.length; i++) { 342 for (var i = 0; i < this.listeners_.length; i++) {
345 if (this.listeners_[i].callback == cb) { 343 if (this.listeners_[i].callback == cb) {
346 return i; 344 return i;
347 } 345 }
348 } 346 }
349 347
350 return -1; 348 return -1;
351 }; 349 };
352 350
353 chrome.Event.prototype.dispatch_ = function(args, listenerIDs) { 351 chrome.Event.prototype.dispatch_ = function(args, listenerIDs) {
354 if (!this.eventOptions_.supportsListeners) 352 if (!this.eventOptions_.supportsListeners)
355 throw new Error("This event does not support listeners."); 353 throw new Error("This event does not support listeners.");
356 var validationErrors = this.validateEventArgs_(args); 354 var validationErrors = this.validateEventArgs_(args);
357 if (validationErrors) { 355 if (validationErrors) {
358 console.error(validationErrors); 356 console.error(validationErrors);
359 return {validationErrors: validationErrors}; 357 return {validationErrors: validationErrors};
360 } 358 }
361 359
362 var listeners = this.attachmentStrategy_.getListenersByIDs(listenerIDs); 360 var listeners = this.attachmentStrategy_.getListenersByIDs(listenerIDs);
363 361
364 var results = []; 362 var results = [];
365 for (var i = 0; i < listeners.length; i++) { 363 for (var i = 0; i < listeners.length; i++) {
366 try { 364 try {
367 var result = listeners[i].callback.apply(null, args); 365 var result = this.dispatchToListener(listeners[i].callback, args);
368 if (result !== undefined) 366 if (result !== undefined)
369 results.push(result); 367 results.push(result);
370 } catch (e) { 368 } catch (e) {
371 console.error("Error in event handler for '" + this.eventName_ + 369 console.error("Error in event handler for '" + this.eventName_ +
372 "': " + e.message + ' ' + e.stack); 370 "': " + e.message + ' ' + e.stack);
373 } 371 }
374 } 372 }
375 if (results.length) 373 if (results.length)
376 return {results: results}; 374 return {results: results};
377 } 375 }
378 376
377 // Can be overridden to support custom dispatching.
378 chrome.Event.prototype.dispatchToListener = function(callback, args) {
379 return callback.apply(null, args);
380 }
381
379 // Dispatches this event object to all listeners, passing all supplied 382 // Dispatches this event object to all listeners, passing all supplied
380 // arguments to this function each listener. 383 // arguments to this function each listener.
381 chrome.Event.prototype.dispatch = function(varargs) { 384 chrome.Event.prototype.dispatch = function(varargs) {
382 return this.dispatch_(Array.prototype.slice.call(arguments), undefined); 385 return this.dispatch_(Array.prototype.slice.call(arguments), undefined);
383 }; 386 };
384 387
385 // Detaches this event object from its name. 388 // Detaches this event object from its name.
386 chrome.Event.prototype.detach_ = function() { 389 chrome.Event.prototype.detach_ = function() {
387 this.attachmentStrategy_.detach(false); 390 this.attachmentStrategy_.detach(false);
388 }; 391 };
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
473 if (event) 476 if (event)
474 event.detach_(); 477 event.detach_();
475 } 478 }
476 }; 479 };
477 480
478 chromeHidden.dispatchError = function(msg) { 481 chromeHidden.dispatchError = function(msg) {
479 console.error(msg); 482 console.error(msg);
480 }; 483 };
481 484
482 exports.Event = chrome.Event; 485 exports.Event = chrome.Event;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698