forked from cory/tildefriends
All of the changes that have been sitting on tildepi for ages. For posterity.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3530 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
137
packages/cory/libiframe/libiframe.js
Normal file
137
packages/cory/libiframe/libiframe.js
Normal file
@ -0,0 +1,137 @@
|
||||
"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,
|
||||
});
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user