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

Side by Side 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: Check whether eventName may be optional Created 8 years, 10 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 chrome = chrome || {}; 5 var chrome = chrome || {};
6 (function () { 6 (function () {
7 native function GetChromeHidden(); 7 native function GetChromeHidden();
8 native function AttachEvent(eventName); 8 native function AttachEvent(eventName);
9 native function DetachEvent(eventName); 9 native function DetachEvent(eventName);
10 native function Print(); 10 native function Print();
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 } 44 }
45 }; 45 };
46 46
47 this.parse = function(thing) { 47 this.parse = function(thing) {
48 return $jsonParse(thing); 48 return $jsonParse(thing);
49 }; 49 };
50 })(); 50 })();
51 51
52 // Event object. If opt_eventName is provided, this object represents 52 // Event object. If opt_eventName is provided, this object represents
53 // the unique instance of that named event, and dispatching an event 53 // the unique instance of that named event, and dispatching an event
54 // with that name will route through this object's listeners. 54 // with that name will route through this object's listeners. Note that
55 // opt_eventName is required for events that support rules.
55 // 56 //
56 // Example: 57 // Example:
57 // chrome.tabs.onChanged = new chrome.Event("tab-changed"); 58 // chrome.tabs.onChanged = new chrome.Event("tab-changed");
58 // chrome.tabs.onChanged.addListener(function(data) { alert(data); }); 59 // chrome.tabs.onChanged.addListener(function(data) { alert(data); });
59 // chromeHidden.Event.dispatch("tab-changed", "hi"); 60 // chromeHidden.Event.dispatch("tab-changed", "hi");
60 // will result in an alert dialog that says 'hi'. 61 // will result in an alert dialog that says 'hi'.
61 chrome.Event = function(opt_eventName, opt_argSchemas) { 62 //
63 // If opt_eventOptions exists, it is a dictionary that contains the boolean
64 // entries "supportsListeners" and "supportsRules".
65 chrome.Event = function(opt_eventName, opt_argSchemas, opt_eventOptions) {
62 this.eventName_ = opt_eventName; 66 this.eventName_ = opt_eventName;
63 this.listeners_ = []; 67 this.listeners_ = [];
68 this.eventOptions_ = opt_eventOptions ||
69 {"supportsListeners": true, "supportsRules": false};
70
71 if (this.eventOptions_.supportsRules && !opt_eventName)
72 throw new Error("Events that support rules require an event name.");
64 73
65 // Validate event parameters if we are in debug. 74 // Validate event parameters if we are in debug.
66 if (opt_argSchemas && 75 if (opt_argSchemas &&
67 chromeHidden.validateCallbacks && 76 chromeHidden.validateCallbacks &&
68 chromeHidden.validate) { 77 chromeHidden.validate) {
69 78
70 this.validate_ = function(args) { 79 this.validate_ = function(args) {
71 try { 80 try {
72 chromeHidden.validate(args, opt_argSchemas); 81 chromeHidden.validate(args, opt_argSchemas);
73 } catch (exception) { 82 } catch (exception) {
74 return "Event validation error during " + opt_eventName + " -- " + 83 return "Event validation error during " + opt_eventName + " -- " +
75 exception; 84 exception;
76 } 85 }
77 }; 86 };
87 } else {
88 this.validate_ = function() {}
78 } 89 }
79 }; 90 };
80 91
81 // A map of event names to the event object that is registered to that name. 92 // A map of event names to the event object that is registered to that name.
82 var attachedNamedEvents = {}; 93 var attachedNamedEvents = {};
83 94
84 // An array of all attached event objects, used for detaching on unload. 95 // An array of all attached event objects, used for detaching on unload.
85 var allAttachedEvents = []; 96 var allAttachedEvents = [];
86 97
87 // A map of functions that massage event arguments before they are dispatched. 98 // A map of functions that massage event arguments before they are dispatched.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 }; 131 };
121 132
122 // Test if a named event has any listeners. 133 // Test if a named event has any listeners.
123 chromeHidden.Event.hasListener = function(name) { 134 chromeHidden.Event.hasListener = function(name) {
124 return (attachedNamedEvents[name] && 135 return (attachedNamedEvents[name] &&
125 attachedNamedEvents[name].listeners_.length > 0); 136 attachedNamedEvents[name].listeners_.length > 0);
126 }; 137 };
127 138
128 // Registers a callback to be called when this event is dispatched. 139 // Registers a callback to be called when this event is dispatched.
129 chrome.Event.prototype.addListener = function(cb) { 140 chrome.Event.prototype.addListener = function(cb) {
141 if (!this.eventOptions_.supportsListeners)
142 throw new Error("This event does not support listeners.");
130 if (this.listeners_.length == 0) { 143 if (this.listeners_.length == 0) {
131 this.attach_(); 144 this.attach_();
132 } 145 }
133 this.listeners_.push(cb); 146 this.listeners_.push(cb);
134 }; 147 };
135 148
136 // Unregisters a callback. 149 // Unregisters a callback.
137 chrome.Event.prototype.removeListener = function(cb) { 150 chrome.Event.prototype.removeListener = function(cb) {
151 if (!this.eventOptions_.supportsListeners)
152 throw new Error("This event does not support listeners.");
138 var idx = this.findListener_(cb); 153 var idx = this.findListener_(cb);
139 if (idx == -1) { 154 if (idx == -1) {
140 return; 155 return;
141 } 156 }
142 157
143 this.listeners_.splice(idx, 1); 158 this.listeners_.splice(idx, 1);
144 if (this.listeners_.length == 0) { 159 if (this.listeners_.length == 0) {
145 this.detach_(); 160 this.detach_();
146 } 161 }
147 }; 162 };
148 163
149 // Test if the given callback is registered for this event. 164 // Test if the given callback is registered for this event.
150 chrome.Event.prototype.hasListener = function(cb) { 165 chrome.Event.prototype.hasListener = function(cb) {
166 if (!this.eventOptions_.supportsListeners)
167 throw new Error("This event does not support listeners.");
151 return this.findListener_(cb) > -1; 168 return this.findListener_(cb) > -1;
152 }; 169 };
153 170
154 // Test if any callbacks are registered for this event. 171 // Test if any callbacks are registered for this event.
155 chrome.Event.prototype.hasListeners = function(cb) { 172 chrome.Event.prototype.hasListeners = function() {
173 if (!this.eventOptions_.supportsListeners)
174 throw new Error("This event does not support listeners.");
156 return this.listeners_.length > 0; 175 return this.listeners_.length > 0;
157 }; 176 };
158 177
159 // Returns the index of the given callback if registered, or -1 if not 178 // Returns the index of the given callback if registered, or -1 if not
160 // found. 179 // found.
161 chrome.Event.prototype.findListener_ = function(cb) { 180 chrome.Event.prototype.findListener_ = function(cb) {
162 for (var i = 0; i < this.listeners_.length; i++) { 181 for (var i = 0; i < this.listeners_.length; i++) {
163 if (this.listeners_[i] == cb) { 182 if (this.listeners_[i] == cb) {
164 return i; 183 return i;
165 } 184 }
166 } 185 }
167 186
168 return -1; 187 return -1;
169 }; 188 };
170 189
171 // Dispatches this event object to all listeners, passing all supplied 190 // Dispatches this event object to all listeners, passing all supplied
172 // arguments to this function each listener. 191 // arguments to this function each listener.
173 chrome.Event.prototype.dispatch = function(varargs) { 192 chrome.Event.prototype.dispatch = function(varargs) {
193 if (!this.eventOptions_.supportsListeners)
194 throw new Error("This event does not support listeners.");
174 var args = Array.prototype.slice.call(arguments); 195 var args = Array.prototype.slice.call(arguments);
175 if (this.validate_) { 196 var validationErrors = this.validate_(args);
176 var validationErrors = this.validate_(args); 197 if (validationErrors) {
177 if (validationErrors) { 198 return validationErrors;
178 return validationErrors;
179 }
180 } 199 }
181 for (var i = 0; i < this.listeners_.length; i++) { 200 for (var i = 0; i < this.listeners_.length; i++) {
182 try { 201 try {
183 this.listeners_[i].apply(null, args); 202 this.listeners_[i].apply(null, args);
184 } catch (e) { 203 } catch (e) {
185 console.error("Error in event handler for '" + this.eventName_ + 204 console.error("Error in event handler for '" + this.eventName_ +
186 "': " + e.stack); 205 "': " + e.stack);
187 } 206 }
188 } 207 }
189 }; 208 };
(...skipping 30 matching lines...) Expand all
220 239
221 delete attachedNamedEvents[this.eventName_]; 240 delete attachedNamedEvents[this.eventName_];
222 }; 241 };
223 242
224 chrome.Event.prototype.destroy_ = function() { 243 chrome.Event.prototype.destroy_ = function() {
225 this.listeners_ = []; 244 this.listeners_ = [];
226 this.validate_ = []; 245 this.validate_ = [];
227 this.detach_(); 246 this.detach_();
228 }; 247 };
229 248
249 chrome.Event.prototype.addRules = function(rules, opt_cb) {
250 if (!this.eventOptions_.supportsRules)
251 throw new Error("This event does not support rules.");
252 if (!chrome.experimental || !chrome.experimental.declarative) {
253 throw new Error("You must have access to the experimental.declarative " +
254 "API to support rules in events");
255 }
256 chrome.experimental.declarative.addRules(this.eventName_, rules, opt_cb);
257 }
258
259 chrome.Event.prototype.removeRules = function(ruleIdentifiers, opt_cb) {
260 if (!this.eventOptions_.supportsRules)
261 throw new Error("This event does not support rules.");
262 if (!chrome.experimental || !chrome.experimental.declarative) {
263 throw new Error("You must have access to the experimental.declarative " +
264 "API to support rules in events");
265 }
266 chrome.experimental.declarative.removeRules(
267 this.eventName_, ruleIdentifiers, opt_cb);
268 }
269
270 chrome.Event.prototype.getRules = function(ruleIdentifiers, cb) {
271 if (!this.eventOptions_.supportsRules)
272 throw new Error("This event does not support rules.");
273 if (!chrome.experimental || !chrome.experimental.declarative) {
274 throw new Error("You must have access to the experimental.declarative " +
275 "API to support rules in events");
276 }
277 chrome.experimental.declarative.getRules(
278 this.eventName_, ruleIdentifiers, cb);
279 }
280
230 // Special load events: we don't use the DOM unload because that slows 281 // Special load events: we don't use the DOM unload because that slows
231 // down tab shutdown. On the other hand, onUnload might not always fire, 282 // down tab shutdown. On the other hand, onUnload might not always fire,
232 // since Chrome will terminate renderers on shutdown (SuddenTermination). 283 // since Chrome will terminate renderers on shutdown (SuddenTermination).
233 chromeHidden.onLoad = new chrome.Event(); 284 chromeHidden.onLoad = new chrome.Event();
234 chromeHidden.onUnload = new chrome.Event(); 285 chromeHidden.onUnload = new chrome.Event();
235 286
236 chromeHidden.dispatchOnLoad = 287 chromeHidden.dispatchOnLoad =
237 chromeHidden.onLoad.dispatch.bind(chromeHidden.onLoad); 288 chromeHidden.onLoad.dispatch.bind(chromeHidden.onLoad);
238 289
239 chromeHidden.dispatchOnUnload = function() { 290 chromeHidden.dispatchOnUnload = function() {
240 chromeHidden.onUnload.dispatch(); 291 chromeHidden.onUnload.dispatch();
241 for (var i = 0; i < allAttachedEvents.length; ++i) { 292 for (var i = 0; i < allAttachedEvents.length; ++i) {
242 var event = allAttachedEvents[i]; 293 var event = allAttachedEvents[i];
243 if (event) 294 if (event)
244 event.detach_(); 295 event.detach_();
245 } 296 }
246 }; 297 };
247 298
248 chromeHidden.dispatchError = function(msg) { 299 chromeHidden.dispatchError = function(msg) {
249 console.error(msg); 300 console.error(msg);
250 }; 301 };
251 })(); 302 })();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698