Chromium Code Reviews| Index: tools/dom/src/chrome/_utils.dart |
| diff --git a/tools/dom/src/chrome/_utils.dart b/tools/dom/src/chrome/_utils.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..b28f31a4dcfe076d1b303437a0f59f2bfb700c87 |
| --- /dev/null |
| +++ b/tools/dom/src/chrome/_utils.dart |
| @@ -0,0 +1,392 @@ |
| +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
|
blois
2013/01/23 02:06:12
2013
sashab
2013/01/23 04:45:34
Done.
|
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
|
blois
2013/01/23 02:06:12
Normally we don't use leading _ for file names (at
sashab
2013/01/23 04:45:34
No worries; I can fix this.
|
| + |
| +/** |
| + * A set of utilities for use with the Chrome Extension APIs. |
| + * |
| + * Allows for easy access to required JS objects. |
| + */ |
| +part of chrome; |
| + |
| +/** |
| + * A dart object, that is convertible to JS. Used for creating objects in dart, |
| + * then passing them to JS. |
| + * |
| + * Objects that are passable to JS need to implement this interface. |
| + */ |
| +abstract class ChromeObject { |
| + /* |
| + * Default Constructor |
| + * |
| + * Called by child objects during their regular construction. |
| + */ |
| + ChromeObject() : |
| + _jsObject = null; |
| + |
| + /* |
| + * Internal proxy constructor |
| + * |
| + * Creates a new object using this existing proxy. |
| + */ |
| + ChromeObject._proxy(this._jsObject); |
| + |
| + /* |
| + * JS Object Representation |
| + */ |
| + Object _jsObject; |
| + |
| + /* |
| + * Return a Map representation of this object's members, non-recursively. |
| + */ |
| + Map _toMap(); |
| + |
| + /* |
| + * Return a non-recursive serialized representation of this object. |
| + * |
| + * Returns a Map representation, if this object has not yet been proxied, |
| + * or the existing proxy, if it has already been proxied. |
| + */ |
| + Object _serialize() { |
| + if (_jsObject == null) |
| + return this._toMap(); |
| + return _jsObject; |
| + } |
| + |
| + /* |
| + * Returns True if this object has a matching JS object, False otherwise. |
| + */ |
| + bool _hasProxy() { |
| + return this._jsObject != null; |
| + } |
| +} |
| + |
| +/** |
| + * Useful functions for converting arguments. |
| + */ |
| + |
| +/** |
| + * Converts the given map-type argument to js-friendly format, recursively. |
| + * Returns the new Map object. |
| + */ |
| +Object _convertMapArgument(Map argument) { |
| + Map m = new Map(); |
| + for (Object key in argument.keys) |
| + m[key] = convertArgument(argument[key]); |
| + return convertDartToNative_Dictionary(m); |
| +} |
| + |
| +/* |
| +Map _convertMapArgument(Map argument) { |
| + var object = JS('var', '{}'); |
| + for (Object key in argument.keys) |
| + JS('void', '#[#] = #', object, key, convertArgument(argument[key])); |
| + return object; |
| +} |
| + */ |
| + |
| +/** |
| + * Converts the given list-type argument to js-friendly format, recursively. |
| + * Returns the new List object. |
| + */ |
| +List _convertListArgument(List argument) { |
| + List l = new List(); |
| + for (var i = 0; i < argument.length; i ++) |
| + l.add(convertArgument(argument[i])); |
| + return l; |
| +} |
| + |
| +/** |
| + * Converts the given argument Object to js-friendly format, recursively. |
| + * |
| + * Flattens out all Chrome objects into their corresponding ._toMap() |
| + * definitions, then converts them to JS objects. |
| + * |
| + * Returns the new argument. |
| + * |
| + * Cannot be used for functions. |
| + */ |
| +Object convertArgument(var argument) { |
| + if (argument == null) |
| + return argument; |
| + |
| + if (argument is num || argument is String || argument is bool) |
| + return argument; |
| + |
| + if (argument is ChromeObject) |
| + return convertArgument(argument._serialize()); |
| + |
| + if (argument is List) |
| + return _convertListArgument(argument); |
| + |
| + if (argument is Map) |
| + return _convertMapArgument(argument); |
| + |
| + if (argument is Function) |
| + throw new Exception("Cannot serialize Function argument ${argument}."); |
| + |
| + // TODO(sashab): Try and detect whether the argument is already serialized. |
| + return argument; |
| +} |
| + |
| +/** |
| + * Description of a declarative rule for handling events. |
| + */ |
| +class Rule extends ChromeObject { |
| + String _id; |
| + List _conditions; |
| + List _actions; |
| + int _priority; |
| + |
| + /* |
| + * Public (Dart) constructor |
| + */ |
| + Rule({ |
| + String id, |
| + List conditions, |
| + List actions, |
| + int priority |
| + }) : |
| + _id = id, |
| + _conditions = conditions, |
| + _actions = actions, |
| + _priority = priority |
| + ; |
| + |
| + /* |
| + * Private (JS) constructor |
| + */ |
| + Rule._proxy(_jsObject) |
| + : super._proxy(_jsObject); |
| + |
| + /* |
| + * Serialisation method |
| + */ |
| + Map _toMap() { |
| + Map m = {}; |
| + if (id != null) m['id'] = id; |
| + if (conditions != null) m['conditions'] = conditions; |
| + if (actions != null) m['actions'] = actions; |
| + if (priority != null) m['priority'] = priority; |
| + return m; |
| + } |
| + |
| + /* |
| + * Public accessors |
| + */ |
| + String get id { |
| + if (!this._hasProxy()) |
| + return this._id; |
| + return JS('String', '#.id', this._jsObject); |
| + } |
| + |
| + void set id(String id) { |
| + if (!this._hasProxy()) |
| + this._id = id; |
| + else |
| + JS('void', '#.id = #', this._jsObject, convertArgument(id)); |
| + } |
| + |
| + List get conditions { |
| + if (!this._hasProxy()) |
| + return this._conditions; |
| + return JS('List', '#.conditions', this._jsObject); |
| + } |
| + |
| + void set conditions(List conditions) { |
| + if (!this._hasProxy()) |
| + this._conditions = conditions; |
| + else |
| + JS('void', '#.conditions = #', this._jsObject, convertArgument(conditions)); |
|
blois
2013/01/23 02:06:12
line length
sashab
2013/01/23 04:45:34
Done, except for the comments on Events
|
| + } |
| + |
| + List get actions { |
| + if (!this._hasProxy()) |
| + return this._actions; |
| + return JS('List', '#.actions', this._jsObject); |
| + } |
| + |
| + void set actions(List actions) { |
| + if (!this._hasProxy()) |
| + this._actions = actions; |
| + else |
| + JS('void', '#.actions = #', this._jsObject, convertArgument(actions)); |
| + } |
| + |
| + int get priority { |
| + if (!this._hasProxy()) |
| + return this._priority; |
| + return JS('int', '#.priority', this._jsObject); |
| + } |
| + |
| + void set priority(int priority) { |
| + if (!this._hasProxy()) |
| + this._priority = priority; |
| + else |
| + JS('void', '#.priority = #', this._jsObject, convertArgument(priority)); |
| + } |
| + |
| +} |
| + |
| +/** |
| + * The Event class. |
| + * |
| + * Chrome Event classes extend this interface. |
| + * |
| + * e.g. |
| + * |
| + * // chrome.app.runtime.onLaunched |
| + * class $Event_ChromeAppRuntimeOnLaunched extends $Event { |
|
blois
2013/01/23 02:06:12
For DOM events, we're moving them over to streams.
sashab
2013/01/23 04:45:34
We could change these to be streams later? Are the
|
| + * // constructor, passing the arity of the callback |
| + * $Event_ChromeAppRuntimeOnLaunched(jsObject) : |
| + * super._(jsObject, 1); |
| + * |
| + * // methods, strengthening the Function parameter specificity |
| + * void addListener(void callback(LaunchData launchData)) |
| + * => super.addListener(callback); |
| + * void removeListener(void callback(LaunchData launchData)) |
| + * => super.removeListener(callback); |
| + * bool hasListener(void callback(LaunchData launchData)) |
| + * => super.hasListener(callback); |
| + * } |
| + * |
| + */ |
| +class $Event { |
|
blois
2013/01/23 02:06:12
Why the leading $?
sashab
2013/01/23 04:45:34
To distinguish it from html:Event. Should I just c
Emily Fortuna
2013/01/23 19:28:04
I made a comment on this in another version of thi
sashab
2013/01/23 22:24:53
I guess I'm just worried because I'm importing dar
|
| + // JS var |
| + Object _jsObject; |
| + |
| + // number of arguments the callback takes |
| + int _callbackArity; |
| + |
| + // constructor |
| + $Event._(this._jsObject, this._callbackArity); |
| + |
| + // methods |
| + |
| + /** |
| + * Registers an event listener <em>callback</em> to an event. |
| + */ |
| + void addListener(Function callback) => |
| + JS('void', |
| + '#.addListener(#)', |
| + this._jsObject, |
| + convertDartClosureToJS(callback, this._callbackArity) |
| + ); |
| + |
| + /** |
| + * Deregisters an event listener <em>callback</em> from an event. |
| + */ |
| + void removeListener(Function callback) => |
| + JS('void', |
| + '#.removeListener(#)', |
| + this._jsObject, |
| + convertDartClosureToJS(callback, this._callbackArity) |
| + ); |
| + |
| + /** |
| + * Returns True if <em>callback</em> is registered to the event. |
| + */ |
| + bool hasListener(Function callback) => |
| + JS('bool', |
| + '#.hasListener(#)', |
| + this._jsObject, |
| + convertDartClosureToJS(callback, this._callbackArity) |
| + ); |
| + |
| + /** |
| + * Returns true if any event listeners are registered to the event. |
| + */ |
| + bool hasListeners() => |
| + JS('bool', |
| + '#.hasListeners()', |
| + this._jsObject |
| + ); |
| + |
| + /** |
| + * Registers rules to handle events. |
| + * |
| + * @param eventName Name of the event this function affects. |
|
blois
2013/01/23 02:06:12
Dart doesn't use JS-style param comments.
sashab
2013/01/23 04:45:34
These were taken from events.idl. Should I just re
|
| + * @param rules Rules to be registered. These do not replace previously registered rules. |
| + * @param callback Called with registered rules. |
| + */ |
| + void addRules(String eventName, List<Rule> rules, [ void callback(List<Rule> rules) ]) { |
|
blois
2013/01/23 02:06:12
Usually no space between [ and arg-
rules, [void
blois
2013/01/23 02:06:12
80 char line length (and more below)
sashab
2013/01/23 04:45:34
Done.
sashab
2013/01/23 04:45:34
Done (except for Event comments).
|
| + // proxy the callback |
| + void __proxied_callback(List rules) {}; |
| + |
| + if (callback != null) |
| + void __proxied_callback(List rules) { |
| + List<Rule> __proxy_rules = new List<Rule>(); |
| + |
| + for (Object o in rules) |
| + __proxy_rules.add(new Rule._proxy(o)); |
| + |
| + callback(__proxy_rules); |
| + } |
| + |
| + JS('void', |
| + '#.addRules(#, #, #)', |
| + this._jsObject, |
| + convertArgument(eventName), |
| + convertArgument(rules), |
| + convertDartClosureToJS(callback, 1) |
| + ); |
| + } |
| + |
| + /** |
| + * Returns currently registered rules. |
| + * |
| + * @param eventName Name of the event this function affects. |
| + * @param ruleIdentifiers If an array is passed, only rules with identifiers contained in this array are returned. |
| + * @param callback Called with registered rules. |
| + */ |
| + void getRules(String eventName, [ List<String> ruleIdentifiers, void callback(List<Rule> rules) ]) { |
| + // proxy the callback |
| + void __proxied_callback(List rules) {}; |
| + |
| + if (callback != null) |
| + void __proxied_callback(List rules) { |
| + List<Rule> __proxy_rules = new List<Rule>(); |
| + |
| + for (Object o in rules) |
| + __proxy_rules.add(new Rule._proxy(o)); |
| + |
| + callback(__proxy_rules); |
| + } |
| + |
| + JS('void', |
| + '#.getRules(#, #, #)', |
| + this._jsObject, |
| + convertArgument(eventName), |
| + convertArgument(ruleIdentifiers), |
| + convertDartClosureToJS(callback, 1) |
| + ); |
| + } |
| + |
| + /** |
| + * Unregisters currently registered rules. |
| + * |
| + * @param eventName Name of the event this function affects. |
| + * @param ruleIdentifiers If an array is passed, only rules with identifiers contained in this array are unregistered. |
| + * @param callback Called when rules were unregistered. |
| + */ |
| + void removeRules(String eventName, [ List<String> ruleIdentifiers, void callback() ]) => |
| + JS('void', |
| + '#.removeRules(#, #, #)', |
| + this._jsObject, |
| + convertArgument(eventName), |
| + convertArgument(ruleIdentifiers), |
| + convertDartClosureToJS(callback, 0) |
| + ); |
| +} |
| + |
| + |
| + |
| + |
| + |
| + |
| + |
| + |
| + |
| + |
| + |
| + |