summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/resources
diff options
context:
space:
mode:
authormpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-08 18:35:34 +0000
committermpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-08 18:35:34 +0000
commita40caa97fbdae3760f52f95f6b265bd1f39b19ae (patch)
treeb98dceab49c4efb854c9923660735cbf96addbcd /chrome/renderer/resources
parent1b812ea42f713908a9034fcf2a26e8d4a8a86a04 (diff)
downloadchromium_src-a40caa97fbdae3760f52f95f6b265bd1f39b19ae.zip
chromium_src-a40caa97fbdae3760f52f95f6b265bd1f39b19ae.tar.gz
chromium_src-a40caa97fbdae3760f52f95f6b265bd1f39b19ae.tar.bz2
Add aa's Event class to our javascript bindings and use it in our extension
message passing API. Review URL: http://codereview.chromium.org/62069 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13371 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer/resources')
-rw-r--r--chrome/renderer/resources/event_bindings.js120
-rw-r--r--chrome/renderer/resources/renderer_extension_bindings.js113
2 files changed, 162 insertions, 71 deletions
diff --git a/chrome/renderer/resources/event_bindings.js b/chrome/renderer/resources/event_bindings.js
new file mode 100644
index 0000000..de5b3a9
--- /dev/null
+++ b/chrome/renderer/resources/event_bindings.js
@@ -0,0 +1,120 @@
+var chromium = chromium || {};
+(function () {
+ native function AttachEvent(eventName);
+ native function DetachEvent(eventName);
+
+ // Event object. If opt_eventName is provided, this object represents
+ // the unique instance of that named event, and dispatching an event
+ // with that name will route through this object's listeners.
+ //
+ // Example:
+ // chromium.ontabchanged = new Event('tabchanged');
+ // chromium.ontabchanged.addListener(function(data) { alert(data); });
+ // chromium.Event.dispatch_('tabchanged', 'hi');
+ // will result in an alert dialog that says 'hi'.
+ chromium.Event = function(opt_eventName) {
+ this.eventName_ = opt_eventName;
+ this.listeners_ = [];
+ };
+
+ // A map of event names to the event object that is registered to that name.
+ chromium.Event.attached_ = {};
+
+ // Dispatches a named event with the given JSON data, which is deserialized
+ // before dispatch.
+ chromium.Event.dispatchJSON_ = function(name, data) {
+ if (chromium.Event.attached_[name]) {
+ if (data) {
+ data = chromium.json.deserialize_(data);
+ }
+ chromium.Event.attached_[name].dispatch_(data);
+ }
+ };
+
+ // Dispatches a named event with the given object data.
+ chromium.Event.dispatch_ = function(name, data) {
+ if (chromium.Event.attached_[name]) {
+ chromium.Event.attached_[name].dispatch(data);
+ }
+ };
+
+ // Registers a callback to be called when this event is dispatched.
+ chromium.Event.prototype.addListener = function(cb) {
+ this.listeners_.push(cb);
+ if (this.listeners_.length == 1) {
+ this.attach_();
+ }
+ };
+
+ // Unregisters a callback.
+ chromium.Event.prototype.removeListener = function(cb) {
+ var idx = this.findListener_(cb);
+ if (idx == -1) {
+ return;
+ }
+
+ this.listeners_.splice(idx, 1);
+ if (this.listeners_.length == 0) {
+ this.detach_();
+ }
+ };
+
+ // Test if the given callback is registered for this event.
+ chromium.Event.prototype.hasListener = function(cb) {
+ return this.findListeners_(cb) > -1;
+ };
+
+ // Returns the index of the given callback if registered, or -1 if not
+ // found.
+ chromium.Event.prototype.findListener_ = function(cb) {
+ for (var i = 0; i < this.listeners_.length; i++) {
+ if (this.listeners_[i] == cb) {
+ return i;
+ }
+ }
+
+ return -1;
+ };
+
+ // Dispatches this event object to all listeners, passing all supplied
+ // arguments to this function each listener.
+ chromium.Event.prototype.dispatch = function(varargs) {
+ var args = Array.prototype.slice.call(arguments);
+ for (var i = 0; i < this.listeners_.length; i++) {
+ try {
+ this.listeners_[i].apply(null, args);
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ };
+
+ // Attaches this event object to its name. Only one object can have a given
+ // name.
+ chromium.Event.prototype.attach_ = function() {
+ AttachEvent(this.eventName_);
+ if (!this.eventName_)
+ return;
+
+ if (chromium.Event.attached_[this.eventName_]) {
+ throw new Error("chromium.Event '" + this.eventName_ +
+ "' is already attached.");
+ }
+
+ chromium.Event.attached_[this.eventName_] = this;
+ };
+
+ // Detaches this event object from its name.
+ chromium.Event.prototype.detach_ = function() {
+ DetachEvent(this.eventName_);
+ if (!this.eventName_)
+ return;
+
+ if (!chromium.Event.attached_[this.eventName_]) {
+ throw new Error("chromium.Event '" + this.eventName_ +
+ "' is not attached.");
+ }
+
+ delete chromium.Event.attached_[this.eventName_];
+ };
+})();
diff --git a/chrome/renderer/resources/renderer_extension_bindings.js b/chrome/renderer/resources/renderer_extension_bindings.js
index 401f82c..deb5c40 100644
--- a/chrome/renderer/resources/renderer_extension_bindings.js
+++ b/chrome/renderer/resources/renderer_extension_bindings.js
@@ -2,92 +2,63 @@ var chromium = chromium || {};
(function () {
native function OpenChannelToExtension(id);
native function PostMessage(portId, msg);
- native function RegisterScriptAPI(private);
- // chromium: Public API.
- // Represents info we know about a chrome extension.
- chromium.Extension = function(id) {
- this.id_ = id;
- };
-
- // Opens a channel to the extension for message passing.
- chromium.Extension.prototype.openChannel = function() {
- portId = OpenChannelToExtension(this.id_);
- if (portId == -1)
- throw new Error('No such extension \"' + this.id_ + '\"');
- return new Port(portId);
+ // Port object. Represents a connection to another script context through
+ // which messages can be passed.
+ chromium.Port = function(portId) {
+ if (chromium.Port.ports_[portId]) {
+ throw new Error("Port '" + portId + "' already exists.");
+ }
+ this.portId_ = portId; // TODO(mpcomplete): readonly
+ this.onmessage = new chromium.Event();
+ chromium.Port.ports_[portId] = this;
+ // Note: this object will never get GCed. If we ever care, we could
+ // add an "ondetach" method to the onmessage Event that gets called
+ // when there are no more listeners.
};
- // Adds a listener that fires when a renderer opens a channel to talk
- // to us.
- chromium.addConnectListener = function(callback) {
- chromium.addEventListener('channel-connect',
- function (e) { callback(e.data.port); });
- };
+ // Map of port IDs to port object.
+ chromium.Port.ports_ = {};
- // Adds a generic event listener.
- chromium.addEventListener = function(type, callback) {
- var listeners = getPrivateData().eventListeners;
- if (!listeners[type])
- listeners[type] = [];
- listeners[type].push(callback);
+ // Called by native code when a channel has been opened to this context.
+ chromium.Port.dispatchOnConnect_ = function(portId) {
+ var port = new chromium.Port(portId);
+ chromium.Event.dispatch_("channel-connect", port);
};
- // Dispatches the given event to anyone listening for that event.
- chromium.dispatchEvent = function(type, data) {
- var event = {type: type, data: data};
- var listeners = getPrivateData().eventListeners;
- for (var i in listeners[type]) {
- listeners[type][i](event);
+ // Called by native code when a message has been sent to the given port.
+ chromium.Port.dispatchOnMessage_ = function(msg, portId) {
+ var port = chromium.Port.ports_[portId];
+ if (port) {
+ port.onmessage.dispatch(msg, port);
}
};
- // Private API.
-
- // Always access privateData through this function, to ensure that we
- // have registered our native API. We do this lazily to avoid registering
- // on pages that don't use these bindings.
- function getPrivateData() {
- if (!scriptAPI.registered_) {
- RegisterScriptAPI(scriptAPI);
- scriptAPI.registered_ = true;
- }
- return privateData;
- }
- var privateData = {
- eventListeners: {},
- ports: {}
+ // Sends a message asynchronously to the context on the other end of this
+ // port.
+ chromium.Port.prototype.postMessage = function(msg) {
+ PostMessage(this.portId_, msg);
};
- // Represents a port through which we can send messages to another process.
- var Port = function(portId) {
- // TODO(mpcomplete): we probably want to hide this portId_ so
- // it can't be guessed at. One idea is to expose v8's SetHiddenValue
- // to our extension.
- this.portId_ = portId;
- getPrivateData().ports[portId] = this;
+ // Extension object.
+ chromium.Extension = function(id) {
+ this.id_ = id;
};
- // Sends a message to the other side of the channel.
- Port.prototype.postMessage = function(msg) {
- PostMessage(this.portId_, msg);
+ // Opens a message channel to the extension. Returns a Port for
+ // message passing.
+ chromium.Extension.prototype.connect = function() {
+ var portId = OpenChannelToExtension(this.id_);
+ if (portId == -1)
+ throw new Error("No such extension: '" + this.id_ + "'");
+ return new chromium.Port(portId);
};
- // Script API: javascript APIs exposed to C++ only.
- // This object allows our native code to call back to us through a
- // private interface that isn't exposed to web content.
- var scriptAPI = {};
-
- // Called by native code when a channel has been opened to this process.
- scriptAPI.dispatchOnConnect = function(portId) {
- chromium.dispatchEvent('channel-connect', {port: new Port(portId)});
+ // Returns a resource URL that can be used to fetch a resource from this
+ // extension.
+ chromium.Extension.prototype.getURL = function(path) {
+ return "chrome-extension://" + this.id_ + "/" + path;
};
- // Called by native code when a message has been sent over the given
- // channel.
- scriptAPI.dispatchOnMessage = function(msg, portId) {
- var port = getPrivateData().ports[portId];
- if (port && port.onMessage)
- port.onMessage(msg, port);
- };
+ chromium.onconnect = new chromium.Event("channel-connect");
})();