add templater
This commit is contained in:
parent
4d6c343422
commit
c33a49e817
8 changed files with 248 additions and 27 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1 +1,3 @@
|
||||||
node_modules
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
dbs
|
||||||
|
|
|
||||||
103
index.js
103
index.js
|
|
@ -3,6 +3,7 @@ const vm = require("node:vm");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const express = require("express");
|
const express = require("express");
|
||||||
const session = require("express-session");
|
const session = require("express-session");
|
||||||
|
const fileUpload = require("express-fileupload");
|
||||||
const SQLiteStore = require("better-sqlite3-session-store")(session);
|
const SQLiteStore = require("better-sqlite3-session-store")(session);
|
||||||
const betterSqlite3 = require("better-sqlite3");
|
const betterSqlite3 = require("better-sqlite3");
|
||||||
const { Eta } = require("eta");
|
const { Eta } = require("eta");
|
||||||
|
|
@ -20,6 +21,7 @@ const routes = { GET: [], POST: [], PUT: [], DELETE: [] };
|
||||||
|
|
||||||
app.use(bodyParser.urlencoded({ extended: true }));
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
app.use(express.static("public"));
|
app.use(express.static("public"));
|
||||||
|
app.use(fileUpload());
|
||||||
|
|
||||||
const db = betterSqlite3("./prime.db");
|
const db = betterSqlite3("./prime.db");
|
||||||
|
|
||||||
|
|
@ -209,12 +211,42 @@ function updateDb(db, appDb) {
|
||||||
db.prepare(sql).run(...values);
|
db.prepare(sql).run(...values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateTemplate(db, template) {
|
||||||
|
const fields = ["content", "name", "test_object"];
|
||||||
|
const values = fields.map((field) => template[field]);
|
||||||
|
const placeholders = fields.map((field) => `${field} = ?`).join(", ");
|
||||||
|
|
||||||
|
const sql = `UPDATE templates SET ${placeholders} WHERE id = ?`;
|
||||||
|
values.push(template.id);
|
||||||
|
db.prepare(sql).run(...values);
|
||||||
|
}
|
||||||
|
|
||||||
function getTemplates(db, structureId) {
|
function getTemplates(db, structureId) {
|
||||||
return db
|
return db
|
||||||
.prepare("SELECT * from templates where structure_id = ?")
|
.prepare("SELECT * from templates where structure_id = ?")
|
||||||
.all(structureId);
|
.all(structureId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTemplate(db, templateId) {
|
||||||
|
return db.prepare("SELECT * from templates where id = ?").get(templateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTemplateContentByName(db, structId, name) {
|
||||||
|
return db
|
||||||
|
.prepare(
|
||||||
|
"SELECT content from templates where structure_id = ? AND name = ?"
|
||||||
|
)
|
||||||
|
.get(structId, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTemplate(db, structureId, name, content, testObjectString) {
|
||||||
|
return db
|
||||||
|
.prepare(
|
||||||
|
"INSERT INTO templates (structure_id, name, content, test_object) VALUES (?, ?, ?, ?)"
|
||||||
|
)
|
||||||
|
.run(structureId, name, content, testObjectString).lastInsertRowid;
|
||||||
|
}
|
||||||
|
|
||||||
function getDbsForStructure(db, structureId) {
|
function getDbsForStructure(db, structureId) {
|
||||||
return db
|
return db
|
||||||
.prepare(
|
.prepare(
|
||||||
|
|
@ -280,8 +312,6 @@ function createDb(db, structId, name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { LRUCache } = require("lru-cache");
|
const { LRUCache } = require("lru-cache");
|
||||||
const { templateSettings } = require("dot");
|
|
||||||
// we'll figure out max size later
|
|
||||||
const templateCache = new LRUCache({ max: 100 });
|
const templateCache = new LRUCache({ max: 100 });
|
||||||
|
|
||||||
function getTemplater(structId) {
|
function getTemplater(structId) {
|
||||||
|
|
@ -293,7 +323,7 @@ function getTemplater(structId) {
|
||||||
return path;
|
return path;
|
||||||
};
|
};
|
||||||
etaInstance.readFile = function (templateAlias) {
|
etaInstance.readFile = function (templateAlias) {
|
||||||
return getTemplateString(db, templateAlias, structId);
|
return getTemplateContentByName(db, structId, templateAlias).content;
|
||||||
};
|
};
|
||||||
templateCache.set(structId, etaInstance);
|
templateCache.set(structId, etaInstance);
|
||||||
}
|
}
|
||||||
|
|
@ -315,9 +345,8 @@ function getDbInstance(dbId) {
|
||||||
return dbInstance;
|
return dbInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
function bootstrapTemplateWithHTMXetc(htmlString, blissRoute) {
|
function bootstrapTemplateWithHTMXetc(htmlString, blissRoute, wrapHTML) {
|
||||||
console.log(htmlString);
|
if (htmlString.startsWith("<html>") || wrapHTML) {
|
||||||
if (htmlString.startsWith("<html>")) {
|
|
||||||
const $ = cheerio.load(htmlString);
|
const $ = cheerio.load(htmlString);
|
||||||
let head = $("head");
|
let head = $("head");
|
||||||
|
|
||||||
|
|
@ -487,6 +516,63 @@ app.post("/workshop/:structure_id/db/:db_id/repl", (req, res) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.post("/workshop/:structure_id/template", (req, res) => {
|
||||||
|
let name = req.body.name;
|
||||||
|
|
||||||
|
const template = createTemplate(
|
||||||
|
db,
|
||||||
|
req.params.structure_id,
|
||||||
|
name,
|
||||||
|
"<div>henlo <%= it.name %></div>",
|
||||||
|
"it = { name: 'templates!' };"
|
||||||
|
);
|
||||||
|
|
||||||
|
return smartRedirect(
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
`/workshop/${req.params.structure_id}/template/${template}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.put("/workshop/:structure_id/template/:template_id", (req, res) => {
|
||||||
|
let id = req.params.template_id;
|
||||||
|
let content = req.body.content;
|
||||||
|
let test_object = req.body.test_object;
|
||||||
|
|
||||||
|
updateTemplate(db, { ...getTemplate(db, id), content, test_object });
|
||||||
|
|
||||||
|
return res.send("good");
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get("/workshop/:structure_id/template/:template_id", (req, res) => {
|
||||||
|
const template = getTemplate(db, req.params.template_id);
|
||||||
|
|
||||||
|
return res.send(
|
||||||
|
bootstrapTemplateWithHTMXetc(
|
||||||
|
eta.render("workshop/template", {
|
||||||
|
template: template,
|
||||||
|
...sidebarStuff(db, req.params.structure_id),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get("/workshop/:structure_id/template/:template_id/preview", (req, res) => {
|
||||||
|
const template = getTemplate(db, req.params.template_id);
|
||||||
|
const eta = getTemplater(req.params.structure_id);
|
||||||
|
|
||||||
|
const context = vm.createContext({ it: null });
|
||||||
|
vm.runInContext(template.test_object, context);
|
||||||
|
|
||||||
|
return res.send(
|
||||||
|
bootstrapTemplateWithHTMXetc(
|
||||||
|
eta.render(template.name, context.it),
|
||||||
|
null,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
app.get("/workshop/:structure_id/route/:id", (req, res) => {
|
app.get("/workshop/:structure_id/route/:id", (req, res) => {
|
||||||
const route = getRoute(db, req.params.id);
|
const route = getRoute(db, req.params.id);
|
||||||
return res.send(
|
return res.send(
|
||||||
|
|
@ -581,7 +667,6 @@ app.all("*", (req, res) => {
|
||||||
|
|
||||||
res.rawSend = res.send;
|
res.rawSend = res.send;
|
||||||
res.send = (...args) => {
|
res.send = (...args) => {
|
||||||
console.log(args[0], args[1], "bingo")
|
|
||||||
res.rawSend(
|
res.rawSend(
|
||||||
bootstrapTemplateWithHTMXetc(
|
bootstrapTemplateWithHTMXetc(
|
||||||
args[0],
|
args[0],
|
||||||
|
|
@ -589,6 +674,10 @@ app.all("*", (req, res) => {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
res.render = (template, context) => {
|
||||||
|
const eta = getTemplater(route.structure_id);
|
||||||
|
res.send(bootstrapTemplateWithHTMXetc(eta.render(template, context)));
|
||||||
|
};
|
||||||
return vm.runInContext(
|
return vm.runInContext(
|
||||||
(route.handler += `\n\nhandler(req, res)`),
|
(route.handler += `\n\nhandler(req, res)`),
|
||||||
context
|
context
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,13 @@ CREATE TABLE templates (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
content TEXT,
|
content TEXT,
|
||||||
user_id INTEGER,
|
|
||||||
structure_id INTEGER,
|
structure_id INTEGER,
|
||||||
|
test_object TEXT DEFAULT "it = {}",
|
||||||
engine TEXT NOT NULL DEFAULT "eta",
|
engine TEXT NOT NULL DEFAULT "eta",
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
FOREIGN KEY(user_id) REFERENCES users(id),
|
|
||||||
FOREIGN KEY(structure_id) REFERENCES structures(id)
|
FOREIGN KEY(structure_id) REFERENCES structures(id)
|
||||||
|
UNIQUE(name, structure_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE routes (
|
CREATE TABLE routes (
|
||||||
|
|
|
||||||
52
package-lock.json
generated
52
package-lock.json
generated
|
|
@ -18,6 +18,7 @@
|
||||||
"ejs": "^3.1.9",
|
"ejs": "^3.1.9",
|
||||||
"eta": "^3.2.0",
|
"eta": "^3.2.0",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
|
"express-fileupload": "^1.5.0",
|
||||||
"express-session": "^1.18.0",
|
"express-session": "^1.18.0",
|
||||||
"jsdom": "^24.1.0",
|
"jsdom": "^24.1.0",
|
||||||
"lru-cache": "^10.2.0",
|
"lru-cache": "^10.2.0",
|
||||||
|
|
@ -290,6 +291,17 @@
|
||||||
"ieee754": "^1.1.13"
|
"ieee754": "^1.1.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/busboy": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
|
||||||
|
"dependencies": {
|
||||||
|
"streamsearch": "^1.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.16.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/bytes": {
|
"node_modules/bytes": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||||
|
|
@ -829,6 +841,17 @@
|
||||||
"node": ">= 0.10.0"
|
"node": ">= 0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/express-fileupload": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-jSW3w9evqM37VWkEPkL2Ck5wUo2a8qa03MH+Ou/0ZSTpNlQFBvSLjU12k2nYcHhaMPv4JVvv6+Ac1OuLgUZb7w==",
|
||||||
|
"dependencies": {
|
||||||
|
"busboy": "^1.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/express-session": {
|
"node_modules/express-session": {
|
||||||
"version": "1.18.0",
|
"version": "1.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz",
|
||||||
|
|
@ -2189,6 +2212,14 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/streamsearch": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/string_decoder": {
|
"node_modules/string_decoder": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
|
|
@ -2711,6 +2742,14 @@
|
||||||
"ieee754": "^1.1.13"
|
"ieee754": "^1.1.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"busboy": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
|
||||||
|
"requires": {
|
||||||
|
"streamsearch": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"bytes": {
|
"bytes": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||||
|
|
@ -3136,6 +3175,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"express-fileupload": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-jSW3w9evqM37VWkEPkL2Ck5wUo2a8qa03MH+Ou/0ZSTpNlQFBvSLjU12k2nYcHhaMPv4JVvv6+Ac1OuLgUZb7w==",
|
||||||
|
"requires": {
|
||||||
|
"busboy": "^1.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"express-session": {
|
"express-session": {
|
||||||
"version": "1.18.0",
|
"version": "1.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz",
|
||||||
|
|
@ -4075,6 +4122,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||||
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
|
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
|
||||||
},
|
},
|
||||||
|
"streamsearch": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="
|
||||||
|
},
|
||||||
"string_decoder": {
|
"string_decoder": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
"ejs": "^3.1.9",
|
"ejs": "^3.1.9",
|
||||||
"eta": "^3.2.0",
|
"eta": "^3.2.0",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
|
"express-fileupload": "^1.5.0",
|
||||||
"express-session": "^1.18.0",
|
"express-session": "^1.18.0",
|
||||||
"jsdom": "^24.1.0",
|
"jsdom": "^24.1.0",
|
||||||
"lru-cache": "^10.2.0",
|
"lru-cache": "^10.2.0",
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,22 @@
|
||||||
<div class="window" _="on closeModal remove me">
|
<div class="fixed inset-0 flex items-center justify-center z-10" _="on closeModal remove me">
|
||||||
|
<div class="window max-w-[768px]">
|
||||||
<div class="title-bar">
|
<div class="title-bar">
|
||||||
<div class="title-bar-text">Command Prompt</div>
|
<div class="title-bar-text">Create Template</div>
|
||||||
<div class="title-bar-controls">
|
<div class="title-bar-controls">
|
||||||
<button aria-label="Minimize"></button>
|
|
||||||
<button aria-label="Maximize"></button>
|
|
||||||
<button aria-label="Close" _="on click trigger closeModal"></button>
|
<button aria-label="Close" _="on click trigger closeModal"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="window-body">
|
<div class="window-body">
|
||||||
<pre>Microsoft❮R❯ Windows DOS
|
<form hx-post="/workshop/<%= it.structure.id %>/template" hx-target="#response">
|
||||||
❮C❯ Copyright Microsoft Corp 1990-2001.
|
<div class="field-row-stacked" style="width: 200px">
|
||||||
<br>C:\WINDOWS\SYSTEM32> You can build a command line easily with a window and pre tag
|
<label>Name</label>
|
||||||
</pre>
|
<input name="name" id="name" type="text" />
|
||||||
|
</div>
|
||||||
|
<section class="field-row" style="justify-content: flex-end">
|
||||||
|
<button type="submit">OK</button>
|
||||||
|
<button type="button" _="on click trigger closeModal">Cancel</button>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
<div id="response"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -24,7 +24,9 @@
|
||||||
<ul>
|
<ul>
|
||||||
<% it.templates.map(template => { %>
|
<% it.templates.map(template => { %>
|
||||||
<li>
|
<li>
|
||||||
<%= template.alias %>
|
<a href="/workshop/<%= it.structure.id %>/template/<%= template.id %>">
|
||||||
|
<%= template.name %>
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
<li hx-get="/workshop/<%= it.structure.id %>/new_template_modal" hx-target="#modal-zone" hx-swap="beforeend" class="cursor-pointer">
|
<li hx-get="/workshop/<%= it.structure.id %>/new_template_modal" hx-target="#modal-zone" hx-swap="beforeend" class="cursor-pointer">
|
||||||
|
|
|
||||||
69
views/workshop/template.eta
Normal file
69
views/workshop/template.eta
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="/css/xp.css">
|
||||||
|
<script src="/js/ace/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="flex flex-col w-full h-full window">
|
||||||
|
<div class="title-bar">
|
||||||
|
<div class="title-bar-text">Workshop - <%~ include('/workshop/structure_name', {structure: it.structure}) %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-row flex-grow window-body">
|
||||||
|
<div class="w-1/5 h-full">
|
||||||
|
<%~ include('/workshop/sidebar', it) %>
|
||||||
|
</div>
|
||||||
|
<div id="main-editor" class="flex flex-grow">
|
||||||
|
<div id="left-pane" class="w-1/2 flex-grow h-full flex flex-col">
|
||||||
|
Template
|
||||||
|
<div id="template-editor" class="w-full flex-grow"><%= it.template.content %></div>
|
||||||
|
Test Object
|
||||||
|
<div id="object-editor" class="w-full flex-grow"><%= it.template.test_object %></div>
|
||||||
|
<button id="save-btn" type="submit">Save</button>
|
||||||
|
</div>
|
||||||
|
<div id="preview-area" class="w-1/2 h-full flex flex-col">
|
||||||
|
<form _="on submit halt the event then set #preview's contentWindow.location.href to #url's value">
|
||||||
|
<input id="url" class="w-full">
|
||||||
|
</form>
|
||||||
|
<iframe id="preview"
|
||||||
|
src="/workshop/<%= it.template.structure_id %>/template/<%= it.template.id %>/preview"
|
||||||
|
class="w-full flex-grow"
|
||||||
|
_="on load set #url's value to my contentWindow.location.href">
|
||||||
|
</iframe>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
const templateEditor = ace.edit("template-editor");
|
||||||
|
templateEditor.setTheme("ace/theme/monokai");
|
||||||
|
templateEditor.session.setMode("ace/mode/ejs");
|
||||||
|
|
||||||
|
const objectEditor = ace.edit("object-editor");
|
||||||
|
objectEditor.setTheme("ace/theme/monokai");
|
||||||
|
objectEditor.session.setMode("ace/mode/javascript");
|
||||||
|
|
||||||
|
document.getElementById('save-btn').onclick = function() {
|
||||||
|
fetch('/workshop/<%= it.structure.id %>/template/<%= it.template.id %>', {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
},
|
||||||
|
body: new URLSearchParams({
|
||||||
|
content: templateEditor.getValue(),
|
||||||
|
test_object: objectEditor.getValue(),
|
||||||
|
}).toString()
|
||||||
|
}).then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
document.getElementById('preview').contentWindow.location.reload()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue