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

Unified 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, 12 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 side-by-side diff with in-line comments
Download patch
Index: third_party/pkg/js/lib/js.dart
diff --git a/third_party/pkg/js/lib/js.dart b/third_party/pkg/js/lib/js.dart
new file mode 100644
index 0000000000000000000000000000000000000000..abad79d4b18b11297b2f6d7d5f55e93cafcf2f34
--- /dev/null
+++ b/third_party/pkg/js/lib/js.dart
@@ -0,0 +1,328 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// 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.
+
+/**
+ * The js.dart library provides simple JavaScript invocation from Dart that
+ * works on both Dartium and on other modern browsers via Dart2JS.
+ *
+ * It provides a model based on scoped [Proxy] objects. Proxies give Dart
+ * code access to JavaScript objects, fields, and functions as well as the
+ * ability to pass Dart objects and functions to JavaScript functions. Scopes
+ * enable developers to use proxies without memory leaks - a common challenge
+ * with cross-runtime interoperation.
+ *
+ * The top-level [context] getter provides a [Proxy] to the global JavaScript
+ * context for the page your Dart code is running on. In the following example:
+ *
+ * import 'package:js/js.dart' as js;
+ *
+ * void main() {
+ * js.context.alert('Hello from Dart via JavaScript');
+ * }
+ *
+ * js.context.alert creates a proxy to the top-level alert function in
+ * JavaScript. It is invoked from Dart as a regular function that forwards to
+ * the underlying JavaScript one. By default, proxies are released when
+ * the currently executing event completes, e.g., when main is completes
+ * in this example.
+ *
+ * The library also enables JavaScript proxies to Dart objects and functions.
+ * For example, the following Dart code:
+ *
+ * js.context.dartCallback = (x) => print(x*2);
+ *
+ * defines a top-level JavaScript function 'dartCallback' that is a proxy to
+ * the corresponding Dart function.
+ *
+ * Note, parameters and return values are intuitively passed by value for
+ * primitives and by reference for non-primitives. In the latter case, the
+ * references are automatically wrapped and unwrapped as proxies by the library.
+ *
+ * This library also allows construction of JavaScripts objects given a [Proxy]
+ * to a corresponding JavaScript constructor. For example, if the following
+ * JavaScript is loaded on the page:
+ *
+ * function Foo(x) {
+ * this.x = x;
+ * }
+ *
+ * Foo.prototype.add = function(other) {
+ * return new Foo(this.x + other.x);
+ * }
+ *
+ * then, the following Dart:
+ *
+ * var foo = new js.Proxy(js.context.Foo, 42);
+ * var foo2 = foo.add(foo);
+ * print(foo2.x);
+ *
+ * will construct a JavaScript Foo object with the parameter 42, invoke its
+ * add method, and return a [Proxy] to a new Foo object whose x field is 84.
+ *
+ * See [samples](http://dart-lang.github.com/js-interop/example) for more
+ * examples of usage.
+ *
+ * See this [article](http://www.dartlang.org/articles/js-dart-interop) for
+ * more detailed discussion.
+ */
+
+library js;
+
+import 'dart:js' as js;
+@MirrorsUsed(symbols: '*')
+import 'dart:mirrors';
+
+/**
+ * A proxy on the global JavaScript context for this page.
+ */
+final Proxy context = new Proxy._(js.context);
+
+/**
+ * Check if [proxy] is instance of [type].
+ */
+bool instanceof(Serializable<Proxy> proxy, Serializable<FunctionProxy> type) =>
+ proxy.toJs()._jsObject.instanceof(type.toJs()._jsObject);
+
+/**
+ * Check if [proxy] has a [name] property.
+ */
+bool hasProperty(Serializable<Proxy> proxy, String name) =>
+ proxy.toJs()._jsObject.hasProperty(name);
+
+/**
+ * Delete the [name] property of [proxy].
+ */
+void deleteProperty(Serializable<Proxy> proxy, String name) {
+ proxy.toJs()._jsObject.deleteProperty(name);
+}
+
+/**
+ * Converts a Dart map [data] to a JavaScript map and return a [Proxy] to it.
+ */
+Proxy map(Map data) => new Proxy._json(data);
+
+/**
+ * Converts a Dart [Iterable] to a JavaScript array and return a [Proxy] to it.
+ */
+Proxy array(Iterable data) => new Proxy._json(data);
+
+// Detect unspecified arguments.
+class _Undefined {
+ const _Undefined();
+}
+
+const _undefined = const _Undefined();
+
+List _pruneUndefined(arg1, arg2, arg3, arg4, arg5, arg6) {
+ // This assumes no argument
+ final args = [arg1, arg2, arg3, arg4, arg5, arg6];
+ final index = args.indexOf(_undefined);
+ if (index < 0) return args;
+ return args.sublist(0, index);
+}
+
+/**
+ * Proxies to JavaScript objects.
+ */
+@proxy
+class Proxy<T extends Proxy> implements Serializable<T> {
+ final js.JsObject _jsObject;
+
+ Proxy._(this._jsObject);
+
+ /**
+ * Constructs a [Proxy] that proxies a native Dart object; _for expert use
+ * only_.
+ *
+ * Use this constructor only if you wish to get access to JavaScript
+ * properties attached to a browser host object, such as a Node or Blob, that
+ * is normally automatically converted into a native Dart object.
+ *
+ * An exception will be thrown if [object] either is `null` or has the type
+ * `bool`, `num`, or `String`.
+ */
+ Proxy.fromBrowserObject(o) : this._(new js.JsObject.fromBrowserObject(o));
+
+ /**
+ * Constructs a [Proxy] to a new JavaScript object by invoking a (proxy to a)
+ * JavaScript [constructor]. The arguments should be either
+ * primitive values, DOM elements, or Proxies.
+ */
+ factory Proxy(Serializable<FunctionProxy> constructor,
+ [arg1 = _undefined,
+ arg2 = _undefined,
+ arg3 = _undefined,
+ arg4 = _undefined,
+ arg5 = _undefined,
+ arg6 = _undefined]) {
+ var arguments = _pruneUndefined(arg1, arg2, arg3, arg4, arg5, arg6);
+ return new Proxy.withArgList(constructor, arguments);
+ }
+
+ /**
+ * Constructs a [Proxy] to a new JavaScript object by invoking a (proxy to a)
+ * JavaScript [constructor]. The [arguments] list should contain either
+ * primitive values, DOM elements, or Proxies.
+ */
+ factory Proxy.withArgList(Serializable<FunctionProxy> constructor,
+ List arguments) => new Proxy._(new js.JsObject(
+ constructor.toJs()._jsObject, arguments.map(_serialize).toList()));
+
+ /**
+ * Constructs a [Proxy] to a new JavaScript map or list created defined via
+ * Dart map or list.
+ */
+ factory Proxy._json(data) =>
+ new Proxy._(new js.JsObject.jsify(_serializeDataTree(data)));
+
+ static _serializeDataTree(data) {
+ if (data is Map) {
+ final map = new Map();
+ for (var key in data.keys) {
+ map[key] = _serializeDataTree(data[key]);
+ }
+ return map;
+ } else if (data is Iterable) {
+ return data.map(_serializeDataTree).toList();
+ } else {
+ return _serialize(data);
+ }
+ }
+
+ Proxy toJs() => this;
+
+ // Resolve whether this is needed.
+ operator[](arg) => _deserialize(_jsObject[arg], thisArg: this);
+
+ // Resolve whether this is needed.
+ operator[]=(key, value) => _jsObject[key] = _serialize(value);
+
+ int get hashCode => _jsObject.hashCode;
+
+ // Test if this is equivalent to another Proxy. This essentially
+ // maps to JavaScript's == operator.
+ operator==(other) => _jsObject == _serialize(other);
+
+ String toString() => _jsObject.toString();
+
+ // Forward member accesses to the backing JavaScript object.
+ noSuchMethod(Invocation invocation) {
+ String member = MirrorSystem.getName(invocation.memberName);
+ // If trying to access a JavaScript field/variable that starts with
+ // _ (underscore), Dart treats it a library private and member name
+ // it suffixed with '@internalLibraryIdentifier' which we have to
+ // strip before sending over to the JS side.
+ if (member.indexOf('@') != -1) {
+ member = member.substring(0, member.indexOf('@'));
+ }
+ if (invocation.isGetter) {
+ if (_jsObject.hasProperty(member)) {
+ return _deserialize(_jsObject[member], thisArg: this);
+ } else {
+ super.noSuchMethod(invocation);
+ }
+ } else if (invocation.isSetter) {
+ if (member.endsWith('=')) {
+ member = member.substring(0, member.length - 1);
+ }
+ _jsObject[member] = _serialize(invocation.positionalArguments[0]);
+ return null;
+ } else {
+ return _deserialize(_jsObject.callMethod(member,
+ invocation.positionalArguments.map(_serialize).toList()),
+ thisArg: this);
+ }
+ }
+}
+
+class _CallbackFunction implements Function {
+ final Function f;
+ final bool withThis;
+
+ _CallbackFunction(this.f, {this.withThis});
+
+ call() => throw new StateError('There should always been at least 1 parameter'
+ '(js this).');
+
+ noSuchMethod(Invocation invocation) {
+ final args = invocation.positionalArguments.skip(
+ withThis != null && withThis ? 0 : 1);
+ return _serialize(Function.apply(f,
+ args.map((e) => _deserialize(e)).toList()));
+ }
+}
+
+/// A [Proxy] subtype to JavaScript functions.
+class FunctionProxy extends Proxy<FunctionProxy> implements Function {
+ final js.JsFunction _jsFunction;
+ final _thisArg;
+
+ FunctionProxy._(js.JsFunction jsFunction, {thisArg}) :
+ this._jsFunction = jsFunction,
+ this._thisArg = thisArg,
+ super._(jsFunction);
+
+ factory FunctionProxy(Function f) => new FunctionProxy._(
+ new js.JsFunction.withThis(new _CallbackFunction(f)));
+
+ factory FunctionProxy.withThis(Function f) => new FunctionProxy._(
+ new js.JsFunction.withThis(new _CallbackFunction(f, withThis: true)));
+
+ // We need to implement call() to satisfy the Function "interface"
+ // This handles the no-arg case, noSuchMethod handles the rest.
+ call() => _deserialize(_jsFunction.apply([], thisArg: _serialize(_thisArg)),
+ thisArg: this);
+
+ noSuchMethod(Invocation invocation) {
+ String member = MirrorSystem.getName(invocation.memberName);
+ // If trying to access a JavaScript field/variable that starts with
+ // _ (underscore), Dart treats it a library private and member name
+ // it suffixed with '@internalLibraryIdentifier' which we have to
+ // strip before sending over to the JS side.
+ if (member.indexOf('@') != -1) {
+ member = member.substring(0, member.indexOf('@'));
+ }
+ if (member == 'call') {
+ // A 'call' (probably) means that this proxy was invoked directly
+ // as if it was a function. Map this to JS function application.
+ return _deserialize(_jsFunction.apply(
+ invocation.positionalArguments.map(_serialize).toList(),
+ thisArg: _serialize(_thisArg)), thisArg: this);
+ }
+ return super.noSuchMethod(invocation);
+ }
+}
+
+/// Marker class used to indicate it is serializable to js. If a class is a
+/// [Serializable] the "toJs" method will be called and the result will be used
+/// as value.
+abstract class Serializable<T> {
+ T toJs();
+}
+
+_serialize(var o) {
+ if (o == null) {
+ return null;
+ } else if (o is Proxy) {
+ return o._jsObject;
+ } else if (o is Serializable) {
+ return _serialize(o.toJs());
+ } else if (o is Function) {
+ return _serialize(new FunctionProxy(o));
+ } else {
+ return o;
+ }
+}
+
+_deserialize(var o, {thisArg}) {
+ if (o == null) {
+ return null;
+ } else if (o is js.JsFunction) {
+ return new FunctionProxy._(o, thisArg: thisArg);
+ } else if (o is js.JsObject) {
+ return new Proxy._(o);
+ } else {
+ return o;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698