OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 /** | |
6 * A set of utilities for use with the Chrome Extension APIs. | |
7 * | |
8 * Allows for easy access to required JS objects. | |
9 */ | |
10 part of chrome; | |
11 | |
12 /** | |
13 * A dart object, that is convertible to JS. Used for creating objects in dart, | |
14 * then passing them to JS. | |
15 * | |
16 * Objects that are passable to JS need to implement this interface. | |
17 */ | |
18 abstract class ChromeObject { | |
19 /* | |
20 * Default Constructor | |
21 * | |
22 * Called by child objects during their regular construction. | |
23 */ | |
24 ChromeObject() : _jsObject = JS('var', '{}'); | |
25 | |
26 /* | |
27 * Internal proxy constructor | |
28 * | |
29 * Creates a new Dart object using this existing proxy. | |
30 */ | |
31 ChromeObject._proxy(this._jsObject); | |
32 | |
33 /* | |
34 * JS Object Representation | |
35 */ | |
36 final Object _jsObject; | |
37 } | |
38 | |
39 /** | |
40 * Useful functions for converting arguments. | |
41 */ | |
42 | |
43 /** | |
44 * Converts the given map-type argument to js-friendly format, recursively. | |
45 * Returns the new Map object. | |
46 */ | |
47 Object _convertMapArgument(Map argument) { | |
48 Map m = new Map(); | |
49 for (Object key in argument.keys) | |
50 m[key] = convertArgument(argument[key]); | |
51 return convertDartToNative_Dictionary(m); | |
52 } | |
53 | |
54 /** | |
55 * Converts the given list-type argument to js-friendly format, recursively. | |
56 * Returns the new List object. | |
57 */ | |
58 List _convertListArgument(List argument) { | |
59 List l = new List(); | |
60 for (var i = 0; i < argument.length; i ++) | |
61 l.add(convertArgument(argument[i])); | |
62 return l; | |
63 } | |
64 | |
65 /** | |
66 * Converts the given argument Object to js-friendly format, recursively. | |
67 * | |
68 * Flattens out all Chrome objects into their corresponding ._toMap() | |
69 * definitions, then converts them to JS objects. | |
70 * | |
71 * Returns the new argument. | |
72 * | |
73 * Cannot be used for functions. | |
74 */ | |
75 Object convertArgument(var argument) { | |
76 if (argument == null) | |
77 return argument; | |
78 | |
79 if (argument is num || argument is String || argument is bool) | |
80 return argument; | |
81 | |
82 if (argument is ChromeObject) | |
83 return argument._jsObject; | |
84 | |
85 if (argument is List) | |
86 return _convertListArgument(argument); | |
87 | |
88 if (argument is Map) | |
89 return _convertMapArgument(argument); | |
90 | |
91 if (argument is Function) | |
92 throw new Exception("Cannot serialize Function argument ${argument}."); | |
93 | |
94 // TODO(sashab): Try and detect whether the argument is already serialized. | |
95 return argument; | |
96 } | |
97 | |
98 /// Description of a declarative rule for handling events. | |
99 class Rule extends ChromeObject { | |
100 /* | |
101 * Public (Dart) constructor | |
102 */ | |
103 Rule({String id, List conditions, List actions, int priority}) { | |
104 this.id = id; | |
105 this.conditions = conditions; | |
106 this.actions = actions; | |
107 this.priority = priority; | |
108 } | |
109 | |
110 /* | |
111 * Private (JS) constructor | |
112 */ | |
113 Rule._proxy(_jsObject) : super._proxy(_jsObject); | |
114 | |
115 /* | |
116 * Public accessors | |
117 */ | |
118 String get id => JS('String', '#.id', this._jsObject); | |
119 | |
120 void set id(String id) { | |
121 JS('void', '#.id = #', this._jsObject, id); | |
122 } | |
123 | |
124 // TODO(sashab): Wrap these generic Lists somehow. | |
125 List get conditions => JS('List', '#.conditions', this._jsObject); | |
126 | |
127 void set conditions(List conditions) { | |
128 JS('void', '#.conditions = #', this._jsObject, convertArgument(conditions)); | |
129 } | |
130 | |
131 // TODO(sashab): Wrap these generic Lists somehow. | |
132 List get actions => JS('List', '#.actions', this._jsObject); | |
133 | |
134 void set actions(List actions) { | |
135 JS('void', '#.actions = #', this._jsObject, convertArgument(actions)); | |
136 } | |
137 | |
138 int get priority => JS('int', '#.priority', this._jsObject); | |
139 | |
140 void set priority(int priority) { | |
141 JS('void', '#.priority = #', this._jsObject, priority); | |
142 } | |
143 | |
144 } | |
145 | |
146 /** | |
147 * The Event class. | |
148 * | |
149 * Chrome Event classes extend this interface. | |
150 * | |
151 * e.g. | |
152 * | |
153 * // chrome.app.runtime.onLaunched | |
154 * class Event_ChromeAppRuntimeOnLaunched extends Event { | |
155 * // constructor, passing the arity of the callback | |
156 * Event_ChromeAppRuntimeOnLaunched(jsObject) : | |
157 * super._(jsObject, 1); | |
158 * | |
159 * // methods, strengthening the Function parameter specificity | |
160 * void addListener(void callback(LaunchData launchData)) | |
161 * => super.addListener(callback); | |
162 * void removeListener(void callback(LaunchData launchData)) | |
163 * => super.removeListener(callback); | |
164 * bool hasListener(void callback(LaunchData launchData)) | |
165 * => super.hasListener(callback); | |
166 * } | |
167 * | |
168 */ | |
169 class Event { | |
170 /* | |
171 * JS Object Representation | |
172 */ | |
173 final Object _jsObject; | |
174 | |
175 /* | |
176 * Number of arguments the callback takes. | |
177 */ | |
178 final int _callbackArity; | |
179 | |
180 /* | |
181 * Private constructor | |
182 */ | |
183 Event._(this._jsObject, this._callbackArity); | |
184 | |
185 /* | |
186 * Methods | |
187 */ | |
188 | |
189 /// Registers an event listener <em>callback</em> to an event. | |
190 void addListener(Function callback) => | |
191 JS('void', | |
192 '#.addListener(#)', | |
193 this._jsObject, | |
194 convertDartClosureToJS(callback, this._callbackArity) | |
195 ); | |
196 | |
197 /// Deregisters an event listener <em>callback</em> from an event. | |
198 void removeListener(Function callback) => | |
199 JS('void', | |
200 '#.removeListener(#)', | |
201 this._jsObject, | |
202 convertDartClosureToJS(callback, this._callbackArity) | |
203 ); | |
204 | |
205 /// Returns True if <em>callback</em> is registered to the event. | |
206 bool hasListener(Function callback) => | |
207 JS('bool', | |
208 '#.hasListener(#)', | |
209 this._jsObject, | |
210 convertDartClosureToJS(callback, this._callbackArity) | |
211 ); | |
212 | |
213 /// Returns true if any event listeners are registered to the event. | |
214 bool hasListeners() => | |
215 JS('bool', | |
216 '#.hasListeners()', | |
217 this._jsObject | |
218 ); | |
219 | |
220 /// Registers rules to handle events. | |
221 /// | |
222 /// [eventName] is the name of the event this function affects and [rules] are | |
223 /// the rules to be registered. These do not replace previously registered | |
224 /// rules. [callback] is called with registered rules. | |
225 /// | |
226 void addRules(String eventName, List<Rule> rules, | |
227 [void callback(List<Rule> rules)]) { | |
228 // proxy the callback | |
229 void __proxy_callback(List rules) { | |
230 if (callback != null) { | |
231 List<Rule> __proxy_rules = new List<Rule>(); | |
232 | |
233 for (Object o in rules) | |
234 __proxy_rules.add(new Rule._proxy(o)); | |
235 | |
236 callback(__proxy_rules); | |
237 } | |
238 } | |
239 | |
240 JS('void', | |
241 '#.addRules(#, #, #)', | |
242 this._jsObject, | |
243 convertArgument(eventName), | |
244 convertArgument(rules), | |
245 convertDartClosureToJS(__proxy_callback, 1) | |
246 ); | |
247 } | |
248 | |
249 /// Returns currently registered rules. | |
250 /// | |
251 /// [eventName] is the name of the event this function affects and, if an arra
y | |
252 /// is passed as [ruleIdentifiers], only rules with identifiers contained in | |
253 /// this array are returned. [callback] is called with registered rules. | |
254 /// | |
255 void getRules(String eventName, [List<String> ruleIdentifiers, | |
256 void callback(List<Rule> rules)]) { | |
257 // proxy the callback | |
258 void __proxy_callback(List rules) { | |
259 if (callback != null) { | |
260 List<Rule> __proxy_rules = new List<Rule>(); | |
261 | |
262 for (Object o in rules) | |
263 __proxy_rules.add(new Rule._proxy(o)); | |
264 | |
265 callback(__proxy_rules); | |
266 } | |
267 } | |
268 | |
269 JS('void', | |
270 '#.getRules(#, #, #)', | |
271 this._jsObject, | |
272 convertArgument(eventName), | |
273 convertArgument(ruleIdentifiers), | |
274 convertDartClosureToJS(__proxy_callback, 1) | |
275 ); | |
276 } | |
277 | |
278 /// Unregisters currently registered rules. | |
279 /// | |
280 /// [eventName] is the name of the event this function affects and, if an arra
y | |
281 /// is passed as [ruleIdentifiers], only rules with identifiers contained in | |
282 /// this array are unregistered. [callback] is called when the rules are | |
283 /// unregistered. | |
284 /// | |
285 void removeRules(String eventName, [List<String> ruleIdentifiers, | |
286 void callback()]) => | |
287 JS('void', | |
288 '#.removeRules(#, #, #)', | |
289 this._jsObject, | |
290 convertArgument(eventName), | |
291 convertArgument(ruleIdentifiers), | |
292 convertDartClosureToJS(callback, 0) | |
293 ); | |
294 } | |
295 | |
OLD | NEW |