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

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: Don't provide scheme to each event individually and create util module 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 sendRequest = require('sendRequest').sendRequest;
9 var utils = require('utils');
8 10
9 var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); 11 var chromeHidden = requireNative('chrome_hidden').GetChromeHidden();
10 12
13 // Schema definitions for the parameters of functions of Event.
14 var addRulesParams = undefined;
Aaron Boodman 2012/05/10 18:27:51 undefined is weird in JavaScript. Suffice to say,
battre 2012/05/11 13:08:46 Done.
not at google - send to devlin 2012/05/14 07:29:38 Can you also prefix them with Schema? I wasn't su
not at google - send to devlin 2012/05/14 07:30:34 (ignore this, forgot to delete, sorry)
15 var getRulesParams = undefined;
16 var removeRulesParams = undefined;
17
18 // This function needs to be called once (only in case Events with rules are
19 // instantiated) to provide the schema definitions for function calls.
20 // |eventsSchema| is the schema of the "events" namespace.
21 function storeFunctionSchemes(eventsSchema) {
not at google - send to devlin 2012/05/14 07:29:38 Schemes -> Schemas?
22 // Schema definition of Events object.
23 var eventType = utils.lookup(eventsSchema.types, 'id', 'Event');
24
25 addRulesParams =
26 utils.lookup(eventType.functions, 'name', 'addRules').parameters;
27 getRulesParams =
28 utils.lookup(eventType.functions, 'name', 'getRules').parameters;
29 removeRulesParams =
30 utils.lookup(eventType.functions, 'name', 'removeRules').parameters;
31 }
32
11 // Local implementation of JSON.parse & JSON.stringify that protect us 33 // Local implementation of JSON.parse & JSON.stringify that protect us
12 // from being clobbered by an extension. 34 // from being clobbered by an extension.
13 // 35 //
14 // TODO(aa): This makes me so sad. We shouldn't need it, as we can just pass 36 // TODO(aa): This makes me so sad. We shouldn't need it, as we can just pass
15 // Values directly over IPC without serializing to strings and use 37 // Values directly over IPC without serializing to strings and use
16 // JSONValueConverter. 38 // JSONValueConverter.
17 chromeHidden.JSON = new (function() { 39 chromeHidden.JSON = new (function() {
18 var $Object = Object; 40 var $Object = Object;
19 var $Array = Array; 41 var $Array = Array;
20 var $jsonStringify = JSON.stringify; 42 var $jsonStringify = JSON.stringify;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 // entries "supportsListeners" and "supportsRules". 83 // entries "supportsListeners" and "supportsRules".
62 chrome.Event = function(opt_eventName, opt_argSchemas, opt_eventOptions) { 84 chrome.Event = function(opt_eventName, opt_argSchemas, opt_eventOptions) {
63 this.eventName_ = opt_eventName; 85 this.eventName_ = opt_eventName;
64 this.listeners_ = []; 86 this.listeners_ = [];
65 this.eventOptions_ = opt_eventOptions || 87 this.eventOptions_ = opt_eventOptions ||
66 {"supportsListeners": true, "supportsRules": false}; 88 {"supportsListeners": true, "supportsRules": false};
67 89
68 if (this.eventOptions_.supportsRules && !opt_eventName) 90 if (this.eventOptions_.supportsRules && !opt_eventName)
69 throw new Error("Events that support rules require an event name."); 91 throw new Error("Events that support rules require an event name.");
70 92
71 // Validate event parameters if we are in debug. 93 // Validate event arguments (the data that is passed to the callbacks)
94 // if we are in debug.
72 if (opt_argSchemas && 95 if (opt_argSchemas &&
73 chromeHidden.validateCallbacks && 96 chromeHidden.validateCallbacks &&
74 chromeHidden.validate) { 97 chromeHidden.validate) {
75 98
76 this.validate_ = function(args) { 99 this.validateEventArgs_ = function(args) {
77 try { 100 try {
78 chromeHidden.validate(args, opt_argSchemas); 101 chromeHidden.validate(args, opt_argSchemas);
79 } catch (exception) { 102 } catch (exception) {
80 return "Event validation error during " + opt_eventName + " -- " + 103 return "Event validation error during " + opt_eventName + " -- " +
81 exception; 104 exception;
82 } 105 }
83 }; 106 };
84 } else { 107 } else {
85 this.validate_ = function() {} 108 this.validateEventArgs_ = function() {}
109 }
110
111 if (this.eventOptions_.supportsRules && !addRulesParams) {
112 throw new Error("storeEventsFunctionSchemes was not called.");
86 } 113 }
87 }; 114 };
88 115
89 // A map of event names to the event object that is registered to that name. 116 // A map of event names to the event object that is registered to that name.
90 var attachedNamedEvents = {}; 117 var attachedNamedEvents = {};
91 118
92 // An array of all attached event objects, used for detaching on unload. 119 // An array of all attached event objects, used for detaching on unload.
93 var allAttachedEvents = []; 120 var allAttachedEvents = [];
94 121
95 // A map of functions that massage event arguments before they are dispatched. 122 // A map of functions that massage event arguments before they are dispatched.
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 212
186 return -1; 213 return -1;
187 }; 214 };
188 215
189 // Dispatches this event object to all listeners, passing all supplied 216 // Dispatches this event object to all listeners, passing all supplied
190 // arguments to this function each listener. 217 // arguments to this function each listener.
191 chrome.Event.prototype.dispatch = function(varargs) { 218 chrome.Event.prototype.dispatch = function(varargs) {
192 if (!this.eventOptions_.supportsListeners) 219 if (!this.eventOptions_.supportsListeners)
193 throw new Error("This event does not support listeners."); 220 throw new Error("This event does not support listeners.");
194 var args = Array.prototype.slice.call(arguments); 221 var args = Array.prototype.slice.call(arguments);
195 var validationErrors = this.validate_(args); 222 var validationErrors = this.validateEventArgs_(args);
196 if (validationErrors) { 223 if (validationErrors) {
197 return {validationErrors: validationErrors}; 224 return {validationErrors: validationErrors};
198 } 225 }
199 var results = []; 226 var results = [];
200 for (var i = 0; i < this.listeners_.length; i++) { 227 for (var i = 0; i < this.listeners_.length; i++) {
201 try { 228 try {
202 var result = this.listeners_[i].apply(null, args); 229 var result = this.listeners_[i].apply(null, args);
203 if (result !== undefined) 230 if (result !== undefined)
204 results.push(result); 231 results.push(result);
205 } catch (e) { 232 } catch (e) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 if (!attachedNamedEvents[this.eventName_]) { 266 if (!attachedNamedEvents[this.eventName_]) {
240 throw new Error("chrome.Event '" + this.eventName_ + 267 throw new Error("chrome.Event '" + this.eventName_ +
241 "' is not attached."); 268 "' is not attached.");
242 } 269 }
243 270
244 delete attachedNamedEvents[this.eventName_]; 271 delete attachedNamedEvents[this.eventName_];
245 }; 272 };
246 273
247 chrome.Event.prototype.destroy_ = function() { 274 chrome.Event.prototype.destroy_ = function() {
248 this.listeners_ = []; 275 this.listeners_ = [];
249 this.validate_ = []; 276 this.validateEventArgs_ = [];
250 this.detach_(false); 277 this.detach_(false);
251 }; 278 };
252 279
253 // Gets the declarative API object, or undefined if this extension doesn't
254 // have access to it.
255 //
256 // This is defined as a function (rather than a variable) because it isn't
257 // accessible until the schema bindings have been generated.
258 function getDeclarativeAPI() {
259 return chromeHidden.internalAPIs.declarative;
260 }
261
262 chrome.Event.prototype.addRules = function(rules, opt_cb) { 280 chrome.Event.prototype.addRules = function(rules, opt_cb) {
263 if (!this.eventOptions_.supportsRules) 281 if (!this.eventOptions_.supportsRules)
264 throw new Error("This event does not support rules."); 282 throw new Error("This event does not support rules.");
265 if (!getDeclarativeAPI()) { 283
266 throw new Error("You must have permission to use the declarative " + 284 // Takes a list of JSON datatype identifiers and returns a schema fragment
267 "API to support rules in events"); 285 // that verifies that a JSON object corresponds to an array of only these
286 // data types.
287 function buildArrayOfChoicesSchema(typesList) {
288 return {
289 'type': 'array',
290 'items': {
291 'choices': typesList.map(function(el) {return {'$ref': el};})
292 }
293 };
294 };
295
296 // Validate conditions and actions against specific schemas of this
297 // event object type.
298 // |rules| is an array of JSON objects that follow the Rule type of the
299 // declarative extension APIs. |conditions| is an array of JSON type
300 // identifiers that are allowed to occur in the conditions attribute of each
301 // rule. Likewise, |actions| is an array of JSON type identifiers that are
302 // allowed to occur in the actions attribute of each rule.
303 function validateRules(rules, conditions, actions) {
304 var conditionsSchema = buildArrayOfChoicesSchema(conditions);
305 var actionsSchema = buildArrayOfChoicesSchema(actions);
306 rules.forEach(function(rule) {
307 chromeHidden.validate([rule.conditions], [conditionsSchema]);
308 chromeHidden.validate([rule.actions], [actionsSchema]);
309 })
310 };
311
312 if (!this.eventOptions_.conditions || !this.eventOptions_.actions) {
313 throw new Error('Event ' + this.eventName_ + ' misses conditions or ' +
314 'actions in the API specification.');
268 } 315 }
269 getDeclarativeAPI().addRules(this.eventName_, rules, opt_cb); 316
317 validateRules(rules,
318 this.eventOptions_.conditions,
319 this.eventOptions_.actions);
320
321 sendRequest("events.addRules", [this.eventName_, rules, opt_cb],
322 addRulesParams);
270 } 323 }
271 324
272 chrome.Event.prototype.removeRules = function(ruleIdentifiers, opt_cb) { 325 chrome.Event.prototype.removeRules = function(ruleIdentifiers, opt_cb) {
273 if (!this.eventOptions_.supportsRules) 326 if (!this.eventOptions_.supportsRules)
274 throw new Error("This event does not support rules."); 327 throw new Error("This event does not support rules.");
275 if (!getDeclarativeAPI()) { 328 sendRequest("events.removeRules",
276 throw new Error("You must have permission to use the declarative " + 329 [this.eventName_, ruleIdentifiers, opt_cb],
277 "API to support rules in events"); 330 removeRulesParams);
278 }
279 getDeclarativeAPI().removeRules(
280 this.eventName_, ruleIdentifiers, opt_cb);
281 } 331 }
282 332
283 chrome.Event.prototype.getRules = function(ruleIdentifiers, cb) { 333 chrome.Event.prototype.getRules = function(ruleIdentifiers, cb) {
284 if (!this.eventOptions_.supportsRules) 334 if (!this.eventOptions_.supportsRules)
285 throw new Error("This event does not support rules."); 335 throw new Error("This event does not support rules.");
286 if (!getDeclarativeAPI()) { 336 sendRequest("events.getRules",
287 throw new Error("You must have permission to use the declarative " + 337 [this.eventName_, ruleIdentifiers, cb],
288 "API to support rules in events"); 338 getRulesParams);
289 }
290 getDeclarativeAPI().getRules(
291 this.eventName_, ruleIdentifiers, cb);
292 } 339 }
293 340
294 // Special load events: we don't use the DOM unload because that slows 341 // Special load events: we don't use the DOM unload because that slows
295 // down tab shutdown. On the other hand, onUnload might not always fire, 342 // down tab shutdown. On the other hand, onUnload might not always fire,
296 // since Chrome will terminate renderers on shutdown (SuddenTermination). 343 // since Chrome will terminate renderers on shutdown (SuddenTermination).
297 chromeHidden.onLoad = new chrome.Event(); 344 chromeHidden.onLoad = new chrome.Event();
298 chromeHidden.onUnload = new chrome.Event(); 345 chromeHidden.onUnload = new chrome.Event();
299 346
300 chromeHidden.dispatchOnLoad = 347 chromeHidden.dispatchOnLoad =
301 chromeHidden.onLoad.dispatch.bind(chromeHidden.onLoad); 348 chromeHidden.onLoad.dispatch.bind(chromeHidden.onLoad);
302 349
303 chromeHidden.dispatchOnUnload = function() { 350 chromeHidden.dispatchOnUnload = function() {
304 chromeHidden.onUnload.dispatch(); 351 chromeHidden.onUnload.dispatch();
305 for (var i = 0; i < allAttachedEvents.length; ++i) { 352 for (var i = 0; i < allAttachedEvents.length; ++i) {
306 var event = allAttachedEvents[i]; 353 var event = allAttachedEvents[i];
307 if (event) 354 if (event)
308 event.detach_(false); 355 event.detach_(false);
309 } 356 }
310 }; 357 };
311 358
312 chromeHidden.dispatchError = function(msg) { 359 chromeHidden.dispatchError = function(msg) {
313 console.error(msg); 360 console.error(msg);
314 }; 361 };
315 362
316 exports.Event = chrome.Event; 363 exports.Event = chrome.Event;
364 exports.storeFunctionSchemes = storeFunctionSchemes
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698