fix, table cp, mengenfeld
This commit is contained in:
@@ -13,6 +13,13 @@ import PreviewManager from './configurator-preview-manager.js'; // Preview Manag
|
|||||||
const root = document.querySelector('[data-skrift-konfigurator="1"]');
|
const root = document.querySelector('[data-skrift-konfigurator="1"]');
|
||||||
if (!root) return;
|
if (!root) return;
|
||||||
|
|
||||||
|
// Guard: Verhindere doppelte Initialisierung
|
||||||
|
if (root.dataset.skriftInitialized === '1') {
|
||||||
|
console.warn('[Konfigurator] Bereits initialisiert, überspringe.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
root.dataset.skriftInitialized = '1';
|
||||||
|
|
||||||
// Cleanup bei Navigation (SPA) oder Seiten-Unload
|
// Cleanup bei Navigation (SPA) oder Seiten-Unload
|
||||||
const cleanupHandlers = [];
|
const cleanupHandlers = [];
|
||||||
|
|
||||||
|
|||||||
@@ -3512,6 +3512,7 @@ function downloadText(filename, text) {
|
|||||||
function createTableModal(dispatch, config) {
|
function createTableModal(dispatch, config) {
|
||||||
let tableWrapper;
|
let tableWrapper;
|
||||||
let currentState = config.getStateFunc();
|
let currentState = config.getStateFunc();
|
||||||
|
let isPasting = false; // Flag um Paste-Vorgang zu markieren
|
||||||
|
|
||||||
// State-Referenz aktualisieren (wird nach jedem Dispatch aufgerufen)
|
// State-Referenz aktualisieren (wird nach jedem Dispatch aufgerufen)
|
||||||
const updateState = () => {
|
const updateState = () => {
|
||||||
@@ -3585,6 +3586,9 @@ function createTableModal(dispatch, config) {
|
|||||||
oninput: col.readOnly
|
oninput: col.readOnly
|
||||||
? null
|
? null
|
||||||
: (e) => {
|
: (e) => {
|
||||||
|
// Während Paste-Vorgang ignorieren - Paste-Handler übernimmt
|
||||||
|
if (isPasting) return;
|
||||||
|
|
||||||
// Scroll-Position VOR dem dispatch speichern
|
// Scroll-Position VOR dem dispatch speichern
|
||||||
const modalContent = e.target.closest(".sk-modal-content");
|
const modalContent = e.target.closest(".sk-modal-content");
|
||||||
const scrollTop = modalContent ? modalContent.scrollTop : 0;
|
const scrollTop = modalContent ? modalContent.scrollTop : 0;
|
||||||
@@ -3633,15 +3637,26 @@ function createTableModal(dispatch, config) {
|
|||||||
// Excel Paste Handler mit automatischer Tabellen-Aktualisierung
|
// Excel Paste Handler mit automatischer Tabellen-Aktualisierung
|
||||||
table.addEventListener("paste", (e) => {
|
table.addEventListener("paste", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
isPasting = true; // Flag setzen um oninput zu blockieren
|
||||||
|
|
||||||
const text = e.clipboardData.getData("text/plain");
|
const text = e.clipboardData.getData("text/plain");
|
||||||
|
|
||||||
if (!text || !text.trim()) return;
|
if (!text || !text.trim()) {
|
||||||
|
isPasting = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const rows = text.split(/\r?\n/).filter((r) => r.trim());
|
const rows = text.split(/\r?\n/).filter((r) => r.trim());
|
||||||
if (rows.length === 0) return;
|
if (rows.length === 0) {
|
||||||
|
isPasting = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const activeInput = document.activeElement;
|
const activeInput = document.activeElement;
|
||||||
if (!activeInput || !activeInput.classList.contains("sk-input")) return;
|
if (!activeInput || !activeInput.classList.contains("sk-input")) {
|
||||||
|
isPasting = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const startRow = parseInt(activeInput.dataset.row || "0");
|
const startRow = parseInt(activeInput.dataset.row || "0");
|
||||||
const startCol = parseInt(activeInput.dataset.col || "0");
|
const startCol = parseInt(activeInput.dataset.col || "0");
|
||||||
@@ -3683,6 +3698,11 @@ function createTableModal(dispatch, config) {
|
|||||||
// Tabelle im Modal aktualisieren
|
// Tabelle im Modal aktualisieren
|
||||||
renderTable();
|
renderTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flag nach kurzem Delay zurücksetzen (für evtl. verzögerte input-Events)
|
||||||
|
setTimeout(() => {
|
||||||
|
isPasting = false;
|
||||||
|
}, 50);
|
||||||
});
|
});
|
||||||
|
|
||||||
return table;
|
return table;
|
||||||
@@ -4039,20 +4059,26 @@ function renderRecipientsTable(state, dispatch) {
|
|||||||
}
|
}
|
||||||
table.appendChild(tbody);
|
table.appendChild(tbody);
|
||||||
|
|
||||||
// Focusout-Handler mit Debounce um Flackern zu vermeiden
|
// Save-Funktion für Registry (wird bei Navigation und periodisch aufgerufen)
|
||||||
let focusoutTimer = null;
|
let hasLocalChanges = false;
|
||||||
let hasLocalChanges = false; // Track ob lokale Änderungen gemacht wurden
|
const saveLocalChanges = () => {
|
||||||
table.addEventListener("focusout", (e) => {
|
if (hasLocalChanges) {
|
||||||
if (focusoutTimer) clearTimeout(focusoutTimer);
|
dispatch({ type: "SET_RECIPIENT_ROWS", rows: [...table._rows] });
|
||||||
focusoutTimer = setTimeout(() => {
|
hasLocalChanges = false;
|
||||||
const newFocus = document.activeElement;
|
}
|
||||||
if (!table.contains(newFocus) && hasLocalChanges) {
|
};
|
||||||
// Nur dispatchen wenn lokale Änderungen gemacht wurden
|
|
||||||
dispatch({ type: "SET_RECIPIENT_ROWS", rows: [...table._rows] });
|
// Bei globaler Registry registrieren
|
||||||
hasLocalChanges = false;
|
const unregisterSave = registerTableSave(saveLocalChanges);
|
||||||
}
|
|
||||||
}, 150);
|
// Auto-Save alle 60 Sekunden
|
||||||
});
|
const autoSaveInterval = setInterval(saveLocalChanges, 60000);
|
||||||
|
|
||||||
|
// Cleanup-Funktion
|
||||||
|
table._cleanup = () => {
|
||||||
|
if (autoSaveInterval) clearInterval(autoSaveInterval);
|
||||||
|
unregisterSave();
|
||||||
|
};
|
||||||
|
|
||||||
// Änderungen tracken bei Input
|
// Änderungen tracken bei Input
|
||||||
table.addEventListener("input", () => {
|
table.addEventListener("input", () => {
|
||||||
@@ -4129,6 +4155,7 @@ function renderRecipientsTable(state, dispatch) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (pastedCells > 0) {
|
if (pastedCells > 0) {
|
||||||
|
hasLocalChanges = false; // Paste übernimmt - keine alten Änderungen mehr relevant
|
||||||
dispatch({ type: "SET_RECIPIENT_ROWS", rows: newData });
|
dispatch({ type: "SET_RECIPIENT_ROWS", rows: newData });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -4200,20 +4227,26 @@ function renderRecipientsTable(state, dispatch) {
|
|||||||
}
|
}
|
||||||
table.appendChild(tbody);
|
table.appendChild(tbody);
|
||||||
|
|
||||||
// Focusout-Handler mit Debounce um Flackern zu vermeiden
|
// Save-Funktion für Registry (wird bei Navigation und periodisch aufgerufen)
|
||||||
let focusoutTimer = null;
|
let hasLocalChanges = false;
|
||||||
let hasLocalChanges = false; // Track ob lokale Änderungen gemacht wurden
|
const saveLocalChanges = () => {
|
||||||
table.addEventListener("focusout", (e) => {
|
if (hasLocalChanges) {
|
||||||
if (focusoutTimer) clearTimeout(focusoutTimer);
|
dispatch({ type: "SET_FREE_ADDRESS_ROWS", rows: [...rows] });
|
||||||
focusoutTimer = setTimeout(() => {
|
hasLocalChanges = false;
|
||||||
const newFocus = document.activeElement;
|
}
|
||||||
if (!table.contains(newFocus) && hasLocalChanges) {
|
};
|
||||||
// Nur dispatchen wenn lokale Änderungen gemacht wurden
|
|
||||||
dispatch({ type: "SET_FREE_ADDRESS_ROWS", rows: [...rows] });
|
// Bei globaler Registry registrieren
|
||||||
hasLocalChanges = false;
|
const unregisterSave = registerTableSave(saveLocalChanges);
|
||||||
}
|
|
||||||
}, 150);
|
// Auto-Save alle 60 Sekunden
|
||||||
});
|
const autoSaveInterval = setInterval(saveLocalChanges, 60000);
|
||||||
|
|
||||||
|
// Cleanup-Funktion
|
||||||
|
table._cleanup = () => {
|
||||||
|
if (autoSaveInterval) clearInterval(autoSaveInterval);
|
||||||
|
unregisterSave();
|
||||||
|
};
|
||||||
|
|
||||||
// Änderungen tracken bei Input
|
// Änderungen tracken bei Input
|
||||||
table.addEventListener("input", () => {
|
table.addEventListener("input", () => {
|
||||||
@@ -4272,6 +4305,7 @@ function renderRecipientsTable(state, dispatch) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (pastedCells > 0) {
|
if (pastedCells > 0) {
|
||||||
|
hasLocalChanges = false; // Paste übernimmt - keine alten Änderungen mehr relevant
|
||||||
dispatch({ type: "SET_FREE_ADDRESS_ROWS", rows: newData });
|
dispatch({ type: "SET_FREE_ADDRESS_ROWS", rows: newData });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -4561,18 +4595,6 @@ function renderCombinedPlaceholderTable(
|
|||||||
}
|
}
|
||||||
table.appendChild(tbody);
|
table.appendChild(tbody);
|
||||||
|
|
||||||
// Focusout-Handler: Speichern wenn Fokus die Tabelle verlässt
|
|
||||||
let focusoutTimer = null;
|
|
||||||
table.addEventListener("focusout", (e) => {
|
|
||||||
if (focusoutTimer) clearTimeout(focusoutTimer);
|
|
||||||
focusoutTimer = setTimeout(() => {
|
|
||||||
const newFocus = document.activeElement;
|
|
||||||
if (!table.contains(newFocus)) {
|
|
||||||
saveLocalChanges();
|
|
||||||
}
|
|
||||||
}, 150);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Paste-Handler für Excel-Daten
|
// Paste-Handler für Excel-Daten
|
||||||
table.addEventListener("paste", (e) => {
|
table.addEventListener("paste", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -4814,20 +4836,26 @@ function renderPlaceholderTable(
|
|||||||
}
|
}
|
||||||
table.appendChild(tbody);
|
table.appendChild(tbody);
|
||||||
|
|
||||||
// Focusout-Handler mit Debounce - analog zur Empfängertabelle
|
// Save-Funktion für Registry (wird bei Navigation und periodisch aufgerufen)
|
||||||
let focusoutTimer = null;
|
let hasLocalChanges = false;
|
||||||
let hasLocalChanges = false; // Track ob lokale Änderungen gemacht wurden
|
const saveLocalChanges = () => {
|
||||||
table.addEventListener("focusout", (e) => {
|
if (hasLocalChanges) {
|
||||||
if (focusoutTimer) clearTimeout(focusoutTimer);
|
dispatch({ type: "SET_PLACEHOLDER_VALUES", values: localValues });
|
||||||
focusoutTimer = setTimeout(() => {
|
hasLocalChanges = false;
|
||||||
const newFocus = document.activeElement;
|
}
|
||||||
if (!table.contains(newFocus) && hasLocalChanges) {
|
};
|
||||||
// Nur dispatchen wenn lokale Änderungen gemacht wurden
|
|
||||||
dispatch({ type: "SET_PLACEHOLDER_VALUES", values: localValues });
|
// Bei globaler Registry registrieren
|
||||||
hasLocalChanges = false;
|
const unregisterSave = registerTableSave(saveLocalChanges);
|
||||||
}
|
|
||||||
}, 150);
|
// Auto-Save alle 60 Sekunden
|
||||||
});
|
const autoSaveInterval = setInterval(saveLocalChanges, 60000);
|
||||||
|
|
||||||
|
// Cleanup-Funktion
|
||||||
|
table._cleanup = () => {
|
||||||
|
if (autoSaveInterval) clearInterval(autoSaveInterval);
|
||||||
|
unregisterSave();
|
||||||
|
};
|
||||||
|
|
||||||
// Änderungen tracken bei Input
|
// Änderungen tracken bei Input
|
||||||
table.addEventListener("input", () => {
|
table.addEventListener("input", () => {
|
||||||
@@ -4881,6 +4909,7 @@ function renderPlaceholderTable(
|
|||||||
|
|
||||||
// Einmal dispatch für alle Änderungen
|
// Einmal dispatch für alle Änderungen
|
||||||
if (pastedCells > 0) {
|
if (pastedCells > 0) {
|
||||||
|
hasLocalChanges = false; // Paste übernimmt - keine alten Änderungen mehr relevant
|
||||||
dispatch({ type: "SET_PLACEHOLDER_VALUES", values: localValues });
|
dispatch({ type: "SET_PLACEHOLDER_VALUES", values: localValues });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -29,19 +29,19 @@ function createInitialState() {
|
|||||||
step: STEPS.PRODUCT,
|
step: STEPS.PRODUCT,
|
||||||
customerType: null, // 'business' | 'private'
|
customerType: null, // 'business' | 'private'
|
||||||
product: null,
|
product: null,
|
||||||
// Calculator-Felder
|
// Calculator-Felder - Defaults auf günstigste Optionen
|
||||||
quantity: 100,
|
quantity: 100,
|
||||||
format: 'a6h', // a4, a6h (a6p), a6q (a6l)
|
format: 'a6p', // a6p ist günstiger als a4 (kein Aufpreis)
|
||||||
shippingMode: 'direct', // direct, bulk
|
shippingMode: 'bulk', // Sammelversand ist günstiger (nur Pauschale statt pro Stück)
|
||||||
envelope: true, // Bei Sammelversand: Kuvert ja/nein
|
envelope: false, // Kein Kuvert ist günstiger
|
||||||
envelopeMode: 'recipientData', // recipientData, customText, none (Beschriftungsart)
|
envelopeMode: 'none', // Keine Beschriftung ist günstiger
|
||||||
followupYearlyVolume: '50-199',
|
followupYearlyVolume: '50-199',
|
||||||
followupCreateMode: 'manual', // auto, manual
|
followupCreateMode: 'manual', // Manuell ist günstiger (keine API-Kosten)
|
||||||
// Motiv (nur für Postkarten/Einladungen mit A6)
|
// Motiv (nur für Postkarten/Einladungen mit A6)
|
||||||
motifNeed: false,
|
motifNeed: false, // Kein Motiv ist günstiger
|
||||||
motifSource: null, // upload, design
|
motifSource: null, // upload, design
|
||||||
// Inhalt
|
// Inhalt
|
||||||
contentCreateMode: 'self', // self, textservice
|
contentCreateMode: 'self', // Selbst erstellen ist günstiger
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,8 +55,14 @@ function reducer(state, action) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
case 'SET_PRODUCT': {
|
case 'SET_PRODUCT': {
|
||||||
// Default-Format setzen
|
// Default-Format: Günstigstes zuerst (A6 hat keinen Aufpreis bei Postkarten/Einladungen)
|
||||||
const defaultFormat = action.product.formats?.[0] || 'a4';
|
// Bei Produkten mit supportsMotif ist A6 günstiger, also bevorzugen
|
||||||
|
const formats = action.product.formats || [];
|
||||||
|
const hasA6 = formats.some(f => f === 'a6p' || f === 'a6l');
|
||||||
|
const hasA4 = formats.includes('a4');
|
||||||
|
// A6 bevorzugen wenn verfügbar (günstiger), sonst erstes Format
|
||||||
|
const defaultFormat = hasA6 ? 'a6p' : (formats[0] || 'a4');
|
||||||
|
|
||||||
// Default-Menge je nach Kundentyp
|
// Default-Menge je nach Kundentyp
|
||||||
const settings = window.SkriftPreisrechner?.settings || window.SkriftConfigurator?.settings || {};
|
const settings = window.SkriftPreisrechner?.settings || window.SkriftConfigurator?.settings || {};
|
||||||
const dynamicPricing = settings.dynamic_pricing || {};
|
const dynamicPricing = settings.dynamic_pricing || {};
|
||||||
|
|||||||
Reference in New Issue
Block a user