| Index: src/site/codelabs/darrrt/examples/packages/browser/interop.js
|
| diff --git a/src/site/codelabs/darrrt/examples/packages/browser/interop.js b/src/site/codelabs/darrrt/examples/packages/browser/interop.js
|
| index 8577e4f28b8c30aa67270ff78727da5789d0bea0..ec02e5857ad195d2df1c15a768f83fda4b7fa098 100644
|
| --- a/src/site/codelabs/darrrt/examples/packages/browser/interop.js
|
| +++ b/src/site/codelabs/darrrt/examples/packages/browser/interop.js
|
| @@ -2,540 +2,8 @@
|
| // 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.
|
|
|
| -// ---------------------------------------------------------------------------
|
| -// Support for JS interoperability
|
| -// ---------------------------------------------------------------------------
|
| -function SendPortSync() {
|
| +// TODO(jmesserly): remove this script after a deprecation period.
|
| +if (typeof console == "object" && typeof console.warn == "function") {
|
| + console.warn('<script src="packages/browser/interop.js"> is no longer ' +
|
| + 'needed for dart:js. See http://pub.dartlang.org/packages/browser.');
|
| }
|
| -
|
| -function ReceivePortSync() {
|
| - this.id = ReceivePortSync.id++;
|
| - ReceivePortSync.map[this.id] = this;
|
| -}
|
| -
|
| -// Type for remote proxies to Dart objects with dart2js.
|
| -function DartProxy(o) {
|
| - this.o = o;
|
| -}
|
| -
|
| -(function() {
|
| - // Serialize the following types as follows:
|
| - // - primitives / null: unchanged
|
| - // - lists: [ 'list', internal id, list of recursively serialized elements ]
|
| - // - maps: [ 'map', internal id, map of keys and recursively serialized values ]
|
| - // - send ports: [ 'sendport', type, isolate id, port id ]
|
| - //
|
| - // Note, internal id's are for cycle detection.
|
| - function serialize(message) {
|
| - var visited = [];
|
| - function checkedSerialization(obj, serializer) {
|
| - // Implementation detail: for now use linear search.
|
| - // Another option is expando, but it may prohibit
|
| - // VM optimizations (like putting object into slow mode
|
| - // on property deletion.)
|
| - var id = visited.indexOf(obj);
|
| - if (id != -1) return [ 'ref', id ];
|
| - var id = visited.length;
|
| - visited.push(obj);
|
| - return serializer(id);
|
| - }
|
| -
|
| - function doSerialize(message) {
|
| - if (message == null) {
|
| - return null; // Convert undefined to null.
|
| - } else if (typeof(message) == 'string' ||
|
| - typeof(message) == 'number' ||
|
| - typeof(message) == 'boolean') {
|
| - return message;
|
| - } else if (message instanceof Array) {
|
| - return checkedSerialization(message, function(id) {
|
| - var values = new Array(message.length);
|
| - for (var i = 0; i < message.length; i++) {
|
| - values[i] = doSerialize(message[i]);
|
| - }
|
| - return [ 'list', id, values ];
|
| - });
|
| - } else if (message instanceof LocalSendPortSync) {
|
| - return [ 'sendport', 'nativejs', message.receivePort.id ];
|
| - } else if (message instanceof DartSendPortSync) {
|
| - return [ 'sendport', 'dart', message.isolateId, message.portId ];
|
| - } else {
|
| - return checkedSerialization(message, function(id) {
|
| - var keys = Object.getOwnPropertyNames(message);
|
| - var values = new Array(keys.length);
|
| - for (var i = 0; i < keys.length; i++) {
|
| - values[i] = doSerialize(message[keys[i]]);
|
| - }
|
| - return [ 'map', id, keys, values ];
|
| - });
|
| - }
|
| - }
|
| - return doSerialize(message);
|
| - }
|
| -
|
| - function deserialize(message) {
|
| - return deserializeHelper(message);
|
| - }
|
| -
|
| - function deserializeHelper(message) {
|
| - if (message == null ||
|
| - typeof(message) == 'string' ||
|
| - typeof(message) == 'number' ||
|
| - typeof(message) == 'boolean') {
|
| - return message;
|
| - }
|
| - switch (message[0]) {
|
| - case 'map': return deserializeMap(message);
|
| - case 'sendport': return deserializeSendPort(message);
|
| - case 'list': return deserializeList(message);
|
| - default: throw 'unimplemented';
|
| - }
|
| - }
|
| -
|
| - function deserializeMap(message) {
|
| - var result = { };
|
| - var id = message[1];
|
| - var keys = message[2];
|
| - var values = message[3];
|
| - for (var i = 0, length = keys.length; i < length; i++) {
|
| - var key = deserializeHelper(keys[i]);
|
| - var value = deserializeHelper(values[i]);
|
| - result[key] = value;
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - function deserializeSendPort(message) {
|
| - var tag = message[1];
|
| - switch (tag) {
|
| - case 'nativejs':
|
| - var id = message[2];
|
| - return new LocalSendPortSync(ReceivePortSync.map[id]);
|
| - case 'dart':
|
| - var isolateId = message[2];
|
| - var portId = message[3];
|
| - return new DartSendPortSync(isolateId, portId);
|
| - default:
|
| - throw 'Illegal SendPortSync type: $tag';
|
| - }
|
| - }
|
| -
|
| - function deserializeList(message) {
|
| - var values = message[2];
|
| - var length = values.length;
|
| - var result = new Array(length);
|
| - for (var i = 0; i < length; i++) {
|
| - result[i] = deserializeHelper(values[i]);
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - window.registerPort = function(name, port) {
|
| - var stringified = JSON.stringify(serialize(port));
|
| - var attrName = 'dart-port:' + name;
|
| - document.documentElement.setAttribute(attrName, stringified);
|
| - };
|
| -
|
| - window.lookupPort = function(name) {
|
| - var attrName = 'dart-port:' + name;
|
| - var stringified = document.documentElement.getAttribute(attrName);
|
| - return deserialize(JSON.parse(stringified));
|
| - };
|
| -
|
| - ReceivePortSync.id = 0;
|
| - ReceivePortSync.map = {};
|
| -
|
| - ReceivePortSync.dispatchCall = function(id, message) {
|
| - // TODO(vsm): Handle and propagate exceptions.
|
| - var deserialized = deserialize(message);
|
| - var result = ReceivePortSync.map[id].callback(deserialized);
|
| - return serialize(result);
|
| - };
|
| -
|
| - ReceivePortSync.prototype.receive = function(callback) {
|
| - this.callback = callback;
|
| - };
|
| -
|
| - ReceivePortSync.prototype.toSendPort = function() {
|
| - return new LocalSendPortSync(this);
|
| - };
|
| -
|
| - ReceivePortSync.prototype.close = function() {
|
| - delete ReceivePortSync.map[this.id];
|
| - };
|
| -
|
| - if (navigator.webkitStartDart) {
|
| - window.addEventListener('js-sync-message', function(event) {
|
| - var data = JSON.parse(getPortSyncEventData(event));
|
| - var deserialized = deserialize(data.message);
|
| - var result = ReceivePortSync.map[data.id].callback(deserialized);
|
| - // TODO(vsm): Handle and propagate exceptions.
|
| - dispatchEvent('js-result', serialize(result));
|
| - }, false);
|
| - }
|
| -
|
| - function LocalSendPortSync(receivePort) {
|
| - this.receivePort = receivePort;
|
| - }
|
| -
|
| - LocalSendPortSync.prototype = new SendPortSync();
|
| -
|
| - LocalSendPortSync.prototype.callSync = function(message) {
|
| - // TODO(vsm): Do a direct deepcopy.
|
| - message = deserialize(serialize(message));
|
| - return this.receivePort.callback(message);
|
| - }
|
| -
|
| - function DartSendPortSync(isolateId, portId) {
|
| - this.isolateId = isolateId;
|
| - this.portId = portId;
|
| - }
|
| -
|
| - DartSendPortSync.prototype = new SendPortSync();
|
| -
|
| - function dispatchEvent(receiver, message) {
|
| - var string = JSON.stringify(message);
|
| - var event = document.createEvent('CustomEvent');
|
| - event.initCustomEvent(receiver, false, false, string);
|
| - window.dispatchEvent(event);
|
| - }
|
| -
|
| - function getPortSyncEventData(event) {
|
| - return event.detail;
|
| - }
|
| -
|
| - DartSendPortSync.prototype.callSync = function(message) {
|
| - var serialized = serialize(message);
|
| - var target = 'dart-port-' + this.isolateId + '-' + this.portId;
|
| - // TODO(vsm): Make this re-entrant.
|
| - // TODO(vsm): Set this up set once, on the first call.
|
| - var source = target + '-result';
|
| - var result = null;
|
| - var listener = function (e) {
|
| - result = JSON.parse(getPortSyncEventData(e));
|
| - };
|
| - window.addEventListener(source, listener, false);
|
| - dispatchEvent(target, [source, serialized]);
|
| - window.removeEventListener(source, listener, false);
|
| - return deserialize(result);
|
| - }
|
| -})();
|
| -
|
| -(function() {
|
| - // Proxy support for js.dart.
|
| -
|
| - // We don't use 'window' because we might be in a web worker, but we don't
|
| - // use 'self' because not all browsers support it
|
| - var globalContext = function() { return this; }();
|
| -
|
| - // Table for local objects and functions that are proxied.
|
| - function ProxiedObjectTable() {
|
| - // Name for debugging.
|
| - this.name = 'js-ref';
|
| -
|
| - // Table from IDs to JS objects.
|
| - this.map = {};
|
| -
|
| - // Generator for new IDs.
|
| - this._nextId = 0;
|
| -
|
| - // Ports for managing communication to proxies.
|
| - this.port = new ReceivePortSync();
|
| - this.sendPort = this.port.toSendPort();
|
| - }
|
| -
|
| - // Number of valid IDs. This is the number of objects (global and local)
|
| - // kept alive by this table.
|
| - ProxiedObjectTable.prototype.count = function () {
|
| - return Object.keys(this.map).length;
|
| - }
|
| -
|
| - // Adds an object to the table and return an ID for serialization.
|
| - ProxiedObjectTable.prototype.add = function (obj) {
|
| - for (var ref in this.map) {
|
| - var o = this.map[ref];
|
| - if (o === obj) {
|
| - return ref;
|
| - }
|
| - }
|
| - var ref = this.name + '-' + this._nextId++;
|
| - this.map[ref] = obj;
|
| - return ref;
|
| - }
|
| -
|
| - // Gets the object or function corresponding to this ID.
|
| - ProxiedObjectTable.prototype.get = function (id) {
|
| - if (!this.map.hasOwnProperty(id)) {
|
| - throw 'Proxy ' + id + ' has been invalidated.'
|
| - }
|
| - return this.map[id];
|
| - }
|
| -
|
| - ProxiedObjectTable.prototype._initialize = function () {
|
| - // Configure this table's port to forward methods, getters, and setters
|
| - // from the remote proxy to the local object.
|
| - var table = this;
|
| -
|
| - this.port.receive(function (message) {
|
| - // TODO(vsm): Support a mechanism to register a handler here.
|
| - try {
|
| - var receiver = table.get(message[0]);
|
| - var member = message[1];
|
| - var kind = message[2];
|
| - var args = message[3].map(deserialize);
|
| - if (kind == 'get') {
|
| - // Getter.
|
| - var field = member;
|
| - if (field in receiver && args.length == 0) {
|
| - return [ 'return', serialize(receiver[field]) ];
|
| - }
|
| - } else if (kind == 'set') {
|
| - // Setter.
|
| - var field = member;
|
| - if (args.length == 1) {
|
| - return [ 'return', serialize(receiver[field] = args[0]) ];
|
| - }
|
| - } else if (kind == 'hasProperty') {
|
| - var field = member;
|
| - return [ 'return', field in receiver ];
|
| - } else if (kind == 'apply') {
|
| - // Direct function invocation.
|
| - return [ 'return',
|
| - serialize(receiver.apply(args[0], args.slice(1))) ];
|
| - } else if (member == '[]' && args.length == 1) {
|
| - // Index getter.
|
| - return [ 'return', serialize(receiver[args[0]]) ];
|
| - } else if (member == '[]=' && args.length == 2) {
|
| - // Index setter.
|
| - return [ 'return', serialize(receiver[args[0]] = args[1]) ];
|
| - } else {
|
| - // Member function invocation.
|
| - var f = receiver[member];
|
| - if (f) {
|
| - var result = f.apply(receiver, args);
|
| - return [ 'return', serialize(result) ];
|
| - }
|
| - }
|
| - return [ 'none' ];
|
| - } catch (e) {
|
| - return [ 'throws', e.toString() ];
|
| - }
|
| - });
|
| - }
|
| -
|
| - // Singleton for local proxied objects.
|
| - var proxiedObjectTable = new ProxiedObjectTable();
|
| - proxiedObjectTable._initialize()
|
| -
|
| - // Type for remote proxies to Dart objects.
|
| - function DartProxy(id, sendPort) {
|
| - this.id = id;
|
| - this.port = sendPort;
|
| - }
|
| -
|
| - // Serializes JS types to SendPortSync format:
|
| - // - primitives -> primitives
|
| - // - sendport -> sendport
|
| - // - Function -> [ 'funcref', function-id, sendport ]
|
| - // - Object -> [ 'objref', object-id, sendport ]
|
| - function serialize(message) {
|
| - if (message == null) {
|
| - return null; // Convert undefined to null.
|
| - } else if (typeof(message) == 'string' ||
|
| - typeof(message) == 'number' ||
|
| - typeof(message) == 'boolean') {
|
| - // Primitives are passed directly through.
|
| - return message;
|
| - } else if (message instanceof SendPortSync) {
|
| - // Non-proxied objects are serialized.
|
| - return message;
|
| - } else if (typeof(message) == 'function') {
|
| - if ('_dart_id' in message) {
|
| - // Remote function proxy.
|
| - var remoteId = message._dart_id;
|
| - var remoteSendPort = message._dart_port;
|
| - return [ 'funcref', remoteId, remoteSendPort ];
|
| - } else {
|
| - // Local function proxy.
|
| - return [ 'funcref',
|
| - proxiedObjectTable.add(message),
|
| - proxiedObjectTable.sendPort ];
|
| - }
|
| - } else if (message instanceof DartProxy) {
|
| - // Remote object proxy.
|
| - return [ 'objref', message.id, message.port ];
|
| - } else {
|
| - // Local object proxy.
|
| - return [ 'objref',
|
| - proxiedObjectTable.add(message),
|
| - proxiedObjectTable.sendPort ];
|
| - }
|
| - }
|
| -
|
| - function deserialize(message) {
|
| - if (message == null) {
|
| - return null; // Convert undefined to null.
|
| - } else if (typeof(message) == 'string' ||
|
| - typeof(message) == 'number' ||
|
| - typeof(message) == 'boolean') {
|
| - // Primitives are passed directly through.
|
| - return message;
|
| - } else if (message instanceof SendPortSync) {
|
| - // Serialized type.
|
| - return message;
|
| - }
|
| - var tag = message[0];
|
| - switch (tag) {
|
| - case 'funcref': return deserializeFunction(message);
|
| - case 'objref': return deserializeObject(message);
|
| - }
|
| - throw 'Unsupported serialized data: ' + message;
|
| - }
|
| -
|
| - // Create a local function that forwards to the remote function.
|
| - function deserializeFunction(message) {
|
| - var id = message[1];
|
| - var port = message[2];
|
| - // TODO(vsm): Add a more robust check for a local SendPortSync.
|
| - if ("receivePort" in port) {
|
| - // Local function.
|
| - return proxiedObjectTable.get(id);
|
| - } else {
|
| - // Remote function. Forward to its port.
|
| - var f = function () {
|
| - var args = Array.prototype.slice.apply(arguments);
|
| - args.splice(0, 0, this);
|
| - args = args.map(serialize);
|
| - var result = port.callSync([id, '#call', args]);
|
| - if (result[0] == 'throws') throw deserialize(result[1]);
|
| - return deserialize(result[1]);
|
| - };
|
| - // Cache the remote id and port.
|
| - f._dart_id = id;
|
| - f._dart_port = port;
|
| - return f;
|
| - }
|
| - }
|
| -
|
| - // Creates a DartProxy to forwards to the remote object.
|
| - function deserializeObject(message) {
|
| - var id = message[1];
|
| - var port = message[2];
|
| - // TODO(vsm): Add a more robust check for a local SendPortSync.
|
| - if ("receivePort" in port) {
|
| - // Local object.
|
| - return proxiedObjectTable.get(id);
|
| - } else {
|
| - // Remote object.
|
| - return new DartProxy(id, port);
|
| - }
|
| - }
|
| -
|
| - // Remote handler to construct a new JavaScript object given its
|
| - // serialized constructor and arguments.
|
| - function construct(args) {
|
| - args = args.map(deserialize);
|
| - var constructor = args[0];
|
| - args = Array.prototype.slice.call(args, 1);
|
| -
|
| - // Until 10 args, the 'new' operator is used. With more arguments we use a
|
| - // generic way that may not work, particularly when the constructor does not
|
| - // have an "apply" method.
|
| - var ret = null;
|
| - if (args.length === 0) {
|
| - ret = new constructor();
|
| - } else if (args.length === 1) {
|
| - ret = new constructor(args[0]);
|
| - } else if (args.length === 2) {
|
| - ret = new constructor(args[0], args[1]);
|
| - } else if (args.length === 3) {
|
| - ret = new constructor(args[0], args[1], args[2]);
|
| - } else if (args.length === 4) {
|
| - ret = new constructor(args[0], args[1], args[2], args[3]);
|
| - } else if (args.length === 5) {
|
| - ret = new constructor(args[0], args[1], args[2], args[3], args[4]);
|
| - } else if (args.length === 6) {
|
| - ret = new constructor(args[0], args[1], args[2], args[3], args[4],
|
| - args[5]);
|
| - } else if (args.length === 7) {
|
| - ret = new constructor(args[0], args[1], args[2], args[3], args[4],
|
| - args[5], args[6]);
|
| - } else if (args.length === 8) {
|
| - ret = new constructor(args[0], args[1], args[2], args[3], args[4],
|
| - args[5], args[6], args[7]);
|
| - } else if (args.length === 9) {
|
| - ret = new constructor(args[0], args[1], args[2], args[3], args[4],
|
| - args[5], args[6], args[7], args[8]);
|
| - } else if (args.length === 10) {
|
| - ret = new constructor(args[0], args[1], args[2], args[3], args[4],
|
| - args[5], args[6], args[7], args[8], args[9]);
|
| - } else {
|
| - // Dummy Type with correct constructor.
|
| - var Type = function(){};
|
| - Type.prototype = constructor.prototype;
|
| -
|
| - // Create a new instance
|
| - var instance = new Type();
|
| -
|
| - // Call the original constructor.
|
| - ret = constructor.apply(instance, args);
|
| - ret = Object(ret) === ret ? ret : instance;
|
| - }
|
| - return serialize(ret);
|
| - }
|
| -
|
| - // Remote handler to return the top-level JavaScript context.
|
| - function context(data) {
|
| - return serialize(globalContext);
|
| - }
|
| -
|
| - // Return true if a JavaScript proxy is instance of a given type (instanceof).
|
| - function proxyInstanceof(args) {
|
| - var obj = deserialize(args[0]);
|
| - var type = deserialize(args[1]);
|
| - return obj instanceof type;
|
| - }
|
| -
|
| - // Return true if a JavaScript proxy is instance of a given type (instanceof).
|
| - function proxyDeleteProperty(args) {
|
| - var obj = deserialize(args[0]);
|
| - var member = deserialize(args[1]);
|
| - delete obj[member];
|
| - }
|
| -
|
| - function proxyConvert(args) {
|
| - return serialize(deserializeDataTree(args));
|
| - }
|
| -
|
| - function deserializeDataTree(data) {
|
| - var type = data[0];
|
| - var value = data[1];
|
| - if (type === 'map') {
|
| - var obj = {};
|
| - for (var i = 0; i < value.length; i++) {
|
| - obj[value[i][0]] = deserializeDataTree(value[i][1]);
|
| - }
|
| - return obj;
|
| - } else if (type === 'list') {
|
| - var list = [];
|
| - for (var i = 0; i < value.length; i++) {
|
| - list.push(deserializeDataTree(value[i]));
|
| - }
|
| - return list;
|
| - } else /* 'simple' */ {
|
| - return deserialize(value);
|
| - }
|
| - }
|
| -
|
| - function makeGlobalPort(name, f) {
|
| - var port = new ReceivePortSync();
|
| - port.receive(f);
|
| - window.registerPort(name, port.toSendPort());
|
| - }
|
| -
|
| - makeGlobalPort('dart-js-context', context);
|
| - makeGlobalPort('dart-js-create', construct);
|
| - makeGlobalPort('dart-js-instanceof', proxyInstanceof);
|
| - makeGlobalPort('dart-js-delete-property', proxyDeleteProperty);
|
| - makeGlobalPort('dart-js-convert', proxyConvert);
|
| -})();
|
|
|