dart-sdk/client/dart.js
vsm@google.com 95e272386c Use userAgent instead of webkitStartDart
This modifies our browser package and test scripts to use the
userAgent instead of webkitStartDart (which is gone) to determine if
we have native dart support.

I'm TBR-ing to get rid of a ton of warnings on the Dartium bots (they
are trying to run both native tests (successfully) and compiled-to-js
tests (warning no js file)).

E.g., see HttpServer warnings on this otherwise green run:

http://chromegw.corp.google.com/i/client.dart/builders/dartium-mac-inc-be/builds/634/steps/drt_core_checked_tests/logs/stdio

Siggi: you have comments elsewhere around removing/refactoring when
webkitStartDart is gone.  They are still there.

TBR=sigmund@google.com,ricow@google.com

Review URL: https://codereview.chromium.org//52023002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@29515 260f80e4-7a28-3924-810f-c04153c831b5
2013-10-30 04:08:39 +00:00

265 lines
8.7 KiB
JavaScript

// Copyright (c) 2012, 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.
var warning = [
'WARNING: This page is using a deprecated dart.js file. ',
'Please update this page as described here: ',
'http://news.dartlang.org/2013/01/big-breaking-change-dartjs-bootstrap-file-moving-to-pub.html'
].join('');
console.error(warning);
// Bootstrap support for Dart scripts on the page as this script.
if (navigator.userAgent.indexOf('(Dart)') === -1) {
// TODO:
// - Support in-browser compilation.
// - Handle inline Dart scripts.
window.addEventListener("DOMContentLoaded", function (e) {
// Fall back to compiled JS. Run through all the scripts and
// replace them if they have a type that indicate that they source
// in Dart code.
//
// <script type="application/dart" src="..."></script>
//
var scripts = document.getElementsByTagName("script");
var length = scripts.length;
for (var i = 0; i < length; ++i) {
if (scripts[i].type == "application/dart") {
// Remap foo.dart to foo.dart.js.
if (scripts[i].src && scripts[i].src != '') {
var script = document.createElement('script');
script.src = scripts[i].src + '.js';
var parent = scripts[i].parentNode;
parent.replaceChild(script, scripts[i]);
}
}
}
}, false);
}
// ---------------------------------------------------------------------------
// Experimental support for JS interoperability
// ---------------------------------------------------------------------------
function SendPortSync() {
}
function ReceivePortSync() {
this.id = ReceivePortSync.id++;
ReceivePortSync.map[this.id] = this;
}
(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);
// TODO(vsm): Phase out usage of localStorage and delete the
// below. We're leaving it in temporarily for backwards
// compatibility.
try {
window.localStorage[attrName] = stringified;
} catch (e) {
// Swallow errors (e.g., Chrome apps disallow this access).
}
};
window.lookupPort = function(name) {
var attrName = 'dart-port:' + name;
var stringified = document.documentElement.getAttribute(attrName);
// TODO(vsm): Phase out usage of localStorage. We're leaving it in
// temporarily for backwards compatibility.
if (!stringified) {
stringified = window.localStorage[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.userAgent.indexOf('(Dart)') !== -1) {
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);
}
})();