mirror of
https://github.com/imgfloat/server.git
synced 2026-02-05 03:39:26 +00:00
Add preliminary js upload
This commit is contained in:
51
src/main/resources/static/css/customAssets.css
Normal file
51
src/main/resources/static/css/customAssets.css
Normal 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;
|
||||||
|
}
|
||||||
55
src/main/resources/static/js/customAssets.js
Normal file
55
src/main/resources/static/js/customAssets.js
Normal 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;
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
<meta name="_csrf_header" th:content="${_csrf.headerName}" />
|
<meta name="_csrf_header" th:content="${_csrf.headerName}" />
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
<link rel="stylesheet" href="/css/styles.css" />
|
<link rel="stylesheet" href="/css/styles.css" />
|
||||||
|
<link rel="stylesheet" href="/css/customAssets.css" />
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"
|
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"
|
||||||
@@ -16,6 +17,7 @@
|
|||||||
/>
|
/>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/stompjs@2.3.3/lib/stomp.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/stompjs@2.3.3/lib/stomp.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/acorn@8.15.0/dist/acorn.min.js"></script>
|
||||||
<script src="/js/csrf.js"></script>
|
<script src="/js/csrf.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="admin-body">
|
<body class="admin-body">
|
||||||
@@ -60,6 +62,18 @@
|
|||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="upload-row">
|
||||||
|
<label
|
||||||
|
class="file-input-trigger"
|
||||||
|
id="custom-asset-button"
|
||||||
|
onclick="toggleCustomAssetModal(undefined)"
|
||||||
|
>
|
||||||
|
<span class="file-input-icon"><i class="fa-solid fa-code"></i></span>
|
||||||
|
<span class="file-input-copy">
|
||||||
|
<strong>Create custom asset</strong>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
<div class="rail-body">
|
<div class="rail-body">
|
||||||
<div class="rail-scroll">
|
<div class="rail-scroll">
|
||||||
<ul id="asset-list" class="asset-list"></ul>
|
<ul id="asset-list" class="asset-list"></ul>
|
||||||
@@ -348,6 +362,41 @@
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="custom-asset-modal" class="modal hidden" onclick="toggleCustomAssetModal(event)">
|
||||||
|
<section class="modal-inner">
|
||||||
|
<h1>Create Custom Asset</h1>
|
||||||
|
<form id="custom-asset-form" onsubmit="submitCodeAsset(event)">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="custom-asset-name">Asset name</label>
|
||||||
|
<input
|
||||||
|
id="custom-asset-name"
|
||||||
|
type="text"
|
||||||
|
class="text-input"
|
||||||
|
placeholder="Enter asset name"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="custom-asset-type">Asset code</label>
|
||||||
|
<textarea
|
||||||
|
class="text-input"
|
||||||
|
id="custom-asset-code"
|
||||||
|
placeholder="function init({ surface, assets, channel }) { } function tick() { }"
|
||||||
|
rows="25"
|
||||||
|
required
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-error hidden" id="custom-asset-error">
|
||||||
|
<strong>JavaScript error: <span id="js-error-title"></span></strong>
|
||||||
|
<pre id="js-error-details"></pre>
|
||||||
|
</div>
|
||||||
|
<div class="form-actions">
|
||||||
|
<button type="button" class="secondary" onclick="toggleCustomAssetModal(event)">Cancel</button>
|
||||||
|
<button type="submit" class="primary">Test and save</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
<script th:inline="javascript">
|
<script th:inline="javascript">
|
||||||
const broadcaster = /*[[${broadcaster}]]*/ "";
|
const broadcaster = /*[[${broadcaster}]]*/ "";
|
||||||
const username = /*[[${username}]]*/ "";
|
const username = /*[[${username}]]*/ "";
|
||||||
@@ -357,5 +406,6 @@
|
|||||||
<script src="/js/cookie-consent.js"></script>
|
<script src="/js/cookie-consent.js"></script>
|
||||||
<script src="/js/toast.js"></script>
|
<script src="/js/toast.js"></script>
|
||||||
<script src="/js/admin.js"></script>
|
<script src="/js/admin.js"></script>
|
||||||
|
<script src="/js/customAssets.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user