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

Unified Diff: chrome/renderer/resources/extensions/event.js

Issue 9192029: Bindings layer for declarative events API (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix some stuff that apitests in followup CL discovered Created 8 years, 11 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 side-by-side diff with in-line comments
Download patch
Index: chrome/renderer/resources/extensions/event.js
diff --git a/chrome/renderer/resources/extensions/event.js b/chrome/renderer/resources/extensions/event.js
index 45d7080a6c478b2fbc9002e6ccba527ea80c57a2..b1ab1e13ecbdd7fb45d5ce012cabddce2bfcd9e4 100644
--- a/chrome/renderer/resources/extensions/event.js
+++ b/chrome/renderer/resources/extensions/event.js
@@ -58,9 +58,14 @@ var chrome = chrome || {};
// chrome.tabs.onChanged.addListener(function(data) { alert(data); });
// chromeHidden.Event.dispatch("tab-changed", "hi");
// will result in an alert dialog that says 'hi'.
- chrome.Event = function(opt_eventName, opt_argSchemas) {
+ //
+ // If opt_eventOptions exists, it is a dictionary that contains the boolean
+ // entries "supportsListeners" and "supportsRules".
+ chrome.Event = function(opt_eventName, opt_argSchemas, opt_eventOptions) {
not at google - send to devlin 2012/02/01 07:23:12 eventCapabilities might be a better name?
battre 2012/02/01 17:35:39 Even if we continue adding stuff, such in this exa
not at google - send to devlin 2012/02/01 23:07:23 Yep, never mind. They're also defined as "options"
this.eventName_ = opt_eventName;
this.listeners_ = [];
+ this.eventOptions_ = opt_eventOptions ||
+ {"supportsListeners": true, "supportsRules": false};
// Validate event parameters if we are in debug.
if (opt_argSchemas &&
@@ -75,7 +80,12 @@ var chrome = chrome || {};
exception;
}
};
+ } else {
+ this.validate_ = function() {}
}
+
+ this.ruleIds_ = {};
+ this.lastGeneratedRuleId_ = 0;
};
// A map of event names to the event object that is registered to that name.
@@ -84,6 +94,9 @@ var chrome = chrome || {};
// An array of all attached event objects, used for detaching on unload.
var allAttachedEvents = [];
+ // An array of all events that have had rules added the them at any time.
+ var allEventsWithRules = [];
+
// A map of functions that massage event arguments before they are dispatched.
// Key is event name, value is function.
var eventArgumentMassagers = {};
@@ -127,6 +140,8 @@ var chrome = chrome || {};
// Registers a callback to be called when this event is dispatched.
chrome.Event.prototype.addListener = function(cb) {
+ if (!this.eventOptions_.supportsListeners)
+ throw new Error("This event does not support listeners.");
if (this.listeners_.length == 0) {
this.attach_();
}
@@ -135,6 +150,8 @@ var chrome = chrome || {};
// Unregisters a callback.
chrome.Event.prototype.removeListener = function(cb) {
+ if (!this.eventOptions_.supportsListeners)
+ throw new Error("This event does not support listeners.");
var idx = this.findListener_(cb);
if (idx == -1) {
return;
@@ -148,11 +165,15 @@ var chrome = chrome || {};
// Test if the given callback is registered for this event.
chrome.Event.prototype.hasListener = function(cb) {
+ if (!this.eventOptions_.supportsListeners)
+ throw new Error("This event does not support listeners.");
return this.findListener_(cb) > -1;
};
// Test if any callbacks are registered for this event.
- chrome.Event.prototype.hasListeners = function(cb) {
+ chrome.Event.prototype.hasListeners = function() {
+ if (!this.eventOptions_.supportsListeners)
+ throw new Error("This event does not support listeners.");
return this.listeners_.length > 0;
};
@@ -171,6 +192,8 @@ var chrome = chrome || {};
// Dispatches this event object to all listeners, passing all supplied
// arguments to this function each listener.
chrome.Event.prototype.dispatch = function(varargs) {
+ if (!this.eventOptions_.supportsListeners)
+ throw new Error("This event does not support listeners.");
var args = Array.prototype.slice.call(arguments);
if (this.validate_) {
not at google - send to devlin 2012/02/01 07:23:12 now that there's always set a validate_ method, th
var validationErrors = this.validate_(args);
@@ -227,6 +250,105 @@ var chrome = chrome || {};
this.detach_();
};
+ // 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.
+ chrome.Event.prototype.buildArrayOfChoicesSchema_ = function(typesList) {
+ return {
+ "type": "array",
+ "items": {
+ "choices": typesList.forEach(function(el) {return {"$ref": el};})
not at google - send to devlin 2012/02/01 08:15:57 What does this do? I thought forEach has no return
battre 2012/02/01 17:35:39 This should have been "map" instead of "forEach".
+ }
+ };
+ }
+
+ // 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.
+ chrome.Event.prototype.validateRules_ = function(rules, conditions, actions) {
+ if (!conditions || !actions) {
+ throw new Error("Error in API specification.");
+ }
+ var conditionsSchema = this.buildArrayOfChoicesSchema_(conditions);
+ var actionsSchema = this.buildArrayOfChoicesSchema_(actions);
+ rules.forEach(function(rule) {
+ chromeHidden.validate([rule.conditions], [conditionsSchema]);
+ chromeHidden.validate([rule.actions], [actionsSchema]);
+ })
+ }
+
+ chrome.Event.prototype.addMissingIds_ = function(rules) {
not at google - send to devlin 2012/02/01 07:23:12 This, and addMissingPriorities, should be done in
battre 2012/02/01 17:35:39 This does not work: We want to tell the extension
+ for (var i = 0; i < rules.length; ++i) {
+ // TODO(battre): check for "".
+ if (!("id" in rules[i])) {
+ // Generate a unique ID.
+ var newRuleId = "";
+ do {
+ newRuleId = "_" + (this.lastGeneratedRuleId_++) + "_"
+ } while (newRuleId in this.ruleIds_);
+ // And store it.
+ rules[i]["id"] = newRuleId;
+ }
+ this.ruleIds_[rules[i]["id"]] = 1;
+ }
+ }
+
+ chrome.Event.prototype.addMissingPriorities_ = function(rules) {
+ for (var i = 0; i < rules.length; ++i) {
+ if (!("priority" in rules[i]))
+ rules[i]["priority"] = 100;
+ }
+ }
+
+ chrome.Event.prototype.addRules = function(rules, opt_cb) {
not at google - send to devlin 2012/02/01 07:23:12 I think that this should just be a thin wrapper ar
battre 2012/02/01 17:35:39 Isn't it a pretty thin wrapper? Which part would y
not at google - send to devlin 2012/02/01 23:07:23 Yep, it is now. By "thin wrapper" I meant... what
+ if (!this.eventOptions_.supportsRules)
+ throw new Error("This event does not support rules.");
+
+ var found = false;
+ for (var i = 0; i < allEventsWithRules.length; ++i) {
+ if (allEventsWithRules === this) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ allEventsWithRules.push(this);
not at google - send to devlin 2012/02/01 07:23:12 This implies an O(n) iteration over all events eac
battre 2012/02/01 17:35:39 I have removed this logic, see below.
+
+ this.validateRules_(rules,
not at google - send to devlin 2012/02/01 07:23:12 I would have thought that the schema-based validat
not at google - send to devlin 2012/02/01 08:15:57 I may have gotten my wires a little bit crossed wh
battre 2012/02/01 17:35:39 I am not sure how how we will implement these cons
+ this.eventOptions_.conditions,
+ this.eventOptions_.actions);
+ this.addMissingIds_(rules);
+ this.addMissingPriorities_(rules);
+ var callback = opt_cb ? opt_cb.bind(undefined, rules) : undefined;
+
+ return chromeHidden.validatingSendRequest.call(
not at google - send to devlin 2012/02/01 07:23:12 This is interesting. All you really need to do, at
battre 2012/02/01 17:35:39 Wow, this became significantly simpler. Done.
+ this,
+ "experimental.declarative.addRules",
+ [this.eventName_, rules, callback]);
+ }
+
+ chrome.Event.prototype.removeRules = function(ruleIdentifiers, opt_cb) {
+ if (!this.eventOptions_.supportsRules)
+ throw new Error("This event does not support rules.");
+ return chromeHidden.validatingSendRequest.call(
+ this,
+ "experimental.declarative.removeRules",
+ [this.eventName_, ruleIdentifiers, opt_cb]);
+ }
+
+ chrome.Event.prototype.getRules = function(ruleIdentifiers, cb) {
+ if (!this.eventOptions_.supportsRules)
+ throw new Error("This event does not support rules.");
+ return chromeHidden.validatingSendRequest.call(
+ this,
+ "experimental.declarative.getRules",
+ [this.eventName_, ruleIdentifiers, cb]);
+ }
+
// Special load events: we don't use the DOM unload because that slows
// down tab shutdown. On the other hand, onUnload might not always fire,
// since Chrome will terminate renderers on shutdown (SuddenTermination).
@@ -246,6 +368,11 @@ var chrome = chrome || {};
if (event)
event.detach_();
}
+ for (var i = 0; i < allEventsWithRules.length; ++i) {
+ var event = allEventsWithRules[i];
+ if (event && event.eventOptions_.supportsRules)
+ event.removeRules([]);
not at google - send to devlin 2012/02/01 07:23:12 Why [] ? Is this to signify removing all rules? T
battre 2012/02/01 17:35:39 I have removed this logic because a) it did not wo
+ }
};
chromeHidden.dispatchError = function(msg) {

Powered by Google App Engine
This is Rietveld 408576698