| OLD | NEW | 
|    1 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file |    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 |    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. |    3 // BSD-style license that can be found in the LICENSE file. | 
|    4  |    4  | 
|    5 // --------------------------------------------------------------------------- |    5 // TODO(jmesserly): remove this script after a deprecation period. | 
|    6 // Support for JS interoperability |    6 if (typeof console == "object" && typeof console.warn == "function") { | 
|    7 // --------------------------------------------------------------------------- |    7   console.warn('<script src="packages/browser/interop.js"> is no longer ' + | 
|    8 function SendPortSync() { |    8       'needed for dart:js. See http://pub.dartlang.org/packages/browser.'); | 
|    9 } |    9 } | 
|   10  |  | 
|   11 function ReceivePortSync() { |  | 
|   12   this.id = ReceivePortSync.id++; |  | 
|   13   ReceivePortSync.map[this.id] = this; |  | 
|   14 } |  | 
|   15  |  | 
|   16 // Type for remote proxies to Dart objects with dart2js. |  | 
|   17 function DartProxy(o) { |  | 
|   18   this.o = o; |  | 
|   19 } |  | 
|   20  |  | 
|   21 (function() { |  | 
|   22   // Serialize the following types as follows: |  | 
|   23   //  - primitives / null: unchanged |  | 
|   24   //  - lists: [ 'list', internal id, list of recursively serialized elements ] |  | 
|   25   //  - maps: [ 'map', internal id, map of keys and recursively serialized value
     s ] |  | 
|   26   //  - send ports: [ 'sendport', type, isolate id, port id ] |  | 
|   27   // |  | 
|   28   // Note, internal id's are for cycle detection. |  | 
|   29   function serialize(message) { |  | 
|   30     var visited = []; |  | 
|   31     function checkedSerialization(obj, serializer) { |  | 
|   32       // Implementation detail: for now use linear search. |  | 
|   33       // Another option is expando, but it may prohibit |  | 
|   34       // VM optimizations (like putting object into slow mode |  | 
|   35       // on property deletion.) |  | 
|   36       var id = visited.indexOf(obj); |  | 
|   37       if (id != -1) return [ 'ref', id ]; |  | 
|   38       var id = visited.length; |  | 
|   39       visited.push(obj); |  | 
|   40       return serializer(id); |  | 
|   41     } |  | 
|   42  |  | 
|   43     function doSerialize(message) { |  | 
|   44       if (message == null) { |  | 
|   45         return null;  // Convert undefined to null. |  | 
|   46       } else if (typeof(message) == 'string' || |  | 
|   47                  typeof(message) == 'number' || |  | 
|   48                  typeof(message) == 'boolean') { |  | 
|   49         return message; |  | 
|   50       } else if (message instanceof Array) { |  | 
|   51         return checkedSerialization(message, function(id) { |  | 
|   52           var values = new Array(message.length); |  | 
|   53           for (var i = 0; i < message.length; i++) { |  | 
|   54             values[i] = doSerialize(message[i]); |  | 
|   55           } |  | 
|   56           return [ 'list', id, values ]; |  | 
|   57         }); |  | 
|   58       } else if (message instanceof LocalSendPortSync) { |  | 
|   59         return [ 'sendport', 'nativejs', message.receivePort.id ]; |  | 
|   60       } else if (message instanceof DartSendPortSync) { |  | 
|   61         return [ 'sendport', 'dart', message.isolateId, message.portId ]; |  | 
|   62       } else { |  | 
|   63         return checkedSerialization(message, function(id) { |  | 
|   64           var keys = Object.getOwnPropertyNames(message); |  | 
|   65           var values = new Array(keys.length); |  | 
|   66           for (var i = 0; i < keys.length; i++) { |  | 
|   67             values[i] = doSerialize(message[keys[i]]); |  | 
|   68           } |  | 
|   69           return [ 'map', id, keys, values ]; |  | 
|   70         }); |  | 
|   71       } |  | 
|   72     } |  | 
|   73     return doSerialize(message); |  | 
|   74   } |  | 
|   75  |  | 
|   76   function deserialize(message) { |  | 
|   77     return deserializeHelper(message); |  | 
|   78   } |  | 
|   79  |  | 
|   80   function deserializeHelper(message) { |  | 
|   81     if (message == null || |  | 
|   82         typeof(message) == 'string' || |  | 
|   83         typeof(message) == 'number' || |  | 
|   84         typeof(message) == 'boolean') { |  | 
|   85       return message; |  | 
|   86     } |  | 
|   87     switch (message[0]) { |  | 
|   88       case 'map': return deserializeMap(message); |  | 
|   89       case 'sendport': return deserializeSendPort(message); |  | 
|   90       case 'list': return deserializeList(message); |  | 
|   91       default: throw 'unimplemented'; |  | 
|   92     } |  | 
|   93   } |  | 
|   94  |  | 
|   95   function deserializeMap(message) { |  | 
|   96     var result = { }; |  | 
|   97     var id = message[1]; |  | 
|   98     var keys = message[2]; |  | 
|   99     var values = message[3]; |  | 
|  100     for (var i = 0, length = keys.length; i < length; i++) { |  | 
|  101       var key = deserializeHelper(keys[i]); |  | 
|  102       var value = deserializeHelper(values[i]); |  | 
|  103       result[key] = value; |  | 
|  104     } |  | 
|  105     return result; |  | 
|  106   } |  | 
|  107  |  | 
|  108   function deserializeSendPort(message) { |  | 
|  109     var tag = message[1]; |  | 
|  110     switch (tag) { |  | 
|  111       case 'nativejs': |  | 
|  112         var id = message[2]; |  | 
|  113         return new LocalSendPortSync(ReceivePortSync.map[id]); |  | 
|  114       case 'dart': |  | 
|  115         var isolateId = message[2]; |  | 
|  116         var portId = message[3]; |  | 
|  117         return new DartSendPortSync(isolateId, portId); |  | 
|  118       default: |  | 
|  119         throw 'Illegal SendPortSync type: $tag'; |  | 
|  120     } |  | 
|  121   } |  | 
|  122  |  | 
|  123   function deserializeList(message) { |  | 
|  124     var values = message[2]; |  | 
|  125     var length = values.length; |  | 
|  126     var result = new Array(length); |  | 
|  127     for (var i = 0; i < length; i++) { |  | 
|  128       result[i] = deserializeHelper(values[i]); |  | 
|  129     } |  | 
|  130     return result; |  | 
|  131   } |  | 
|  132  |  | 
|  133   window.registerPort = function(name, port) { |  | 
|  134     var stringified = JSON.stringify(serialize(port)); |  | 
|  135     var attrName = 'dart-port:' + name; |  | 
|  136     document.documentElement.setAttribute(attrName, stringified); |  | 
|  137   }; |  | 
|  138  |  | 
|  139   window.lookupPort = function(name) { |  | 
|  140     var attrName = 'dart-port:' + name; |  | 
|  141     var stringified = document.documentElement.getAttribute(attrName); |  | 
|  142     return deserialize(JSON.parse(stringified)); |  | 
|  143   }; |  | 
|  144  |  | 
|  145   ReceivePortSync.id = 0; |  | 
|  146   ReceivePortSync.map = {}; |  | 
|  147  |  | 
|  148   ReceivePortSync.dispatchCall = function(id, message) { |  | 
|  149     // TODO(vsm): Handle and propagate exceptions. |  | 
|  150     var deserialized = deserialize(message); |  | 
|  151     var result = ReceivePortSync.map[id].callback(deserialized); |  | 
|  152     return serialize(result); |  | 
|  153   }; |  | 
|  154  |  | 
|  155   ReceivePortSync.prototype.receive = function(callback) { |  | 
|  156     this.callback = callback; |  | 
|  157   }; |  | 
|  158  |  | 
|  159   ReceivePortSync.prototype.toSendPort = function() { |  | 
|  160     return new LocalSendPortSync(this); |  | 
|  161   }; |  | 
|  162  |  | 
|  163   ReceivePortSync.prototype.close = function() { |  | 
|  164     delete ReceivePortSync.map[this.id]; |  | 
|  165   }; |  | 
|  166  |  | 
|  167   if (navigator.webkitStartDart) { |  | 
|  168     window.addEventListener('js-sync-message', function(event) { |  | 
|  169       var data = JSON.parse(getPortSyncEventData(event)); |  | 
|  170       var deserialized = deserialize(data.message); |  | 
|  171       var result = ReceivePortSync.map[data.id].callback(deserialized); |  | 
|  172       // TODO(vsm): Handle and propagate exceptions. |  | 
|  173       dispatchEvent('js-result', serialize(result)); |  | 
|  174     }, false); |  | 
|  175   } |  | 
|  176  |  | 
|  177   function LocalSendPortSync(receivePort) { |  | 
|  178     this.receivePort = receivePort; |  | 
|  179   } |  | 
|  180  |  | 
|  181   LocalSendPortSync.prototype = new SendPortSync(); |  | 
|  182  |  | 
|  183   LocalSendPortSync.prototype.callSync = function(message) { |  | 
|  184     // TODO(vsm): Do a direct deepcopy. |  | 
|  185     message = deserialize(serialize(message)); |  | 
|  186     return this.receivePort.callback(message); |  | 
|  187   } |  | 
|  188  |  | 
|  189   function DartSendPortSync(isolateId, portId) { |  | 
|  190     this.isolateId = isolateId; |  | 
|  191     this.portId = portId; |  | 
|  192   } |  | 
|  193  |  | 
|  194   DartSendPortSync.prototype = new SendPortSync(); |  | 
|  195  |  | 
|  196   function dispatchEvent(receiver, message) { |  | 
|  197     var string = JSON.stringify(message); |  | 
|  198     var event = document.createEvent('CustomEvent'); |  | 
|  199     event.initCustomEvent(receiver, false, false, string); |  | 
|  200     window.dispatchEvent(event); |  | 
|  201   } |  | 
|  202  |  | 
|  203   function getPortSyncEventData(event) { |  | 
|  204     return event.detail; |  | 
|  205   } |  | 
|  206  |  | 
|  207   DartSendPortSync.prototype.callSync = function(message) { |  | 
|  208     var serialized = serialize(message); |  | 
|  209     var target = 'dart-port-' + this.isolateId + '-' + this.portId; |  | 
|  210     // TODO(vsm): Make this re-entrant. |  | 
|  211     // TODO(vsm): Set this up set once, on the first call. |  | 
|  212     var source = target + '-result'; |  | 
|  213     var result = null; |  | 
|  214     var listener = function (e) { |  | 
|  215       result = JSON.parse(getPortSyncEventData(e)); |  | 
|  216     }; |  | 
|  217     window.addEventListener(source, listener, false); |  | 
|  218     dispatchEvent(target, [source, serialized]); |  | 
|  219     window.removeEventListener(source, listener, false); |  | 
|  220     return deserialize(result); |  | 
|  221   } |  | 
|  222 })(); |  | 
|  223  |  | 
|  224 (function() { |  | 
|  225   // Proxy support for js.dart. |  | 
|  226  |  | 
|  227   // We don't use 'window' because we might be in a web worker, but we don't |  | 
|  228   // use 'self' because not all browsers support it |  | 
|  229   var globalContext = function() { return this; }(); |  | 
|  230  |  | 
|  231   // Table for local objects and functions that are proxied. |  | 
|  232   function ProxiedObjectTable() { |  | 
|  233     // Name for debugging. |  | 
|  234     this.name = 'js-ref'; |  | 
|  235  |  | 
|  236     // Table from IDs to JS objects. |  | 
|  237     this.map = {}; |  | 
|  238  |  | 
|  239     // Generator for new IDs. |  | 
|  240     this._nextId = 0; |  | 
|  241  |  | 
|  242     // Ports for managing communication to proxies. |  | 
|  243     this.port = new ReceivePortSync(); |  | 
|  244     this.sendPort = this.port.toSendPort(); |  | 
|  245   } |  | 
|  246  |  | 
|  247   // Number of valid IDs.  This is the number of objects (global and local) |  | 
|  248   // kept alive by this table. |  | 
|  249   ProxiedObjectTable.prototype.count = function () { |  | 
|  250     return Object.keys(this.map).length; |  | 
|  251   } |  | 
|  252  |  | 
|  253   // Adds an object to the table and return an ID for serialization. |  | 
|  254   ProxiedObjectTable.prototype.add = function (obj) { |  | 
|  255     for (var ref in this.map) { |  | 
|  256       var o = this.map[ref]; |  | 
|  257       if (o === obj) { |  | 
|  258         return ref; |  | 
|  259       } |  | 
|  260     } |  | 
|  261     var ref = this.name + '-' + this._nextId++; |  | 
|  262     this.map[ref] = obj; |  | 
|  263     return ref; |  | 
|  264   } |  | 
|  265  |  | 
|  266   // Gets the object or function corresponding to this ID. |  | 
|  267   ProxiedObjectTable.prototype.get = function (id) { |  | 
|  268     if (!this.map.hasOwnProperty(id)) { |  | 
|  269       throw 'Proxy ' + id + ' has been invalidated.' |  | 
|  270     } |  | 
|  271     return this.map[id]; |  | 
|  272   } |  | 
|  273  |  | 
|  274   ProxiedObjectTable.prototype._initialize = function () { |  | 
|  275     // Configure this table's port to forward methods, getters, and setters |  | 
|  276     // from the remote proxy to the local object. |  | 
|  277     var table = this; |  | 
|  278  |  | 
|  279     this.port.receive(function (message) { |  | 
|  280       // TODO(vsm): Support a mechanism to register a handler here. |  | 
|  281       try { |  | 
|  282         var receiver = table.get(message[0]); |  | 
|  283         var member = message[1]; |  | 
|  284         var kind = message[2]; |  | 
|  285         var args = message[3].map(deserialize); |  | 
|  286         if (kind == 'get') { |  | 
|  287           // Getter. |  | 
|  288           var field = member; |  | 
|  289           if (field in receiver && args.length == 0) { |  | 
|  290             return [ 'return', serialize(receiver[field]) ]; |  | 
|  291           } |  | 
|  292         } else if (kind == 'set') { |  | 
|  293           // Setter. |  | 
|  294           var field = member; |  | 
|  295           if (args.length == 1) { |  | 
|  296             return [ 'return', serialize(receiver[field] = args[0]) ]; |  | 
|  297           } |  | 
|  298         } else if (kind == 'hasProperty') { |  | 
|  299           var field = member; |  | 
|  300           return [ 'return', field in receiver ]; |  | 
|  301         } else if (kind == 'apply') { |  | 
|  302           // Direct function invocation. |  | 
|  303           return [ 'return', |  | 
|  304               serialize(receiver.apply(args[0], args.slice(1))) ]; |  | 
|  305         } else if (member == '[]' && args.length == 1) { |  | 
|  306           // Index getter. |  | 
|  307           return [ 'return', serialize(receiver[args[0]]) ]; |  | 
|  308         } else if (member == '[]=' && args.length == 2) { |  | 
|  309           // Index setter. |  | 
|  310           return [ 'return', serialize(receiver[args[0]] = args[1]) ]; |  | 
|  311         } else { |  | 
|  312           // Member function invocation. |  | 
|  313           var f = receiver[member]; |  | 
|  314           if (f) { |  | 
|  315             var result = f.apply(receiver, args); |  | 
|  316             return [ 'return', serialize(result) ]; |  | 
|  317           } |  | 
|  318         } |  | 
|  319         return [ 'none' ]; |  | 
|  320       } catch (e) { |  | 
|  321         return [ 'throws', e.toString() ]; |  | 
|  322       } |  | 
|  323     }); |  | 
|  324   } |  | 
|  325  |  | 
|  326   // Singleton for local proxied objects. |  | 
|  327   var proxiedObjectTable = new ProxiedObjectTable(); |  | 
|  328   proxiedObjectTable._initialize() |  | 
|  329  |  | 
|  330   // Type for remote proxies to Dart objects. |  | 
|  331   function DartProxy(id, sendPort) { |  | 
|  332     this.id = id; |  | 
|  333     this.port = sendPort; |  | 
|  334   } |  | 
|  335  |  | 
|  336   // Serializes JS types to SendPortSync format: |  | 
|  337   // - primitives -> primitives |  | 
|  338   // - sendport -> sendport |  | 
|  339   // - Function -> [ 'funcref', function-id, sendport ] |  | 
|  340   // - Object -> [ 'objref', object-id, sendport ] |  | 
|  341   function serialize(message) { |  | 
|  342     if (message == null) { |  | 
|  343       return null;  // Convert undefined to null. |  | 
|  344     } else if (typeof(message) == 'string' || |  | 
|  345                typeof(message) == 'number' || |  | 
|  346                typeof(message) == 'boolean') { |  | 
|  347       // Primitives are passed directly through. |  | 
|  348       return message; |  | 
|  349     } else if (message instanceof SendPortSync) { |  | 
|  350       // Non-proxied objects are serialized. |  | 
|  351       return message; |  | 
|  352     } else if (typeof(message) == 'function') { |  | 
|  353       if ('_dart_id' in message) { |  | 
|  354         // Remote function proxy. |  | 
|  355         var remoteId = message._dart_id; |  | 
|  356         var remoteSendPort = message._dart_port; |  | 
|  357         return [ 'funcref', remoteId, remoteSendPort ]; |  | 
|  358       } else { |  | 
|  359         // Local function proxy. |  | 
|  360         return [ 'funcref', |  | 
|  361                  proxiedObjectTable.add(message), |  | 
|  362                  proxiedObjectTable.sendPort ]; |  | 
|  363       } |  | 
|  364     } else if (message instanceof DartProxy) { |  | 
|  365       // Remote object proxy. |  | 
|  366       return [ 'objref', message.id, message.port ]; |  | 
|  367     } else { |  | 
|  368       // Local object proxy. |  | 
|  369       return [ 'objref', |  | 
|  370                proxiedObjectTable.add(message), |  | 
|  371                proxiedObjectTable.sendPort ]; |  | 
|  372     } |  | 
|  373   } |  | 
|  374  |  | 
|  375   function deserialize(message) { |  | 
|  376     if (message == null) { |  | 
|  377       return null;  // Convert undefined to null. |  | 
|  378     } else if (typeof(message) == 'string' || |  | 
|  379                typeof(message) == 'number' || |  | 
|  380                typeof(message) == 'boolean') { |  | 
|  381       // Primitives are passed directly through. |  | 
|  382       return message; |  | 
|  383     } else if (message instanceof SendPortSync) { |  | 
|  384       // Serialized type. |  | 
|  385       return message; |  | 
|  386     } |  | 
|  387     var tag = message[0]; |  | 
|  388     switch (tag) { |  | 
|  389       case 'funcref': return deserializeFunction(message); |  | 
|  390       case 'objref': return deserializeObject(message); |  | 
|  391     } |  | 
|  392     throw 'Unsupported serialized data: ' + message; |  | 
|  393   } |  | 
|  394  |  | 
|  395   // Create a local function that forwards to the remote function. |  | 
|  396   function deserializeFunction(message) { |  | 
|  397     var id = message[1]; |  | 
|  398     var port = message[2]; |  | 
|  399     // TODO(vsm): Add a more robust check for a local SendPortSync. |  | 
|  400     if ("receivePort" in port) { |  | 
|  401       // Local function. |  | 
|  402       return proxiedObjectTable.get(id); |  | 
|  403     } else { |  | 
|  404       // Remote function.  Forward to its port. |  | 
|  405       var f = function () { |  | 
|  406         var args = Array.prototype.slice.apply(arguments); |  | 
|  407         args.splice(0, 0, this); |  | 
|  408         args = args.map(serialize); |  | 
|  409         var result = port.callSync([id, '#call', args]); |  | 
|  410         if (result[0] == 'throws') throw deserialize(result[1]); |  | 
|  411         return deserialize(result[1]); |  | 
|  412       }; |  | 
|  413       // Cache the remote id and port. |  | 
|  414       f._dart_id = id; |  | 
|  415       f._dart_port = port; |  | 
|  416       return f; |  | 
|  417     } |  | 
|  418   } |  | 
|  419  |  | 
|  420   // Creates a DartProxy to forwards to the remote object. |  | 
|  421   function deserializeObject(message) { |  | 
|  422     var id = message[1]; |  | 
|  423     var port = message[2]; |  | 
|  424     // TODO(vsm): Add a more robust check for a local SendPortSync. |  | 
|  425     if ("receivePort" in port) { |  | 
|  426       // Local object. |  | 
|  427       return proxiedObjectTable.get(id); |  | 
|  428     } else { |  | 
|  429       // Remote object. |  | 
|  430       return new DartProxy(id, port); |  | 
|  431     } |  | 
|  432   } |  | 
|  433  |  | 
|  434   // Remote handler to construct a new JavaScript object given its |  | 
|  435   // serialized constructor and arguments. |  | 
|  436   function construct(args) { |  | 
|  437     args = args.map(deserialize); |  | 
|  438     var constructor = args[0]; |  | 
|  439     args = Array.prototype.slice.call(args, 1); |  | 
|  440  |  | 
|  441     // Until 10 args, the 'new' operator is used. With more arguments we use a |  | 
|  442     // generic way that may not work, particularly when the constructor does not |  | 
|  443     // have an "apply" method. |  | 
|  444     var ret = null; |  | 
|  445     if (args.length === 0) { |  | 
|  446       ret = new constructor(); |  | 
|  447     } else if (args.length === 1) { |  | 
|  448       ret = new constructor(args[0]); |  | 
|  449     } else if (args.length === 2) { |  | 
|  450       ret = new constructor(args[0], args[1]); |  | 
|  451     } else if (args.length === 3) { |  | 
|  452       ret = new constructor(args[0], args[1], args[2]); |  | 
|  453     } else if (args.length === 4) { |  | 
|  454       ret = new constructor(args[0], args[1], args[2], args[3]); |  | 
|  455     } else if (args.length === 5) { |  | 
|  456       ret = new constructor(args[0], args[1], args[2], args[3], args[4]); |  | 
|  457     } else if (args.length === 6) { |  | 
|  458       ret = new constructor(args[0], args[1], args[2], args[3], args[4], |  | 
|  459                             args[5]); |  | 
|  460     } else if (args.length === 7) { |  | 
|  461       ret = new constructor(args[0], args[1], args[2], args[3], args[4], |  | 
|  462                             args[5], args[6]); |  | 
|  463     } else if (args.length === 8) { |  | 
|  464       ret = new constructor(args[0], args[1], args[2], args[3], args[4], |  | 
|  465                             args[5], args[6], args[7]); |  | 
|  466     } else if (args.length === 9) { |  | 
|  467       ret = new constructor(args[0], args[1], args[2], args[3], args[4], |  | 
|  468                             args[5], args[6], args[7], args[8]); |  | 
|  469     } else if (args.length === 10) { |  | 
|  470       ret = new constructor(args[0], args[1], args[2], args[3], args[4], |  | 
|  471                             args[5], args[6], args[7], args[8], args[9]); |  | 
|  472     } else { |  | 
|  473       // Dummy Type with correct constructor. |  | 
|  474       var Type = function(){}; |  | 
|  475       Type.prototype = constructor.prototype; |  | 
|  476  |  | 
|  477       // Create a new instance |  | 
|  478       var instance = new Type(); |  | 
|  479  |  | 
|  480       // Call the original constructor. |  | 
|  481       ret = constructor.apply(instance, args); |  | 
|  482       ret = Object(ret) === ret ? ret : instance; |  | 
|  483     } |  | 
|  484     return serialize(ret); |  | 
|  485   } |  | 
|  486  |  | 
|  487   // Remote handler to return the top-level JavaScript context. |  | 
|  488   function context(data) { |  | 
|  489     return serialize(globalContext); |  | 
|  490   } |  | 
|  491  |  | 
|  492   // Return true if a JavaScript proxy is instance of a given type (instanceof). |  | 
|  493   function proxyInstanceof(args) { |  | 
|  494     var obj = deserialize(args[0]); |  | 
|  495     var type = deserialize(args[1]); |  | 
|  496     return obj instanceof type; |  | 
|  497   } |  | 
|  498  |  | 
|  499   // Return true if a JavaScript proxy is instance of a given type (instanceof). |  | 
|  500   function proxyDeleteProperty(args) { |  | 
|  501     var obj = deserialize(args[0]); |  | 
|  502     var member = deserialize(args[1]); |  | 
|  503     delete obj[member]; |  | 
|  504   } |  | 
|  505  |  | 
|  506   function proxyConvert(args) { |  | 
|  507     return serialize(deserializeDataTree(args)); |  | 
|  508   } |  | 
|  509  |  | 
|  510   function deserializeDataTree(data) { |  | 
|  511     var type = data[0]; |  | 
|  512     var value = data[1]; |  | 
|  513     if (type === 'map') { |  | 
|  514       var obj = {}; |  | 
|  515       for (var i = 0; i < value.length; i++) { |  | 
|  516         obj[value[i][0]] = deserializeDataTree(value[i][1]); |  | 
|  517       } |  | 
|  518       return obj; |  | 
|  519     } else if (type === 'list') { |  | 
|  520       var list = []; |  | 
|  521       for (var i = 0; i < value.length; i++) { |  | 
|  522         list.push(deserializeDataTree(value[i])); |  | 
|  523       } |  | 
|  524       return list; |  | 
|  525     } else /* 'simple' */ { |  | 
|  526       return deserialize(value); |  | 
|  527     } |  | 
|  528   } |  | 
|  529  |  | 
|  530   function makeGlobalPort(name, f) { |  | 
|  531     var port = new ReceivePortSync(); |  | 
|  532     port.receive(f); |  | 
|  533     window.registerPort(name, port.toSendPort()); |  | 
|  534   } |  | 
|  535  |  | 
|  536   makeGlobalPort('dart-js-context', context); |  | 
|  537   makeGlobalPort('dart-js-create', construct); |  | 
|  538   makeGlobalPort('dart-js-instanceof', proxyInstanceof); |  | 
|  539   makeGlobalPort('dart-js-delete-property', proxyDeleteProperty); |  | 
|  540   makeGlobalPort('dart-js-convert', proxyConvert); |  | 
|  541 })(); |  | 
| OLD | NEW |