Files
owl/playground/src/app.js
T

293 lines
7.8 KiB
JavaScript
Raw Normal View History

2019-03-28 17:31:25 +01:00
import { SAMPLES } from "./samples.js";
2019-04-26 14:01:47 +02:00
let owlJS;
async function owlSourceCode() {
if (owlJS) {
return owlJS;
}
const result = await fetch("/playground/libs/owl.js");
owlJS = await result.text();
return owlJS;
}
2019-03-28 17:31:25 +01:00
const MODES = {
js: "ace/mode/javascript",
css: "ace/mode/css",
xml: "ace/mode/xml"
};
2019-03-29 15:35:09 +01:00
const DEFAULT_XML = `<templates>
</templates>`;
2019-04-26 14:01:47 +02:00
const DEFAULT_HTML = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>OWL App</title>
<link rel="icon" href="data:,">
<script src="owl.js"></script>
<link rel="stylesheet" href="app.css">
<script type="module" src="app.js"></script>
</head>
<body>
</body>
</html>
`;
2019-03-31 09:35:03 +02:00
//------------------------------------------------------------------------------
// Tabbed editor
//------------------------------------------------------------------------------
class TabbedEditor extends owl.Component {
2019-03-31 09:35:03 +02:00
constructor() {
super(...arguments);
this.template = "tabbed-editor";
2019-03-31 09:35:03 +02:00
this.state = {
2019-03-31 22:37:04 +02:00
currentTab: this.props.display.split("|")[0]
};
this.tabs = {
js: this.props.display.includes("js"),
xml: this.props.display.includes("xml"),
css: this.props.display.includes("css")
2019-03-31 09:35:03 +02:00
};
}
mounted() {
this.editor = ace.edit(this.refs.editor);
// remove this for xml/css (?)
this.editor.session.setOption("useWorker", false);
2019-03-31 22:37:04 +02:00
this.editor.setValue(this.props[this.state.currentTab], -1);
this.editor.setFontSize("13px");
2019-03-31 09:35:03 +02:00
this.editor.setTheme("ace/theme/monokai");
this.editor.session.setMode(MODES[this.state.currentTab]);
2019-04-17 12:48:54 +02:00
const tabSize = this.state.currentTab === "xml" ? 2 : 4;
this.editor.session.setOption("tabSize", tabSize);
2019-03-31 09:35:03 +02:00
this.editor.on("blur", () => {
const editorValue = this.editor.getValue();
const propsValue = this.props[this.state.currentTab];
if (editorValue !== propsValue) {
this.trigger("updateCode", {
type: this.state.currentTab,
value: editorValue
});
}
});
}
2019-04-09 14:02:43 +02:00
patched() {
2019-03-31 09:35:03 +02:00
if (this.editor) {
window.dispatchEvent(new Event("resize"));
2019-03-31 09:35:03 +02:00
this.editor.setValue(this.props[this.state.currentTab], -1);
}
}
willUnmount() {
this.editor.destroy();
delete this.editor;
}
setTab(tab) {
this.editor.setValue(this.props[tab], -1);
const mode = MODES[tab];
this.editor.session.setMode(mode);
2019-04-17 12:48:54 +02:00
const tabSize = tab === "xml" ? 2 : 4;
this.editor.session.setOption("tabSize", tabSize);
2019-04-17 11:44:35 +02:00
this.state.currentTab = tab;
2019-03-31 09:35:03 +02:00
}
2019-04-01 10:06:04 +02:00
onMouseDown(ev) {
if (ev.target.tagName === "DIV") {
let y = ev.clientY;
const resizer = ev => {
const delta = ev.clientY - y;
y = ev.clientY;
this.trigger("updatePanelHeight", { delta });
};
document.body.addEventListener("mousemove", resizer);
document.body.addEventListener("mouseup", () => {
document.body.removeEventListener("mousemove", resizer);
});
}
}
2019-03-31 09:35:03 +02:00
}
//------------------------------------------------------------------------------
// MAIN APP
//------------------------------------------------------------------------------
class App extends owl.Component {
2019-03-28 17:31:25 +01:00
constructor(...args) {
super(...args);
this.template = "playground";
2019-03-28 17:31:25 +01:00
this.version = owl._version;
this.SAMPLES = SAMPLES;
2019-03-31 09:35:03 +02:00
this.widgets = { TabbedEditor };
2019-03-28 17:31:25 +01:00
this.state = {
js: SAMPLES[0].code,
2019-03-29 13:23:36 +01:00
css: SAMPLES[0].css || "",
2019-03-29 15:35:09 +01:00
xml: SAMPLES[0].xml || DEFAULT_XML,
error: false,
2019-03-30 20:22:11 +01:00
displayWelcome: true,
2019-04-01 09:22:12 +02:00
splitLayout: true,
2019-04-01 10:06:04 +02:00
leftPaneWidth: Math.ceil(window.innerWidth / 2),
topPanelHeight: null
2019-03-28 17:31:25 +01:00
};
}
2019-03-28 14:01:49 +01:00
displayError(error) {
this.state.error = error;
if (error) {
setTimeout(() => {
this.refs.content.innerHTML = "";
});
return;
}
}
2019-03-29 15:35:09 +01:00
async runCode() {
this.state.displayWelcome = false;
2019-03-29 15:35:09 +01:00
// check templates
var qweb = new owl.QWeb();
2019-03-29 15:35:09 +01:00
var error = false;
2019-04-17 16:13:52 +02:00
const sanitizedXML = this.state.xml.replace(/<!--[\s\S]*?-->/g, "");
2019-03-29 15:35:09 +01:00
try {
2019-04-17 16:13:52 +02:00
qweb.loadTemplates(sanitizedXML);
2019-03-29 15:35:09 +01:00
} catch (e) {
error = e;
}
if (error) {
this.displayError(error.message);
2019-03-29 15:35:09 +01:00
return;
} else {
this.state.error = false;
2019-03-29 15:35:09 +01:00
}
// create iframe
2019-03-28 17:31:25 +01:00
const iframe = document.createElement("iframe");
iframe.onload = () => {
const doc = iframe.contentDocument;
// inject js
const owlScript = doc.createElement("script");
owlScript.type = "text/javascript";
owlScript.src = "libs/owl.js";
owlScript.addEventListener("load", () => {
const script = doc.createElement("script");
script.type = "text/javascript";
2019-04-17 16:13:52 +02:00
const content = `window.TEMPLATES = \`${sanitizedXML}\`\n${
2019-03-29 15:35:09 +01:00
this.state.js
}`;
script.innerHTML = content;
const errorHandler = e => this.displayError(e.message);
iframe.contentWindow.addEventListener("error", errorHandler);
setTimeout(function() {
if (iframe.contentWindow) {
iframe.contentWindow.removeEventListener("error", errorHandler);
}
}, 100);
doc.body.appendChild(script);
});
doc.head.appendChild(owlScript);
2019-03-28 17:31:25 +01:00
// inject css
const style = document.createElement("style");
style.innerHTML = this.state.css;
doc.head.appendChild(style);
2019-03-28 17:31:25 +01:00
};
this.refs.content.innerHTML = "";
this.refs.content.appendChild(iframe);
}
setSample(ev) {
const sample = SAMPLES.find(s => s.description === ev.target.value);
2019-04-17 11:44:35 +02:00
this.state.js = sample.code;
this.state.css = sample.css || "";
this.state.xml = sample.xml || DEFAULT_XML;
2019-03-28 14:01:49 +01:00
}
2019-03-30 20:22:11 +01:00
get leftPaneStyle() {
return `width:${this.state.leftPaneWidth}px`;
}
get rightPaneStyle() {
2019-03-31 09:35:03 +02:00
return `width:${window.innerWidth - 6 - this.state.leftPaneWidth}px`;
2019-03-30 20:22:11 +01:00
}
2019-04-01 10:06:04 +02:00
get topEditorStyle() {
return `flex: 0 0 ${this.state.topPanelHeight}px`;
}
onMouseDown() {
2019-03-30 20:22:11 +01:00
const resizer = ev => {
2019-04-17 11:44:35 +02:00
this.state.leftPaneWidth = ev.clientX;
2019-03-30 20:22:11 +01:00
};
document.body.addEventListener("mousemove", resizer);
for (let iframe of document.getElementsByTagName("iframe")) {
iframe.classList.add("disabled");
}
document.body.addEventListener("mouseup", () => {
document.body.removeEventListener("mousemove", resizer);
for (let iframe of document.getElementsByTagName("iframe")) {
iframe.classList.remove("disabled");
}
});
}
2019-03-31 09:35:03 +02:00
updateCode(ev) {
this.state[ev.type] = ev.value;
}
2019-03-31 22:37:04 +02:00
toggleLayout() {
2019-04-17 11:44:35 +02:00
this.state.splitLayout = !this.state.splitLayout;
2019-03-31 22:37:04 +02:00
}
2019-04-01 10:06:04 +02:00
updatePanelHeight(ev) {
if (!ev.delta) {
return;
}
let height = this.state.topPanelHeight;
if (!height) {
height = document.getElementsByClassName("tabbed-editor")[0].clientHeight;
}
2019-04-17 11:44:35 +02:00
this.state.topPanelHeight = height + ev.delta;
2019-04-01 10:06:04 +02:00
}
2019-04-26 14:01:47 +02:00
async downloadCode() {
2019-04-29 11:17:53 +02:00
await owl.utils.loadJS("libs/FileSaver.min.js");
await owl.utils.loadJS("libs/jszip.min.js");
2019-04-26 14:01:47 +02:00
const zip = new JSZip();
const JS = `async function startApp() {
const TEMPLATES = await owl.utils.loadTemplates('app.xml');
${this.state.js};
}
owl.utils.whenReady(startApp);`;
zip.file("app.js", JS);
zip.file("app.css", this.state.css);
zip.file("app.xml", this.state.xml);
zip.file("index.html", DEFAULT_HTML);
zip.file("owl.js", owlSourceCode());
zip.generateAsync({ type: "blob" }).then(function(content) {
saveAs(content, "app.zip");
});
}
2019-03-28 14:01:49 +01:00
}
2019-03-29 16:14:36 +01:00
//------------------------------------------------------------------------------
// Application initialization
//------------------------------------------------------------------------------
document.title = `${document.title} (v${owl._version})`;
2019-03-28 14:01:49 +01:00
document.addEventListener("DOMContentLoaded", async function() {
const templates = await owl.utils.loadTemplates("src/templates.xml");
const qweb = new owl.QWeb(templates);
2019-03-28 17:31:25 +01:00
const env = { qweb };
2019-03-29 16:14:36 +01:00
const app = new App(env);
app.mount(document.body);
2019-03-28 14:01:49 +01:00
});