Add preliminary js upload

This commit is contained in:
2026-01-08 12:54:21 +01:00
parent e5de5b325d
commit 7c9f47cb1f
3 changed files with 156 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
.modal {
display: flex;
justify-content: center;
align-items: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background-color: rgba(0, 0, 0, 0.45);
}
.modal .modal-inner {
width: 1024px;
background-color: #0a0e1a;
border-radius: 8px;
padding: 12px;
color: white;
border: 1px solid #504768;
max-height: 90vh;
overflow: auto;
}
.modal .modal-inner form {
display: flex;
flex-direction: column;
gap: 12px;
}
.modal .modal-inner .form-group {
display: flex;
flex-direction: column;
gap: 8px;
}
.modal .modal-inner .form-actions {
display: flex;
justify-content: space-between;
}
.modal .modal-inner textarea {
max-width: 100%;
resize: vertical;
}
.modal .modal-inner .form-error {
padding: 8px;
background-color: rgba(200, 0, 0, 0.3);
border: 1px solid #a00;
border-radius: 4px;
}

View File

@@ -0,0 +1,55 @@
const assetModal = document.getElementById("custom-asset-modal");
const userSourceTextArea = document.getElementById("custom-asset-code");
const formErrorWrapper = document.getElementById("custom-asset-error");
const jsErrorTitle = document.getElementById("js-error-title");
const jsErrorDetails = document.getElementById("js-error-details");
function toggleCustomAssetModal(event) {
if (event !== undefined && event.target !== event.currentTarget) {
return;
}
if (assetModal.classList.contains("hidden")) {
assetModal.classList.remove("hidden");
} else {
assetModal.classList.add("hidden");
}
}
function submitCodeAsset(formEvent) {
formEvent.preventDefault();
const src = userSourceTextArea.value;
const error = getUserJavaScriptSourceError(src);
if (error) {
jsErrorTitle.textContent = error.title;
jsErrorDetails.textContent = error.details;
formErrorWrapper.classList.remove("hidden");
return false;
}
formErrorWrapper.classList.add("hidden");
jsErrorTitle.textContent = "";
jsErrorDetails.textContent = "";
return false;
}
function getUserJavaScriptSourceError(src) {
let ast;
try {
ast = acorn.parse(src, {
ecmaVersion: "latest",
sourceType: "script",
});
} catch (e) {
return { title: "Syntax Error", details: e.message };
}
const functionNames = ast.body.filter((node) => node.type === "FunctionDeclaration").map((node) => node.id.name);
if (!functionNames.includes("init")) {
return { title: "Missing function: init", details: "Your code must include a function named 'init'." };
}
if (!functionNames.includes("tick")) {
return { title: "Missing function: tick", details: "Your code must include a function named 'tick'." };
}
return undefined;
}