Grotti 3.7.0: Treiber für Kobra 4 und Marlin, smartere Dateien-Auswahl und einstellbare Etiketten.

Senden und Abbruch laufen über den Treiber, Orca-Doppelzeilen und tote Ideen-API fallen weg, Drucker folgen der Datei, Etikettenformat liegt in den Einstellungen.
This commit is contained in:
Dominic Gundel committed 2026-11-02 14:03:57 +01:00
1 parent 5081212212
commit db6a85a703
54 files changed
+3379 -384

No files matched your search

+52 -5
View File
@@ -270,12 +270,58 @@ function dots(colors) {
return wrap;
}
function slotLabel(slot) {
function printerFamily(host) {
return (printers.find((p) => p.host === host) || {}).family || "";
}
function slotLabel(slot, host) {
if (!slot) return "";
const family = printerFamily(host);
if (family === "tenlog") return "Kopf " + slot;
if (family === "anycubic_i3") return "am Drucker";
if (slot <= 4) return "ACE 1 · " + slot;
return "ACE 2 · " + (slot - 4);
}
function fillSlotOptions(host, keep) {
const select = document.getElementById("spool-slot");
const label = document.querySelector('label[for="spool-slot"]');
const current = keep != null ? String(keep) : select.value;
const family = printerFamily(host);
let options = [['', 'nicht im ACE']];
let tip = "ACE 1 = Plätze 1–4, ACE 2 = 5–8. Leer = externe Spule am Drucker. Ohne Drucker = Regal.";
if (!host) {
options = [['', 'Regal — kein Platz']];
tip = "Ohne Drucker liegt die Rolle im Regal.";
} else if (family === "tenlog") {
options = [['', 'kein Kopf'], ['1', 'Kopf 1'], ['2', 'Kopf 2']];
tip = "Tenlog: Kopf 1 oder Kopf 2. Leer = Rolle am Drucker ohne festen Kopf.";
} else if (family === "anycubic_i3") {
options = [['', 'am Drucker']];
tip = "Anycubic i3 hat keinen ACE — die Rolle liegt am Drucker.";
} else if (["kobra_3", "kobra_s1", "kobra_4"].includes(family)) {
options = [
['', 'nicht im ACE'],
['1', 'ACE 1 · Platz 1'], ['2', 'ACE 1 · Platz 2'], ['3', 'ACE 1 · Platz 3'], ['4', 'ACE 1 · Platz 4'],
['5', 'ACE 2 · Platz 1'], ['6', 'ACE 2 · Platz 2'], ['7', 'ACE 2 · Platz 3'], ['8', 'ACE 2 · Platz 4'],
];
} else {
options = [['', 'am Drucker']];
tip = "Platz nur bei ACE-Druckern.";
}
select.innerHTML = options.map(([value, text]) =>
`<option value="${escapeHtml(value)}">${escapeHtml(text)}</option>`
).join("");
if ([...select.options].some((o) => o.value === current)) select.value = current;
else select.value = "";
if (label) {
const tipNode = label.querySelector(".tip");
if (tipNode) tipNode.title = tip;
const title = family === "tenlog" ? "Kopf" : family === "anycubic_i3" ? "Lage" : "ACE-Platz";
label.childNodes[0].textContent = title + " ";
}
}
function printerName(host) {
return (printers.find((p) => p.host === host) || {}).name || host || "";
}
@@ -283,7 +329,7 @@ function printerName(host) {
function ortLabel(spool) {
if (!spool.printer_host) return "Regal";
const name = printerName(spool.printer_host);
if (spool.ace_slot) return name + " · " + slotLabel(spool.ace_slot);
if (spool.ace_slot) return name + " · " + slotLabel(spool.ace_slot, spool.printer_host);
return name + " · extern";
}
@@ -556,7 +602,7 @@ function fill(spool) {
document.getElementById("spool-chargen").value = spool ? (spool.chargen_nr || spool.code || "") : "";
document.getElementById("spool-hersteller").value = spool ? (spool.hersteller_charge || "") : "";
document.getElementById("spool-printer").value = spool ? spool.printer_host : "";
document.getElementById("spool-slot").value = spool && spool.ace_slot ? String(spool.ace_slot) : "";
fillSlotOptions(spool ? spool.printer_host : "", spool && spool.ace_slot ? String(spool.ace_slot) : "");
document.getElementById("spool-price").value = spool ? spool.price_per_kg : 0;
document.getElementById("spool-left").value = spool
? Math.round((Number(spool.remaining_g) || 0) * 10) / 10
@@ -676,6 +722,7 @@ function fillSelects() {
select.appendChild(option);
});
select.value = current;
fillSlotOptions(select.value);
const materialSelect = document.getElementById("spool-material");
const currentMaterial = materialSelect.value;
@@ -905,6 +952,7 @@ document.getElementById("sorten-close").addEventListener("click", closeSortenPan
document.getElementById("spool-material").addEventListener("change", () => applyMaterial(selectedMaterial(), true));
document.getElementById("spool-printer").addEventListener("change", () => {
fillSlotOptions(document.getElementById("spool-printer").value);
const material = selectedMaterial();
if (material) document.getElementById("spool-vol").value = volumeOf(material);
showHint();
@@ -1134,8 +1182,7 @@ load().then(() => {
document.getElementById("spool-new")?.click?.();
const hostField = document.getElementById("spool-printer");
if (hostField) hostField.value = hostHint;
const slotField = document.getElementById("spool-slot");
if (slotField && slotHint) slotField.value = String(slotHint);
fillSlotOptions(hostHint, slotHint ? String(slotHint) : "");
document.getElementById("spool-name")?.scrollIntoView({ behavior: "smooth", block: "center" });
toast("Drucker und Platz vorausgefüllt — Rolle wählen und speichern.");
}