forked from cory/tildefriends
137 lines
3.3 KiB
JavaScript
137 lines
3.3 KiB
JavaScript
|
"use strict";
|
||
|
|
||
|
//! {"category": "libraries"}
|
||
|
|
||
|
const kRpcSource = `
|
||
|
class RPC {
|
||
|
constructor() {
|
||
|
this._functions = [];
|
||
|
this.exports = null;
|
||
|
this.sendCallback = null;
|
||
|
}
|
||
|
|
||
|
export(functions) {
|
||
|
return this._send(["export", functions]);
|
||
|
}
|
||
|
|
||
|
_call(index) {
|
||
|
return this._send(["call", index, Array.prototype.slice.call(arguments, 1)]);
|
||
|
}
|
||
|
|
||
|
_send(message) {
|
||
|
var serialized = this._serialize(message);
|
||
|
if (this.sendCallback) {
|
||
|
return this.sendCallback(serialized);
|
||
|
}
|
||
|
return serialized;
|
||
|
}
|
||
|
|
||
|
deliver(message) {
|
||
|
var deserialized = this._deserialize(message);
|
||
|
if (deserialized[0] == "export") {
|
||
|
this.exports = deserialized[1];
|
||
|
} else if (deserialized[0] == "call") {
|
||
|
var f = this._functions[deserialized[1]];
|
||
|
f.apply(null, deserialized[2]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_deserialize(data) {
|
||
|
var result = null;
|
||
|
if (data[0] == "array") {
|
||
|
result = new Array(data[1].length);
|
||
|
for (var i = 0; i < data[1].length; i++) {
|
||
|
result[i] = this._deserialize(data[1][i]);
|
||
|
}
|
||
|
} else if (data[0] == "object") {
|
||
|
result = {};
|
||
|
for (var i in data[1]) {
|
||
|
result[i] = this._deserialize(data[1][i]);
|
||
|
}
|
||
|
} else if (data[0] == "number" || data[0] == "boolean" || data[0] == "string") {
|
||
|
result = data[1];
|
||
|
} else if (data[0] == "function") {
|
||
|
result = this._call.bind(this, data[1]);
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
_serialize(data) {
|
||
|
var result = null;
|
||
|
if (Array.isArray(data)) {
|
||
|
result = ["array", data.map(x => this._serialize(x, this.functions))];
|
||
|
} else if (typeof data == "function") {
|
||
|
var index = this._functions.indexOf(data);
|
||
|
if (index == -1) {
|
||
|
index = this._functions.length;
|
||
|
this._functions.push(data);
|
||
|
}
|
||
|
result = ["function", index];
|
||
|
} else if (typeof data == "object") {
|
||
|
var fields = {};
|
||
|
while (data) {
|
||
|
var own = Object.getOwnPropertyNames(data);
|
||
|
for (var i = 0; i < own.length; i++) {
|
||
|
var name = own[i];
|
||
|
if (name != "constructor") {
|
||
|
var descriptor = Object.getOwnPropertyDescriptor(data, name);
|
||
|
if (descriptor&& typeof descriptor.value == "function") {
|
||
|
fields[name] = this._serialize(descriptor.value, this.functions);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (data.__proto__ == Object.prototype) {
|
||
|
break;
|
||
|
}
|
||
|
data = Object.getPrototypeOf(data);
|
||
|
}
|
||
|
result = ["object", fields];
|
||
|
} else {
|
||
|
result = [typeof data, data];
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
}`
|
||
|
|
||
|
exports.iframe = function(options) {
|
||
|
return new Promise(function(resolve, reject) {
|
||
|
var iframeName = options.name || "iframe";
|
||
|
var RPC = eval(kRpcSource);
|
||
|
var rpc = new RPC();
|
||
|
rpc.sendCallback = terminal.postMessageToIframe.bind(null, iframeName);
|
||
|
|
||
|
core.register("onWindowMessage", function(message) {
|
||
|
if (message.message == "ready") {
|
||
|
resolve(rpc.exports);
|
||
|
} else {
|
||
|
rpc.deliver(message.message);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
terminal.split([{name: "terminal", type: "vertical"}]);
|
||
|
terminal.print({
|
||
|
iframe: `
|
||
|
<!DOCTYPE html>
|
||
|
<body style="background-color: #fff"></body>
|
||
|
<script language="javascript">
|
||
|
${kRpcSource}
|
||
|
window.addEventListener("load", function() {
|
||
|
parent.postMessage("ready", "*");
|
||
|
});
|
||
|
let rpc = new RPC();
|
||
|
window.addEventListener("message", function(event) {
|
||
|
rpc.deliver(event.data);
|
||
|
});
|
||
|
rpc.sendCallback = function(data) {
|
||
|
parent.postMessage(data, "*");
|
||
|
}
|
||
|
${options.source}
|
||
|
</script>
|
||
|
`,
|
||
|
name: iframeName,
|
||
|
style: "flex: 1 1; " + options.style,
|
||
|
width: null,
|
||
|
height: null,
|
||
|
});
|
||
|
});
|
||
|
}
|