diff --git a/config.html b/config.html
index 79cd4d7..50b4e76 100644
--- a/config.html
+++ b/config.html
@@ -55,6 +55,15 @@
diff --git a/css/form.css b/css/form.css
index 596c8f2..57f7861 100644
--- a/css/form.css
+++ b/css/form.css
@@ -46,4 +46,8 @@ input[type="checkbox"] {
input[type="radio"] {
position: inherit;
-}
\ No newline at end of file
+}
+
+div[draggable="true"] {
+ cursor: grab;
+}
diff --git a/css/style.css b/css/style.css
index f37c21b..1df0a78 100644
--- a/css/style.css
+++ b/css/style.css
@@ -102,4 +102,8 @@ hr, * {
.none {
display: none;
+}
+
+.spacer {
+ min-height: 1em;
}
\ No newline at end of file
diff --git a/scripts/config.js b/scripts/config.js
index eaaa3ed..62ea4e6 100644
--- a/scripts/config.js
+++ b/scripts/config.js
@@ -1,4 +1,4 @@
-import { requestPVE, requestAPI, goToPage, getURIData, resourcesConfig, setTitleAndHeader } from "./utils.js";
+import { requestPVE, requestAPI, goToPage, getURIData, resourcesConfig, setTitleAndHeader, bootConfig } from "./utils.js";
import { alert, dialog } from "./dialog.js";
window.addEventListener("DOMContentLoaded", init); // do the dumb thing where the disk config refreshes every second
@@ -6,6 +6,7 @@ window.addEventListener("DOMContentLoaded", init); // do the dumb thing where th
const diskMetaData = resourcesConfig.disk;
const networkMetaData = resourcesConfig.network;
const pcieMetaData = resourcesConfig.pcie;
+const bootMetaData = bootConfig;
let node;
let type;
@@ -617,12 +618,6 @@ async function populateDevices () {
}
}
-async function populateBoot () {
- if (type === "qemu") {
- document.querySelector("#boot-card").classList.remove("none");
- }
-}
-
function addDeviceLine (fieldset, prefix, deviceID, deviceDetails, deviceName) {
const field = document.querySelector(`#${fieldset}`);
@@ -756,6 +751,124 @@ async function handleDeviceAdd () {
d.querySelector("#pcie").checked = true;
}
+async function populateBoot () {
+ if (type === "qemu") {
+ document.querySelector("#boot-card").classList.remove("none");
+ document.querySelectorAll(".drop-target").forEach((element) => {
+ element.addEventListener("dragenter", (event) => {
+ event.target.style.borderTop = "1px dotted";
+ event.preventDefault();
+ });
+ element.addEventListener("dragleave", (event) => {
+ event.target.attributeStyleMap.clear();
+ event.preventDefault();
+ });
+ element.addEventListener("dragover", (event) => {
+ event.preventDefault();
+ });
+ element.addEventListener("drop", (event) => {
+ const data = event.dataTransfer.getData("text/plain");
+ event.target.attributeStyleMap.clear();
+ addBootLine(element.parentElement.id, JSON.parse(data), element);
+ event.preventDefault();
+ });
+ });
+ const order = config.data.boot.replace("order=", "").split(";");
+ const bootable = { disabled: [] };
+ const eligible = bootMetaData.eligiblePrefixes;
+ for (let i = 0; i < order.length; i++) {
+ const prefix = eligible.find((pref) => order[i].startsWith(pref));
+ bootable[i] = { id: order[i], prefix };
+ }
+ Object.keys(config.data).forEach((element) => {
+ const prefix = eligible.find((pref) => element.startsWith(pref));
+ if (prefix && !order.includes(element)) {
+ bootable.disabled.push({ id: element, prefix });
+ }
+ });
+ Object.keys(bootable).sort();
+ Object.keys(bootable).forEach((element) => {
+ if (element !== "disabled") {
+ addBootLine("enabled", bootable[element], document.querySelector("#enabled-spacer"));
+ }
+ else {
+ bootable.disabled.forEach((item) => {
+ addBootLine("disabled", item, document.querySelector("#disabled-spacer"));
+ });
+ }
+ });
+ }
+}
+
+function addBootLine (fieldset, bootable, before = null) {
+ const box = document.createElement("div");
+ const icon = document.createElement("img");
+ icon.src = bootMetaData[bootable.prefix].icon;
+ box.append(icon);
+ const label = document.createElement("p");
+ label.innerText = bootable.id;
+ label.style.margin = "0px";
+ box.append(label);
+ box.draggable = true;
+ box.classList.add("flex");
+ box.classList.add("row");
+ box.classList.add("drop-target");
+ box.id = `boot-${bootable.id}`;
+ // setup draggable event listeners
+ box.addEventListener("dragstart", (event) => {
+ event.target.style.opacity = "0.5";
+ event.dataTransfer.setData("text/plain", JSON.stringify(bootable));
+ event.dataTransfer.effectAllowed = "move";
+ });
+ box.addEventListener("dragend", (event) => {
+ if (event.dataTransfer.dropEffect === "move") {
+ box.parentElement.removeChild(box);
+ }
+ else {
+ event.target.attributeStyleMap.clear();
+ }
+ });
+ box.addEventListener("dragenter", (event) => {
+ if (event.target.parentElement.classList.contains("drop-target")) {
+ event.target.parentElement.style.borderTop = "1px dotted";
+ }
+ event.preventDefault();
+ });
+ box.addEventListener("dragleave", (event) => {
+ if (event.target.parentElement.classList.contains("drop-target")) {
+ event.target.parentElement.style.borderTop = "";
+ }
+ event.preventDefault();
+ });
+ box.addEventListener("dragover", (event) => {
+ event.preventDefault();
+ });
+ box.addEventListener("drop", (event) => {
+ event.preventDefault();
+ const data = event.dataTransfer.getData("text/plain");
+ if (event.target.parentElement.classList.contains("drop-target")) {
+ event.target.parentElement.attributeStyleMap.clear();
+ }
+ addBootLine(box.parentElement.id, JSON.parse(data), box);
+ });
+ if (before) {
+ document.querySelector(`#${fieldset}`).insertBefore(box, before);
+ }
+ else {
+ document.querySelector(`#${fieldset}`).append(box);
+ }
+}
+
+class DraggableItem extends HTMLElement {
+ constructor () {
+ super();
+ }
+}
+
+customElements.define("draggable-item", DraggableItem);
+
+window.customElement
+
async function handleFormExit () {
const body = {
cores: document.querySelector("#cores").value,
diff --git a/scripts/utils.js b/scripts/utils.js
index 39dca91..0e360aa 100644
--- a/scripts/utils.js
+++ b/scripts/utils.js
@@ -129,6 +129,19 @@ export const nodesConfig = {
}
};
+export const bootConfig = {
+ eligiblePrefixes: ["ide", "sata", "net"],
+ ide: {
+ icon: "images/resources/disk.svg"
+ },
+ sata: {
+ icon: "images/resources/drive.svg"
+ },
+ net: {
+ icon: "images/resources/network.svg"
+ }
+};
+
export function getCookie (cname) {
const name = cname + "=";
const decodedCookie = decodeURIComponent(document.cookie);