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

Side by Side Diff: third_party/pkg/js/lib/js.dart

Issue 124053002: Adding Angular and dependent packages for testing (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 * The js.dart library provides simple JavaScript invocation from Dart that
7 * works on both Dartium and on other modern browsers via Dart2JS.
8 *
9 * It provides a model based on scoped [Proxy] objects. Proxies give Dart
10 * code access to JavaScript objects, fields, and functions as well as the
11 * ability to pass Dart objects and functions to JavaScript functions. Scopes
12 * enable developers to use proxies without memory leaks - a common challenge
13 * with cross-runtime interoperation.
14 *
15 * The top-level [context] getter provides a [Proxy] to the global JavaScript
16 * context for the page your Dart code is running on. In the following example:
17 *
18 * import 'package:js/js.dart' as js;
19 *
20 * void main() {
21 * js.context.alert('Hello from Dart via JavaScript');
22 * }
23 *
24 * js.context.alert creates a proxy to the top-level alert function in
25 * JavaScript. It is invoked from Dart as a regular function that forwards to
26 * the underlying JavaScript one. By default, proxies are released when
27 * the currently executing event completes, e.g., when main is completes
28 * in this example.
29 *
30 * The library also enables JavaScript proxies to Dart objects and functions.
31 * For example, the following Dart code:
32 *
33 * js.context.dartCallback = (x) => print(x*2);
34 *
35 * defines a top-level JavaScript function 'dartCallback' that is a proxy to
36 * the corresponding Dart function.
37 *
38 * Note, parameters and return values are intuitively passed by value for
39 * primitives and by reference for non-primitives. In the latter case, the
40 * references are automatically wrapped and unwrapped as proxies by the library.
41 *
42 * This library also allows construction of JavaScripts objects given a [Proxy]
43 * to a corresponding JavaScript constructor. For example, if the following
44 * JavaScript is loaded on the page:
45 *
46 * function Foo(x) {
47 * this.x = x;
48 * }
49 *
50 * Foo.prototype.add = function(other) {
51 * return new Foo(this.x + other.x);
52 * }
53 *
54 * then, the following Dart:
55 *
56 * var foo = new js.Proxy(js.context.Foo, 42);
57 * var foo2 = foo.add(foo);
58 * print(foo2.x);
59 *
60 * will construct a JavaScript Foo object with the parameter 42, invoke its
61 * add method, and return a [Proxy] to a new Foo object whose x field is 84.
62 *
63 * See [samples](http://dart-lang.github.com/js-interop/example) for more
64 * examples of usage.
65 *
66 * See this [article](http://www.dartlang.org/articles/js-dart-interop) for
67 * more detailed discussion.
68 */
69
70 library js;
71
72 import 'dart:js' as js;
73 @MirrorsUsed(symbols: '*')
74 import 'dart:mirrors';
75
76 /**
77 * A proxy on the global JavaScript context for this page.
78 */
79 final Proxy context = new Proxy._(js.context);
80
81 /**
82 * Check if [proxy] is instance of [type].
83 */
84 bool instanceof(Serializable<Proxy> proxy, Serializable<FunctionProxy> type) =>
85 proxy.toJs()._jsObject.instanceof(type.toJs()._jsObject);
86
87 /**
88 * Check if [proxy] has a [name] property.
89 */
90 bool hasProperty(Serializable<Proxy> proxy, String name) =>
91 proxy.toJs()._jsObject.hasProperty(name);
92
93 /**
94 * Delete the [name] property of [proxy].
95 */
96 void deleteProperty(Serializable<Proxy> proxy, String name) {
97 proxy.toJs()._jsObject.deleteProperty(name);
98 }
99
100 /**
101 * Converts a Dart map [data] to a JavaScript map and return a [Proxy] to it.
102 */
103 Proxy map(Map data) => new Proxy._json(data);
104
105 /**
106 * Converts a Dart [Iterable] to a JavaScript array and return a [Proxy] to it.
107 */
108 Proxy array(Iterable data) => new Proxy._json(data);
109
110 // Detect unspecified arguments.
111 class _Undefined {
112 const _Undefined();
113 }
114
115 const _undefined = const _Undefined();
116
117 List _pruneUndefined(arg1, arg2, arg3, arg4, arg5, arg6) {
118 // This assumes no argument
119 final args = [arg1, arg2, arg3, arg4, arg5, arg6];
120 final index = args.indexOf(_undefined);
121 if (index < 0) return args;
122 return args.sublist(0, index);
123 }
124
125 /**
126 * Proxies to JavaScript objects.
127 */
128 @proxy
129 class Proxy<T extends Proxy> implements Serializable<T> {
130 final js.JsObject _jsObject;
131
132 Proxy._(this._jsObject);
133
134 /**
135 * Constructs a [Proxy] that proxies a native Dart object; _for expert use
136 * only_.
137 *
138 * Use this constructor only if you wish to get access to JavaScript
139 * properties attached to a browser host object, such as a Node or Blob, that
140 * is normally automatically converted into a native Dart object.
141 *
142 * An exception will be thrown if [object] either is `null` or has the type
143 * `bool`, `num`, or `String`.
144 */
145 Proxy.fromBrowserObject(o) : this._(new js.JsObject.fromBrowserObject(o));
146
147 /**
148 * Constructs a [Proxy] to a new JavaScript object by invoking a (proxy to a)
149 * JavaScript [constructor]. The arguments should be either
150 * primitive values, DOM elements, or Proxies.
151 */
152 factory Proxy(Serializable<FunctionProxy> constructor,
153 [arg1 = _undefined,
154 arg2 = _undefined,
155 arg3 = _undefined,
156 arg4 = _undefined,
157 arg5 = _undefined,
158 arg6 = _undefined]) {
159 var arguments = _pruneUndefined(arg1, arg2, arg3, arg4, arg5, arg6);
160 return new Proxy.withArgList(constructor, arguments);
161 }
162
163 /**
164 * Constructs a [Proxy] to a new JavaScript object by invoking a (proxy to a)
165 * JavaScript [constructor]. The [arguments] list should contain either
166 * primitive values, DOM elements, or Proxies.
167 */
168 factory Proxy.withArgList(Serializable<FunctionProxy> constructor,
169 List arguments) => new Proxy._(new js.JsObject(
170 constructor.toJs()._jsObject, arguments.map(_serialize).toList()));
171
172 /**
173 * Constructs a [Proxy] to a new JavaScript map or list created defined via
174 * Dart map or list.
175 */
176 factory Proxy._json(data) =>
177 new Proxy._(new js.JsObject.jsify(_serializeDataTree(data)));
178
179 static _serializeDataTree(data) {
180 if (data is Map) {
181 final map = new Map();
182 for (var key in data.keys) {
183 map[key] = _serializeDataTree(data[key]);
184 }
185 return map;
186 } else if (data is Iterable) {
187 return data.map(_serializeDataTree).toList();
188 } else {
189 return _serialize(data);
190 }
191 }
192
193 Proxy toJs() => this;
194
195 // Resolve whether this is needed.
196 operator[](arg) => _deserialize(_jsObject[arg], thisArg: this);
197
198 // Resolve whether this is needed.
199 operator[]=(key, value) => _jsObject[key] = _serialize(value);
200
201 int get hashCode => _jsObject.hashCode;
202
203 // Test if this is equivalent to another Proxy. This essentially
204 // maps to JavaScript's == operator.
205 operator==(other) => _jsObject == _serialize(other);
206
207 String toString() => _jsObject.toString();
208
209 // Forward member accesses to the backing JavaScript object.
210 noSuchMethod(Invocation invocation) {
211 String member = MirrorSystem.getName(invocation.memberName);
212 // If trying to access a JavaScript field/variable that starts with
213 // _ (underscore), Dart treats it a library private and member name
214 // it suffixed with '@internalLibraryIdentifier' which we have to
215 // strip before sending over to the JS side.
216 if (member.indexOf('@') != -1) {
217 member = member.substring(0, member.indexOf('@'));
218 }
219 if (invocation.isGetter) {
220 if (_jsObject.hasProperty(member)) {
221 return _deserialize(_jsObject[member], thisArg: this);
222 } else {
223 super.noSuchMethod(invocation);
224 }
225 } else if (invocation.isSetter) {
226 if (member.endsWith('=')) {
227 member = member.substring(0, member.length - 1);
228 }
229 _jsObject[member] = _serialize(invocation.positionalArguments[0]);
230 return null;
231 } else {
232 return _deserialize(_jsObject.callMethod(member,
233 invocation.positionalArguments.map(_serialize).toList()),
234 thisArg: this);
235 }
236 }
237 }
238
239 class _CallbackFunction implements Function {
240 final Function f;
241 final bool withThis;
242
243 _CallbackFunction(this.f, {this.withThis});
244
245 call() => throw new StateError('There should always been at least 1 parameter'
246 '(js this).');
247
248 noSuchMethod(Invocation invocation) {
249 final args = invocation.positionalArguments.skip(
250 withThis != null && withThis ? 0 : 1);
251 return _serialize(Function.apply(f,
252 args.map((e) => _deserialize(e)).toList()));
253 }
254 }
255
256 /// A [Proxy] subtype to JavaScript functions.
257 class FunctionProxy extends Proxy<FunctionProxy> implements Function {
258 final js.JsFunction _jsFunction;
259 final _thisArg;
260
261 FunctionProxy._(js.JsFunction jsFunction, {thisArg}) :
262 this._jsFunction = jsFunction,
263 this._thisArg = thisArg,
264 super._(jsFunction);
265
266 factory FunctionProxy(Function f) => new FunctionProxy._(
267 new js.JsFunction.withThis(new _CallbackFunction(f)));
268
269 factory FunctionProxy.withThis(Function f) => new FunctionProxy._(
270 new js.JsFunction.withThis(new _CallbackFunction(f, withThis: true)));
271
272 // We need to implement call() to satisfy the Function "interface"
273 // This handles the no-arg case, noSuchMethod handles the rest.
274 call() => _deserialize(_jsFunction.apply([], thisArg: _serialize(_thisArg)),
275 thisArg: this);
276
277 noSuchMethod(Invocation invocation) {
278 String member = MirrorSystem.getName(invocation.memberName);
279 // If trying to access a JavaScript field/variable that starts with
280 // _ (underscore), Dart treats it a library private and member name
281 // it suffixed with '@internalLibraryIdentifier' which we have to
282 // strip before sending over to the JS side.
283 if (member.indexOf('@') != -1) {
284 member = member.substring(0, member.indexOf('@'));
285 }
286 if (member == 'call') {
287 // A 'call' (probably) means that this proxy was invoked directly
288 // as if it was a function. Map this to JS function application.
289 return _deserialize(_jsFunction.apply(
290 invocation.positionalArguments.map(_serialize).toList(),
291 thisArg: _serialize(_thisArg)), thisArg: this);
292 }
293 return super.noSuchMethod(invocation);
294 }
295 }
296
297 /// Marker class used to indicate it is serializable to js. If a class is a
298 /// [Serializable] the "toJs" method will be called and the result will be used
299 /// as value.
300 abstract class Serializable<T> {
301 T toJs();
302 }
303
304 _serialize(var o) {
305 if (o == null) {
306 return null;
307 } else if (o is Proxy) {
308 return o._jsObject;
309 } else if (o is Serializable) {
310 return _serialize(o.toJs());
311 } else if (o is Function) {
312 return _serialize(new FunctionProxy(o));
313 } else {
314 return o;
315 }
316 }
317
318 _deserialize(var o, {thisArg}) {
319 if (o == null) {
320 return null;
321 } else if (o is js.JsFunction) {
322 return new FunctionProxy._(o, thisArg: thisArg);
323 } else if (o is js.JsObject) {
324 return new Proxy._(o);
325 } else {
326 return o;
327 }
328 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698