| Index: chrome/renderer/resources/extensions/event.js
|
| diff --git a/chrome/renderer/resources/extensions/event.js b/chrome/renderer/resources/extensions/event.js
|
| index 81c465b0d83d5150c4402719784de7eb72825fda..8961ce56fc112758d971b496ccaa842b070af33b 100644
|
| --- a/chrome/renderer/resources/extensions/event.js
|
| +++ b/chrome/renderer/resources/extensions/event.js
|
| @@ -5,8 +5,36 @@
|
| var eventBindingsNatives = requireNative('event_bindings');
|
| var AttachEvent = eventBindingsNatives.AttachEvent;
|
| var DetachEvent = eventBindingsNatives.DetachEvent;
|
| + var sendRequest = require('sendRequest').sendRequest;
|
| + var utils = require('utils');
|
|
|
| var chromeHidden = requireNative('chrome_hidden').GetChromeHidden();
|
| + var GetExtensionAPIDefinition =
|
| + requireNative('apiDefinitions').GetExtensionAPIDefinition;
|
| +
|
| + // Schemas for the rule-style functions on the events API that
|
| + // only need to be generated occasionally, so populate them lazily.
|
| + var ruleFunctionSchemas = {
|
| + // These values are set lazily:
|
| + // addRules: {},
|
| + // getRules: {},
|
| + // removeRules: {}
|
| + };
|
| +
|
| + // This function ensures that |ruleFunctionSchemas| is populated.
|
| + function ensureRuleSchemasLoaded() {
|
| + if (ruleFunctionSchemas.addRules)
|
| + return;
|
| + var eventsSchema = GetExtensionAPIDefinition("events")[0];
|
| + var eventType = utils.lookup(eventsSchema.types, 'id', 'events.Event');
|
| +
|
| + ruleFunctionSchemas.addRules =
|
| + utils.lookup(eventType.functions, 'name', 'addRules');
|
| + ruleFunctionSchemas.getRules =
|
| + utils.lookup(eventType.functions, 'name', 'getRules');
|
| + ruleFunctionSchemas.removeRules =
|
| + utils.lookup(eventType.functions, 'name', 'removeRules');
|
| + }
|
|
|
| // Local implementation of JSON.parse & JSON.stringify that protect us
|
| // from being clobbered by an extension.
|
| @@ -68,12 +96,13 @@
|
| if (this.eventOptions_.supportsRules && !opt_eventName)
|
| throw new Error("Events that support rules require an event name.");
|
|
|
| - // Validate event parameters if we are in debug.
|
| + // Validate event arguments (the data that is passed to the callbacks)
|
| + // if we are in debug.
|
| if (opt_argSchemas &&
|
| chromeHidden.validateCallbacks &&
|
| chromeHidden.validate) {
|
|
|
| - this.validate_ = function(args) {
|
| + this.validateEventArgs_ = function(args) {
|
| try {
|
| chromeHidden.validate(args, opt_argSchemas);
|
| } catch (exception) {
|
| @@ -82,7 +111,7 @@
|
| }
|
| };
|
| } else {
|
| - this.validate_ = function() {}
|
| + this.validateEventArgs_ = function() {}
|
| }
|
| };
|
|
|
| @@ -192,7 +221,7 @@
|
| if (!this.eventOptions_.supportsListeners)
|
| throw new Error("This event does not support listeners.");
|
| var args = Array.prototype.slice.call(arguments);
|
| - var validationErrors = this.validate_(args);
|
| + var validationErrors = this.validateEventArgs_(args);
|
| if (validationErrors) {
|
| return {validationErrors: validationErrors};
|
| }
|
| @@ -246,49 +275,72 @@
|
|
|
| chrome.Event.prototype.destroy_ = function() {
|
| this.listeners_ = [];
|
| - this.validate_ = [];
|
| + this.validateEventArgs_ = [];
|
| this.detach_(false);
|
| };
|
|
|
| - // Gets the declarative API object, or undefined if this extension doesn't
|
| - // have access to it.
|
| - //
|
| - // This is defined as a function (rather than a variable) because it isn't
|
| - // accessible until the schema bindings have been generated.
|
| - function getDeclarativeAPI() {
|
| - return chromeHidden.internalAPIs.declarative;
|
| - }
|
| -
|
| chrome.Event.prototype.addRules = function(rules, opt_cb) {
|
| if (!this.eventOptions_.supportsRules)
|
| throw new Error("This event does not support rules.");
|
| - if (!getDeclarativeAPI()) {
|
| - throw new Error("You must have permission to use the declarative " +
|
| - "API to support rules in events");
|
| +
|
| + // Takes a list of JSON datatype identifiers and returns a schema fragment
|
| + // that verifies that a JSON object corresponds to an array of only these
|
| + // data types.
|
| + function buildArrayOfChoicesSchema(typesList) {
|
| + return {
|
| + 'type': 'array',
|
| + 'items': {
|
| + 'choices': typesList.map(function(el) {return {'$ref': el};})
|
| + }
|
| + };
|
| + };
|
| +
|
| + // Validate conditions and actions against specific schemas of this
|
| + // event object type.
|
| + // |rules| is an array of JSON objects that follow the Rule type of the
|
| + // declarative extension APIs. |conditions| is an array of JSON type
|
| + // identifiers that are allowed to occur in the conditions attribute of each
|
| + // rule. Likewise, |actions| is an array of JSON type identifiers that are
|
| + // allowed to occur in the actions attribute of each rule.
|
| + function validateRules(rules, conditions, actions) {
|
| + var conditionsSchema = buildArrayOfChoicesSchema(conditions);
|
| + var actionsSchema = buildArrayOfChoicesSchema(actions);
|
| + rules.forEach(function(rule) {
|
| + chromeHidden.validate([rule.conditions], [conditionsSchema]);
|
| + chromeHidden.validate([rule.actions], [actionsSchema]);
|
| + })
|
| + };
|
| +
|
| + if (!this.eventOptions_.conditions || !this.eventOptions_.actions) {
|
| + throw new Error('Event ' + this.eventName_ + ' misses conditions or ' +
|
| + 'actions in the API specification.');
|
| }
|
| - getDeclarativeAPI().addRules(this.eventName_, rules, opt_cb);
|
| +
|
| + validateRules(rules,
|
| + this.eventOptions_.conditions,
|
| + this.eventOptions_.actions);
|
| +
|
| + ensureRuleSchemasLoaded();
|
| + sendRequest("events.addRules", [this.eventName_, rules, opt_cb],
|
| + ruleFunctionSchemas.addRules.parameters);
|
| }
|
|
|
| chrome.Event.prototype.removeRules = function(ruleIdentifiers, opt_cb) {
|
| if (!this.eventOptions_.supportsRules)
|
| throw new Error("This event does not support rules.");
|
| - if (!getDeclarativeAPI()) {
|
| - throw new Error("You must have permission to use the declarative " +
|
| - "API to support rules in events");
|
| - }
|
| - getDeclarativeAPI().removeRules(
|
| - this.eventName_, ruleIdentifiers, opt_cb);
|
| + ensureRuleSchemasLoaded();
|
| + sendRequest("events.removeRules",
|
| + [this.eventName_, ruleIdentifiers, opt_cb],
|
| + ruleFunctionSchemas.removeRules.parameters);
|
| }
|
|
|
| chrome.Event.prototype.getRules = function(ruleIdentifiers, cb) {
|
| if (!this.eventOptions_.supportsRules)
|
| throw new Error("This event does not support rules.");
|
| - if (!getDeclarativeAPI()) {
|
| - throw new Error("You must have permission to use the declarative " +
|
| - "API to support rules in events");
|
| - }
|
| - getDeclarativeAPI().getRules(
|
| - this.eventName_, ruleIdentifiers, cb);
|
| + ensureRuleSchemasLoaded();
|
| + sendRequest("events.getRules",
|
| + [this.eventName_, ruleIdentifiers, cb],
|
| + ruleFunctionSchemas.getRules.parameters);
|
| }
|
|
|
| // Special load events: we don't use the DOM unload because that slows
|
|
|