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

Side by Side Diff: src/site/codelabs/darrrt/examples/packages/browser/interop.js

Issue 339243004: Update generated JS for codelab's pirate app. (Closed) Base URL: https://github.com/dart-lang/dartlang.org.git@master
Patch Set: Created 6 years, 6 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
OLDNEW
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 })();
OLDNEW
« no previous file with comments | « src/site/codelabs/darrrt/examples/packages/browser/dart.js ('k') | src/site/codelabs/darrrt/examples/piratebadge.css » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698