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

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

Issue 10392008: Move declarative API into events API (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 7 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 eventBindingsNatives = requireNative('event_bindings'); 5 var eventBindingsNatives = requireNative('event_bindings');
6 var AttachEvent = eventBindingsNatives.AttachEvent; 6 var AttachEvent = eventBindingsNatives.AttachEvent;
7 var DetachEvent = eventBindingsNatives.DetachEvent; 7 var DetachEvent = eventBindingsNatives.DetachEvent;
8 var Print = eventBindingsNatives.Print; 8 var Print = eventBindingsNatives.Print;
9 var sendRequest = require('sendRequest').sendRequest;
Aaron Boodman 2012/05/09 19:29:46 TODO(aa): Look at this file more closely.
9 10
10 var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); 11 var chromeHidden = requireNative('chrome_hidden').GetChromeHidden();
11 12
12 // Local implementation of JSON.parse & JSON.stringify that protect us 13 // Local implementation of JSON.parse & JSON.stringify that protect us
13 // from being clobbered by an extension. 14 // from being clobbered by an extension.
14 // 15 //
15 // TODO(aa): This makes me so sad. We shouldn't need it, as we can just pass 16 // TODO(aa): This makes me so sad. We shouldn't need it, as we can just pass
16 // Values directly over IPC without serializing to strings and use 17 // Values directly over IPC without serializing to strings and use
17 // JSONValueConverter. 18 // JSONValueConverter.
18 chromeHidden.JSON = new (function() { 19 chromeHidden.JSON = new (function() {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 // opt_eventName is required for events that support rules. 54 // opt_eventName is required for events that support rules.
54 // 55 //
55 // Example: 56 // Example:
56 // chrome.tabs.onChanged = new chrome.Event("tab-changed"); 57 // chrome.tabs.onChanged = new chrome.Event("tab-changed");
57 // chrome.tabs.onChanged.addListener(function(data) { alert(data); }); 58 // chrome.tabs.onChanged.addListener(function(data) { alert(data); });
58 // chromeHidden.Event.dispatch("tab-changed", "hi"); 59 // chromeHidden.Event.dispatch("tab-changed", "hi");
59 // will result in an alert dialog that says 'hi'. 60 // will result in an alert dialog that says 'hi'.
60 // 61 //
61 // If opt_eventOptions exists, it is a dictionary that contains the boolean 62 // If opt_eventOptions exists, it is a dictionary that contains the boolean
62 // entries "supportsListeners" and "supportsRules". 63 // entries "supportsListeners" and "supportsRules".
63 chrome.Event = function(opt_eventName, opt_argSchemas, opt_eventOptions) { 64 chrome.Event = function(opt_eventName, opt_argSchemas, opt_eventOptions,
not at google - send to devlin 2012/05/10 09:01:25 nit: arguments should line up or fix on 1 line :(
battre 2012/05/10 16:40:29 According to the JavaScript Style Guide, the rule
65 opt_eventsSchema) {
64 this.eventName_ = opt_eventName; 66 this.eventName_ = opt_eventName;
65 this.listeners_ = []; 67 this.listeners_ = [];
66 this.eventOptions_ = opt_eventOptions || 68 this.eventOptions_ = opt_eventOptions ||
67 {"supportsListeners": true, "supportsRules": false}; 69 {"supportsListeners": true, "supportsRules": false};
70 this.eventsSchema_ = opt_eventsSchema;
68 71
69 if (this.eventOptions_.supportsRules && !opt_eventName) 72 if (this.eventOptions_.supportsRules && !opt_eventName)
70 throw new Error("Events that support rules require an event name."); 73 throw new Error("Events that support rules require an event name.");
71 74
72 // Validate event parameters if we are in debug. 75 // Validate event arguments (the data that is passed to the callbacks)
76 // if we are in debug.
73 if (opt_argSchemas && 77 if (opt_argSchemas &&
74 chromeHidden.validateCallbacks && 78 chromeHidden.validateCallbacks &&
75 chromeHidden.validate) { 79 chromeHidden.validate) {
76 80
77 this.validate_ = function(args) { 81 this.validateEventArgs_ = function(args) {
78 try { 82 try {
79 chromeHidden.validate(args, opt_argSchemas); 83 chromeHidden.validate(args, opt_argSchemas);
80 } catch (exception) { 84 } catch (exception) {
81 return "Event validation error during " + opt_eventName + " -- " + 85 return "Event validation error during " + opt_eventName + " -- " +
82 exception; 86 exception;
83 } 87 }
84 }; 88 };
85 } else { 89 } else {
86 this.validate_ = function() {} 90 this.validateEventArgs_ = function() {}
91 }
92
93 if (this.eventOptions_.supportsRules) {
94 if (!this.eventsSchema_) {
95 throw new Error("Events with rules support require the schema of the " +
96 "chrome.events namespace");
97 }
98 // Determine schemas of function parameters.
99 var eventType = chromeHidden.lookup(this.eventsSchema_.types,
100 'id', 'Event');
not at google - send to devlin 2012/05/10 09:01:25 nit: argument lineup thing (and on the lines below
battre 2012/05/10 16:40:29 See above
101 this.addRulesParams_ = chromeHidden.lookup(eventType.functions,
102 'name', 'addRules').parameters;
103 this.getRulesParams_ = chromeHidden.lookup(eventType.functions,
104 'name', 'getRules').parameters;
105 this.removeRulesParams_ = chromeHidden.lookup(eventType.functions,
106 'name', 'removeRules').parameters;
107 } else {
108 this.addRulesParams_ = [];
109 this.getRulesParams_ = [];
110 this.removeRulesParams_ = [];
87 } 111 }
88 }; 112 };
89 113
90 // A map of event names to the event object that is registered to that name. 114 // A map of event names to the event object that is registered to that name.
91 var attachedNamedEvents = {}; 115 var attachedNamedEvents = {};
92 116
93 // An array of all attached event objects, used for detaching on unload. 117 // An array of all attached event objects, used for detaching on unload.
94 var allAttachedEvents = []; 118 var allAttachedEvents = [];
95 119
96 // A map of functions that massage event arguments before they are dispatched. 120 // A map of functions that massage event arguments before they are dispatched.
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 210
187 return -1; 211 return -1;
188 }; 212 };
189 213
190 // Dispatches this event object to all listeners, passing all supplied 214 // Dispatches this event object to all listeners, passing all supplied
191 // arguments to this function each listener. 215 // arguments to this function each listener.
192 chrome.Event.prototype.dispatch = function(varargs) { 216 chrome.Event.prototype.dispatch = function(varargs) {
193 if (!this.eventOptions_.supportsListeners) 217 if (!this.eventOptions_.supportsListeners)
194 throw new Error("This event does not support listeners."); 218 throw new Error("This event does not support listeners.");
195 var args = Array.prototype.slice.call(arguments); 219 var args = Array.prototype.slice.call(arguments);
196 var validationErrors = this.validate_(args); 220 var validationErrors = this.validateEventArgs_(args);
197 if (validationErrors) { 221 if (validationErrors) {
198 return {validationErrors: validationErrors}; 222 return {validationErrors: validationErrors};
199 } 223 }
200 var results = []; 224 var results = [];
201 for (var i = 0; i < this.listeners_.length; i++) { 225 for (var i = 0; i < this.listeners_.length; i++) {
202 try { 226 try {
203 var result = this.listeners_[i].apply(null, args); 227 var result = this.listeners_[i].apply(null, args);
204 if (result !== undefined) 228 if (result !== undefined)
205 results.push(result); 229 results.push(result);
206 } catch (e) { 230 } catch (e) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 if (!attachedNamedEvents[this.eventName_]) { 264 if (!attachedNamedEvents[this.eventName_]) {
241 throw new Error("chrome.Event '" + this.eventName_ + 265 throw new Error("chrome.Event '" + this.eventName_ +
242 "' is not attached."); 266 "' is not attached.");
243 } 267 }
244 268
245 delete attachedNamedEvents[this.eventName_]; 269 delete attachedNamedEvents[this.eventName_];
246 }; 270 };
247 271
248 chrome.Event.prototype.destroy_ = function() { 272 chrome.Event.prototype.destroy_ = function() {
249 this.listeners_ = []; 273 this.listeners_ = [];
250 this.validate_ = []; 274 this.validateEventArgs_ = [];
251 this.detach_(false); 275 this.detach_(false);
252 }; 276 };
253 277
254 // Gets the declarative API object, or undefined if this extension doesn't
255 // have access to it.
256 //
257 // This is defined as a function (rather than a variable) because it isn't
258 // accessible until the schema bindings have been generated.
259 function getDeclarativeAPI() {
260 return chromeHidden.internalAPIs.declarative;
261 }
262
263 chrome.Event.prototype.addRules = function(rules, opt_cb) { 278 chrome.Event.prototype.addRules = function(rules, opt_cb) {
264 if (!this.eventOptions_.supportsRules) 279 if (!this.eventOptions_.supportsRules)
265 throw new Error("This event does not support rules."); 280 throw new Error("This event does not support rules.");
266 if (!getDeclarativeAPI()) { 281
267 throw new Error("You must have permission to use the declarative " + 282 // Takes a list of JSON datatype identifiers and returns a schema fragment
268 "API to support rules in events"); 283 // that verifies that a JSON object corresponds to an array of only these
284 // data types.
285 function buildArrayOfChoicesSchema(typesList) {
286 return {
287 'type': 'array',
288 'items': {
289 'choices': typesList.map(function(el) {return {'$ref': el};})
290 }
291 };
292 };
293
294 // Validate conditions and actions against specific schemas of this
295 // event object type.
296 // |rules| is an array of JSON objects that follow the Rule type of the
297 // declarative extension APIs. |conditions| is an array of JSON type
298 // identifiers that are allowed to occur in the conditions attribute of each
299 // rule. Likewise, |actions| is an array of JSON type identifiers that are
300 // allowed to occur in the actions attribute of each rule.
301 function validateRules(rules, conditions, actions) {
302 var conditionsSchema = buildArrayOfChoicesSchema(conditions);
303 var actionsSchema = buildArrayOfChoicesSchema(actions);
304 rules.forEach(function(rule) {
305 chromeHidden.validate([rule.conditions], [conditionsSchema]);
306 chromeHidden.validate([rule.actions], [actionsSchema]);
307 })
308 };
309
310 if (!this.eventOptions_.conditions || !this.eventOptions_.actions) {
311 throw new Error('Event ' + this.eventName_ + ' misses conditions or ' +
312 'actions in the API specification.');
269 } 313 }
270 getDeclarativeAPI().addRules(this.eventName_, rules, opt_cb); 314
315 validateRules(rules,
316 this.eventOptions_.conditions,
317 this.eventOptions_.actions);
318
319 sendRequest("events.addRules", [this.eventName_, rules, opt_cb],
320 this.addRulesParams_);
not at google - send to devlin 2012/05/10 09:01:25 did we lose the ability to do chromeHidden.interna
battre 2012/05/10 16:40:29 Yes, because there is no such function anymore. "e
271 } 321 }
272 322
273 chrome.Event.prototype.removeRules = function(ruleIdentifiers, opt_cb) { 323 chrome.Event.prototype.removeRules = function(ruleIdentifiers, opt_cb) {
274 if (!this.eventOptions_.supportsRules) 324 if (!this.eventOptions_.supportsRules)
275 throw new Error("This event does not support rules."); 325 throw new Error("This event does not support rules.");
276 if (!getDeclarativeAPI()) { 326 sendRequest("events.removeRules",
277 throw new Error("You must have permission to use the declarative " + 327 [this.eventName_, ruleIdentifiers, opt_cb],
278 "API to support rules in events"); 328 this.removeRulesParams_);
279 }
280 getDeclarativeAPI().removeRules(
281 this.eventName_, ruleIdentifiers, opt_cb);
282 } 329 }
283 330
284 chrome.Event.prototype.getRules = function(ruleIdentifiers, cb) { 331 chrome.Event.prototype.getRules = function(ruleIdentifiers, cb) {
285 if (!this.eventOptions_.supportsRules) 332 if (!this.eventOptions_.supportsRules)
286 throw new Error("This event does not support rules."); 333 throw new Error("This event does not support rules.");
287 if (!getDeclarativeAPI()) { 334 sendRequest("events.getRules",
288 throw new Error("You must have permission to use the declarative " + 335 [this.eventName_, ruleIdentifiers, cb],
289 "API to support rules in events"); 336 this.getRulesParams_);
290 }
291 getDeclarativeAPI().getRules(
292 this.eventName_, ruleIdentifiers, cb);
293 } 337 }
294 338
295 // Special load events: we don't use the DOM unload because that slows 339 // Special load events: we don't use the DOM unload because that slows
296 // down tab shutdown. On the other hand, onUnload might not always fire, 340 // down tab shutdown. On the other hand, onUnload might not always fire,
297 // since Chrome will terminate renderers on shutdown (SuddenTermination). 341 // since Chrome will terminate renderers on shutdown (SuddenTermination).
298 chromeHidden.onLoad = new chrome.Event(); 342 chromeHidden.onLoad = new chrome.Event();
299 chromeHidden.onUnload = new chrome.Event(); 343 chromeHidden.onUnload = new chrome.Event();
300 344
301 chromeHidden.dispatchOnLoad = 345 chromeHidden.dispatchOnLoad =
302 chromeHidden.onLoad.dispatch.bind(chromeHidden.onLoad); 346 chromeHidden.onLoad.dispatch.bind(chromeHidden.onLoad);
303 347
304 chromeHidden.dispatchOnUnload = function() { 348 chromeHidden.dispatchOnUnload = function() {
305 chromeHidden.onUnload.dispatch(); 349 chromeHidden.onUnload.dispatch();
306 for (var i = 0; i < allAttachedEvents.length; ++i) { 350 for (var i = 0; i < allAttachedEvents.length; ++i) {
307 var event = allAttachedEvents[i]; 351 var event = allAttachedEvents[i];
308 if (event) 352 if (event)
309 event.detach_(false); 353 event.detach_(false);
310 } 354 }
311 }; 355 };
312 356
313 chromeHidden.dispatchError = function(msg) { 357 chromeHidden.dispatchError = function(msg) {
314 console.error(msg); 358 console.error(msg);
315 }; 359 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698