/* ─── TRP-Exclude: Konfigurator sofort vor Übersetzung schützen ─── */ (function () { var sels = ['.mkl_pc_container', '.mkl_pc', 'ul.layers', '.mkl_pc_toolbar', '.mx-variant-header', '.mx-tech-specs']; function mark() { for (var i = 0; i < sels.length; i++) { var els = document.querySelectorAll(sels[i]); for (var j = 0; j < els.length; j++) els[j].setAttribute('data-no-translation', ''); } } mark(); document.addEventListener('DOMContentLoaded', mark); setTimeout(mark, 0); setTimeout(mark, 50); // ← PERF: 50ms statt 200ms reicht für TRP })(); /* ─── MX Pre-Hide: Layer-/Choice-Namen auf Nicht-DE Seiten sofort verstecken ─── * Verhindert den deutschen "Flash" bevor mxTranslateDom() läuft. * Nutzt das lang-Attribut des -Tags. * Sobald mxTranslateDom() den .mx-tl Span einfuegt, wird die uebersetzte * Version sichtbar und das Original bleibt via mx-has-tl versteckt. * * WICHTIG: Kein !important – stattdessen wird das ').appendTo('head'); } /* ─── Schlitzungsmuster Info-Popup CSS → ausgelagert in configurator.css ─── */ /* ─── MX Translation Helper ─── * Nutzt window.MX_TRANSLATIONS (aus PHP geladen) um deutsche Texte * in die aktuelle Sprache zu übersetzen. * WICHTIG: Die internen Keys (für Logik) bleiben IMMER deutsch. * Nur sichtbare DOM-Texte werden übersetzt. */ var MX_T = window.MX_TRANSLATIONS || {}; var MX_IS_DE = !window.MX_LANG || window.MX_LANG === 'DE'; /* ─── MX Translation CSS: Sofort injizieren (verhindert deutschen Flash) ─── * Auf nicht-DE Seiten werden layer-name / choice-name etc. SOFORT per * visibility:hidden unsichtbar gemacht – noch bevor mxTranslateDom() feuert. * Das verhindert den kurzen Aufblitz der deutschen Texte. * Sobald .mx-has-tl gesetzt + .mx-tl Span eingefügt wird, ist der * englische Text sichtbar und das Original bleibt per display:none verborgen. */ if (!MX_IS_DE && !document.getElementById('mx-translation-css')) { $('').appendTo('head'); } // Case-insensitive Lookup-Map: lowercase(DE) → translated var MX_T_LC = {}; (function () { for (var k in MX_T) { if (MX_T.hasOwnProperty(k)) { MX_T_LC[k.toLowerCase()] = MX_T[k]; } } })(); /** * Übersetze einen deutschen Text. Case-insensitive. * Behält die Original-Schreibweise bei: * "HART" → "HARD" (alles uppercase) * "Hart" → "Hard" (Title case) * "hart" → "hard" (lowercase) */ function mxT(text) { if (MX_IS_DE || !text) return text; var trimmed = (typeof text === 'string') ? text.trim() : String(text); if (!trimmed) return trimmed; // 1) Exakter Match if (MX_T[trimmed]) return MX_T[trimmed]; // 2) Case-insensitive Match var lc = trimmed.toLowerCase(); var translated = MX_T_LC[lc]; if (!translated) return trimmed; // 3) Casing vom Original beibehalten var isAllUpper = trimmed === trimmed.toUpperCase(); var isAllLower = trimmed === trimmed.toLowerCase(); var isTitleCase = !isAllUpper && !isAllLower && trimmed[0] === trimmed[0].toUpperCase(); if (isAllUpper) return translated.toUpperCase(); if (isAllLower) return translated.toLowerCase(); if (isTitleCase) return translated.charAt(0).toUpperCase() + translated.slice(1); return translated; } /** * Übersetzt alle sichtbaren Texte im Konfigurator DOM. * * Strategie für .layer-name und .choice-name: * - Originaltext bleibt UNBERÜHRT ($.text() gibt immer deutsch zurück) * - Ein Geschwister-Span .mx-tl wird NEBEN dem Original eingefügt * - Das Original wird per CSS versteckt, der .mx-tl ist sichtbar * - So funktioniert die interne Logik weiter mit deutschen Namen */ function mxTranslateDom() { if (MX_IS_DE) return; if (!Object.keys(MX_T).length) return; mxLog('Translating DOM to', window.MX_LANG, '(' + Object.keys(MX_T).length + ' entries)'); // ── Helper: Translated sibling neben Element einfügen ── function setTranslatedSibling($el, translated, tagClass) { // Prüfe ob schon ein .mx-tl Geschwister existiert var $existing = $el.next('.mx-tl'); if ($existing.length) { // Update falls Text sich geändert hat if ($existing.text() !== translated) { $existing.text(translated); } } else { // Neuen Span einfügen mit gleicher CSS-Klasse wie das Original var origClasses = $el.attr('class') || ''; // Entferne mx-has-tl aus den kopierten Klassen var newClasses = origClasses.replace(/\bmx-has-tl\b/g, '').trim(); var $tl = $('').text(translated); $el.after($tl); } $el.addClass('mx-has-tl'); } // ── Helper: Entferne Übersetzung wenn nicht mehr nötig ── function removeTranslatedSibling($el) { $el.next('.mx-tl').remove(); $el.removeClass('mx-has-tl'); // Sichtbarkeit wiederherstellen: mx-show überschreibt die pre-hide CSS-Regel $el.addClass('mx-show'); } // 1) Layer-Namen $('ul.layers > li.layers-list-item').each(function () { var $nameEl = $(this).find('> .layer-item .layer-name').first(); var original = $.trim($nameEl.text()); if (!original) return; var translated = mxT(original); if (translated !== original) { setTranslatedSibling($nameEl, translated); } else { removeTranslatedSibling($nameEl); } }); // 2) Choice-Namen $('ul.layers .layer_choices li.choice').each(function () { var $nameEl = $(this).find('.choice-name').first(); var original = $.trim($nameEl.text()); if (!original) return; var translated = mxT(original); if (translated !== original) { setTranslatedSibling($nameEl, translated); } else { removeTranslatedSibling($nameEl); } }); // 3) Selected-choice Labels $('ul.layers > li.layers-list-item .selected-choice').each(function () { var $el = $(this); var original = $.trim($el.text()); if (!original) { removeTranslatedSibling($el); return; } var translated = mxT(original); if (translated !== original) { setTranslatedSibling($el, translated); } else { removeTranslatedSibling($el); } }); // 3b) Aufnahme-Radio Labels (nur reine Text-Radios, NICHT innerhalb Bild-Tiles) $('.mx-aufnahme-radio-label').each(function () { var $el = $(this); if ($el.hasClass('mx-tl')) return; // Skip wenn innerhalb eines Bild-Tiles (Aufnahme-Cat, Drehrichtung) if ($el.closest('.mx-aufnahme-tile, .mx-dreh-tile, .mx-aufnahme-cat-tile').length) return; // Skip wenn Geschwister ein img hat (Bild-Tile) if ($el.siblings('img').length) return; var original = $.trim($el.text()); if (!original) return; var translated = mxT(original); if (translated !== original) { setTranslatedSibling($el, translated); } else { // Kein Übersetzungs-Span nötig → Sichtbarkeit wiederherstellen removeTranslatedSibling($el); } }); // 3c) Drehrichtung-Tile Labels — SKIP: Bilder enthalten bereits den Text // 3d) Besatz-Tile Labels $('.mx-besatz-tile-label, .mx-besatz-tile span').each(function () { var $el = $(this); if ($el.hasClass('mx-tl')) return; var original = $.trim($el.text()); if (!original) return; var translated = mxT(original); if (translated !== original) { $el.text(translated); } // Sichtbarkeit immer wiederherstellen (war per :not(.mx-show) CSS versteckt) $el.addClass('mx-show'); }); // 3e) Aufnahme category tiles — SKIP: Bilder enthalten bereits den Text // 3f) Drehrichtung tiles — SKIP: Bilder enthalten bereits den Text // 3f) Edition / Evo tile labels $('.mx-evo-tile-label, .mx-edition-label').each(function () { var original = $.trim($(this).text()); if (!original) return; var translated = mxT(original); if (translated !== original) { $(this).text(translated); } }); // 3g) Reinigungsvlies / Kraftband no-summary tile labels $('.mx-edition-no-summary-tile-label').each(function () { var $el = $(this); if ($el.hasClass('mx-tl')) return; var original = $.trim($el.text()); if (!original) return; var translated = mxT(original); if (translated !== original) { $el.text(translated); } }); // 4) Tech-Spec Labels (sicher per .text() zu ändern) $('.mx-spec-item .mx-spec-label').each(function () { var original = $(this).attr('data-mx-original') || $.trim($(this).text()); if (!original) return; var translated = mxT(original); if (translated !== original) { $(this).text(translated); } }); // 5) Tech-Spec Values $('.mx-spec-item .mx-spec-value').each(function () { var original = $.trim($(this).text()); if (!original) return; if (/^\d/.test(original)) return; var translated = mxT(original); if (translated !== original) { $(this).text(translated); } }); // 6) Tab-Header Texte $('.wc-tabs li a, .woocommerce-tabs .tabs li a, .elementor-tab-title').each(function () { var original = $.trim($(this).text()); if (!original) return; var translated = mxT(original); if (translated !== original) { $(this).text(translated); } }); // 7) Statische Texte $('.mx-tech-specs p, .mkl_pc_container .no-data-text').each(function () { var original = $.trim($(this).text()); if (!original) return; var translated = mxT(original); if (translated !== original) { $(this).text(translated); } }); // 8) Produkttitel + Artikel-ID Bereich $('.mx-variant-title, .product_title, h1.entry-title').each(function () { var $el = $(this); var original = $.trim($el.text()); if (!original) return; var translated = mxT(original); if (translated !== original) { $el.text(translated); } }); // 9) Breadcrumb (letztes Element = Produktname) $('.woocommerce-breadcrumb, .breadcrumbs').find('span:last, a:last').each(function () { var original = $.trim($(this).text()); if (!original) return; var translated = mxT(original); if (translated !== original) { $(this).text(translated); } }); // 10) Reset-Button Label ("Konfiguration zurücksetzen") $('.mx-reset-label').each(function () { var $outer = $(this); var $target = $outer.children('span').first(); if (!$target.length) $target = $outer; if ($target.hasClass('mx-tl')) return; var original = $.trim($target.text()); if (!original) return; var translated = mxT(original); if (translated && translated !== original) { $target.text(translated); } }); // 11) Hersteller-Bar Prefix ("Werkzeuge für") $('.mx-manufacturer-bar-prefix').each(function () { var $el = $(this); if ($el.hasClass('mx-tl')) return; var original = $.trim($el.text()); if (!original) return; var translated = mxT(original); if (translated && translated !== original) { $el.text(translated); } }); // 12) Maschinenhersteller-Reset Button ("Maschinenhersteller ändern") $('#mx-reset-manufacturer, .mx-reset-manufacturer').each(function () { var $el = $(this); if ($el.hasClass('mx-tl')) return; var original = $.trim($el.text()); if (!original) return; var translated = mxT(original); if (translated && translated !== original) { $el.text(translated); } }); // 13) Artikel-ID Label ("ARTIKEL ID ") $('.mx-variant-id-label').each(function () { var $el = $(this); if ($el.hasClass('mx-tl')) return; var raw = $el.text(); var trimmed = $.trim(raw); if (!trimmed) return; var translated = mxT(trimmed); if (translated && translated !== trimmed) { // Leerzeichen am Ende beibehalten (z.B. "ARTIKEL ID " → "ARTICLE ID ") var trailingSpace = raw.slice(trimmed.length); $el.text(translated + trailingSpace); } }); mxLog('✓ DOM translation complete'); } /** * MutationObserver: Wenn .selected-choice Text dynamisch geändert wird, * den .mx-tl Geschwister-Span automatisch aktualisieren. */ if (!MX_IS_DE && typeof MutationObserver !== 'undefined') { (function () { var selChoiceObserver = new MutationObserver(function (mutations) { for (var i = 0; i < mutations.length; i++) { var target = mutations[i].target; if (!target || !target.classList) continue; var isSelectedChoice = target.classList.contains('selected-choice'); if (!isSelectedChoice && target.parentElement) { isSelectedChoice = target.parentElement.classList.contains('selected-choice'); if (isSelectedChoice) target = target.parentElement; } if (isSelectedChoice) { var $el = $(target); var original = $.trim($el.text()); var translated = original ? mxT(original) : ''; if (original && translated !== original) { var $tl = $el.next('.mx-tl'); if ($tl.length) { $tl.text(translated); } else { var cls = ($el.attr('class') || '').replace(/\bmx-has-tl\b/g, '').trim(); $('').text(translated).insertAfter($el); } $el.addClass('mx-has-tl'); } else { $el.next('.mx-tl').remove(); $el.removeClass('mx-has-tl'); // Sichtbarkeit wiederherstellen (war per :not(.mx-show) CSS versteckt) $el.addClass('mx-show'); } } } }); setTimeout(function () { var container = document.querySelector('ul.layers') || document.querySelector('.mkl_pc_container'); if (container) { selChoiceObserver.observe(container, { childList: true, subtree: true, characterData: true }); } }, 500); })(); } function mxLog() { if (!DBG || !window.console) return; try { var args = Array.prototype.slice.call(arguments); args.unshift('[MX-DBG]'); console.log.apply(console, args); } catch (e) { } } function mxWarn() { if (!window.console) return; try { var args = Array.prototype.slice.call(arguments); args.unshift('[MX-DBG]'); console.warn.apply(console, args); } catch (e) { } } function mxErr() { if (!window.console) return; try { var args = Array.prototype.slice.call(arguments); args.unshift('[MX-DBG]'); console.error.apply(console, args); } catch (e) { } } var MX_DBG_REQ_COUNT = 0; var MX_AVAIL_XHR = null; var MX_AVAIL_SEQ = 0; var MX_ALL_CHOICES_CACHE = null; var MX_AVAIL_RESP_CACHE = new Map(); var MX_AVAIL_CACHE_TTL_MS = 5 * 60 * 1000; var MX_AVAIL_CACHE_MAX = 500; function mxStableStringify(obj) { if (!obj || typeof obj !== 'object') return String(obj); if (Array.isArray(obj)) return '[' + obj.map(mxStableStringify).join(',') + ']'; var keys = Object.keys(obj).sort(); var parts = []; for (var i = 0; i < keys.length; i++) { var k = keys[i]; parts.push(JSON.stringify(k) + ':' + mxStableStringify(obj[k])); } return '{' + parts.join(',') + '}'; } function mxMakeAvailCacheKey(productId, manufacturer, selectedOptions, ignoreSelections, heroOnly) { return [ 'p:', productId, '|m:', (manufacturer || ''), '|i:', ignoreSelections ? '1' : '0', '|h:', heroOnly ? '1' : '0', '|c:', (window.MX_LAST_CLICKED_LAYER || ''), '|s:', mxStableStringify(selectedOptions || {}) ].join(''); } function mxCacheGet(key) { var e = MX_AVAIL_RESP_CACHE.get(key); if (!e) return null; if ((Date.now() - e.t) > MX_AVAIL_CACHE_TTL_MS) { MX_AVAIL_RESP_CACHE.delete(key); return null; } // touch (LRU) MX_AVAIL_RESP_CACHE.delete(key); MX_AVAIL_RESP_CACHE.set(key, e); return e.v; } function mxCacheSet(key, value) { MX_AVAIL_RESP_CACHE.set(key, { t: Date.now(), v: value }); while (MX_AVAIL_RESP_CACHE.size > MX_AVAIL_CACHE_MAX) { var firstKey = MX_AVAIL_RESP_CACHE.keys().next().value; MX_AVAIL_RESP_CACHE.delete(firstKey); } } function safeUpdatePopupPosition() { if (window.MX_Popup && typeof window.MX_Popup.updatePosition === 'function') { window.MX_Popup.updatePosition(); } } function moveResetButtonToViewer() { var viewer = document.querySelector('.mkl_pc_viewer'); var footer = document.querySelector('footer.mkl_pc_footer'); if (!viewer || !footer) return; var btn = footer.querySelector('button.reset-configuration'); if (!btn) return; if (getComputedStyle(viewer).position === 'static') { viewer.style.position = 'relative'; } if (btn.parentNode !== viewer) { viewer.appendChild(btn); } btn.classList.add('mx-reset-in-viewer'); if (!btn.querySelector('.mx-reset-label')) { var labelSpan = document.createElement('span'); labelSpan.className = 'mx-reset-label'; var nodesToMove = []; for (var i = 0; i < btn.childNodes.length; i++) { var n = btn.childNodes[i]; var isSvgIcon = n.nodeType === 1 && n.tagName && n.tagName.toLowerCase() === 'svg' && n.classList && n.classList.contains('mx-reset-icon'); if (!isSvgIcon) nodesToMove.push(n); } nodesToMove.forEach(function (n) { labelSpan.appendChild(n); }); btn.appendChild(labelSpan); } if (!btn.querySelector('svg.mx-reset-icon')) { btn.insertAdjacentHTML( 'afterbegin', '' ); } if (!btn.getAttribute('aria-label')) { btn.setAttribute('aria-label', mxT('Zurücksetzen')); } if (!btn.classList.contains('mx-reset-bound')) { btn.classList.add('mx-reset-bound'); btn.addEventListener('click', function (e) { e.preventDefault(); e.stopPropagation(); if (window.MX_INITIAL_AUTO_SELECTION && typeof window.MX_INITIAL_AUTO_SELECTION === 'object') { MX_HERO_LOCK_ACTIVE = false; HAS_INTERACTED = false; MX_USER_JUST_CLICKED = {}; window.MX_LAST_CLICKED_LAYER = ''; applyAutoSelection(window.MX_INITIAL_AUTO_SELECTION, { skipAjax: false }); } else { clearAllSelections(); sendAvailability(true, false); } }); } } function debounce(fn, wait) { var timeout; return function () { var ctx = this; var args = arguments; clearTimeout(timeout); timeout = setTimeout(function () { fn.apply(ctx, args); }, wait); }; } var MX_PENDING_VARIANT_IMAGE = null; // hold variant image until selection stabilizes var HAS_INTERACTED = false; var imageCache = {}; var LAST_KNOWN_PK = null; // MX: global exponieren damit functions.php darauf zugreifen kann Object.defineProperty(window, 'LAST_KNOWN_PK', { get: function() { return LAST_KNOWN_PK; }, configurable: true }); var MX_HERO_LOCK_ACTIVE = false; var MX_INITIAL_AUTO_SELECTION = null; var MX_LAST_WRITTEN_CONFIG = null; var MX_LAST_WRITTEN_CONFIG_SOURCE = ''; var MX_LAST_WRITTEN_CONFIG_AT = 0; function mxCloneConfig(config) { if (!Array.isArray(config)) return []; return config.map(function (item) { var cloned = {}; for (var k in item) { if (item.hasOwnProperty(k)) cloned[k] = item[k]; } return cloned; }); } function mxReadHiddenConfigField() { var $field = $('form.cart').find('input[name="pc_configurator_data"]').first(); if (!$field.length) return []; try { var parsed = JSON.parse($field.val() || '[]'); return Array.isArray(parsed) ? parsed : []; } catch (e) { return []; } } function mxRememberSerializedConfig(config, source) { if (!Array.isArray(config) || !config.length) return; MX_LAST_WRITTEN_CONFIG = mxCloneConfig(config); MX_LAST_WRITTEN_CONFIG_SOURCE = source || ''; MX_LAST_WRITTEN_CONFIG_AT = Date.now(); } var CACHED_SELECTED_OPTIONS = null; var CACHE_TIMESTAMP = 0; var PNG_MAP = { 'STANDARD': 'Standard.png', 'PROFESSIONAL': 'Professional.png', 'HERO': 'Hero.png', 'DIAMOND': 'Diamond.png', 'PLUS PROFESSIONAL': 'Professional+.png', 'HERO R2': 'HERO R2.png' }; var ASSET_BASE = '/wp-content/plugins/mx-pc-conditions/assets/images/'; var ASSET_DIR_BY_TYPE = { editionTile: 'editions', editionSummary: 'editions-material', evolutionStage: 'evolutionsstufe', besatzTile: 'Besatz' }; // Produktname → Unterordner für Besatz-Bilder var BESATZ_PRODUCT_FOLDERS = { 'spiralrundbürste': 'Spiralrundbürste', 'spiralrundbuerste': 'Spiralrundbürste', 'tellerbürste': 'Tellerbürste', 'tellerburste': 'Tellerbürste' }; // Besatz-Optionen mit zugehörigem Bild-Dateinamen // Schlüssel: Label-Text (uppercase), Wert: Dateiname ohne Ordner var BESATZ_IMAGE_MAP = { 'F': 'F.png', 'FS': 'FS.png', 'S': 'S.png', 'SMS': 'SMS.png', 'TF': 'TF.png', 'W': 'W.png' }; function getProductFolderKey() { var cats = window.MX_LAST_CATEGORIES; if (Array.isArray(cats) && cats.length) { var s = cats.join(' ').toLowerCase(); if (s.indexOf('entgratteller') !== -1) return 'Entgratteller'; if (s.indexOf('entgratwalze') !== -1) return 'Entgratwalze'; if (s.indexOf('fiberscheibe') !== -1) return 'Fiberscheibe'; if (s.indexOf('entgratbürstensegment') !== -1 || s.indexOf('entgratbuerstensegment') !== -1) return 'Entgratbürstensegment'; if (s.indexOf('entgratblock') !== -1) return 'Entgratblock'; if (s.indexOf('entgratbürstenpinsel') !== -1) return 'Entgratbürstenpinsel'; if (s.indexOf('lamellenschleifrad') !== -1) return 'Lamellenschleifrad'; if (s.indexOf('schleifbürstenteller') !== -1) return 'Schleifbürstenteller'; if (s.indexOf('schleifbürste') !== -1) return 'Schleifbürste'; if (s.indexOf('entgratbürstenteller') !== -1) return 'Entgratbürstenteller'; if (s.indexOf('schleifgewebebogen') !== -1) return 'Schleifgewebebogen'; if (s.indexOf('schleifgewebeband') !== -1) return 'Schleifgewebeband'; if (s.indexOf('schleifpapierband') !== -1) return 'Schleifpapierband'; if (s.indexOf('schleifstern') !== -1) return 'Schleifstern'; if (s.indexOf('schleifklettscheibe') !== -1) return 'Schleifklettscheibe'; if (s.indexOf('entgratsegment') !== -1) return 'Entgratsegment'; if (s.indexOf('schleifvliesteller') !== -1) return 'Schleifvliesteller'; if (s.indexOf('oxidbürste') !== -1 || s.indexOf('oxidbuerste') !== -1) return 'Oxidbürste'; if (s.indexOf('reinigungsvlies') !== -1) return 'Reinigungsvlies'; if (s.indexOf('kraftband') !== -1) return 'Kraftband'; } var title = (window.MX_PRODUCT_TITLE || '').toLowerCase(); if (title.indexOf('entgratteller') !== -1) return 'Entgratteller'; if (title.indexOf('entgratwalze') !== -1) return 'Entgratwalze'; if (title.indexOf('fiberscheibe') !== -1) return 'Fiberscheibe'; if (title.indexOf('entgratbürstensegment') !== -1 || title.indexOf('entgratbuerstensegment') !== -1) return 'Entgratbürstensegment'; if (title.indexOf('entgratblock') !== -1) return 'Entgratblock'; if (title.indexOf('entgratbürstenpinsel') !== -1) return 'Entgratbürstenpinsel'; if (title.indexOf('lamellenschleifrad') !== -1) return 'Lamellenschleifrad'; if (title.indexOf('schleifbürstenteller') !== -1) return 'Schleifbürstenteller'; if (title.indexOf('schleifbürste') !== -1) return 'Schleifbürste'; if (title.indexOf('entgratbürstenteller') !== -1) return 'Entgratbürstenteller'; if (title.indexOf('schleifgewebebogen') !== -1) return 'Schleifgewebebogen'; if (title.indexOf('schleifgewebeband') !== -1) return 'Schleifgewebeband'; if (title.indexOf('schleifpapierband') !== -1) return 'Schleifpapierband'; if (title.indexOf('schleifstern') !== -1) return 'Schleifstern'; if (title.indexOf('schleifklettscheibe') !== -1) return 'Schleifklettscheibe'; if (title.indexOf('entgratsegment') !== -1) return 'Entgratsegment'; if (title.indexOf('schleifvliesteller') !== -1) return 'Schleifvliesteller'; if (title.indexOf('oxidbürste') !== -1 || title.indexOf('oxidbuerste') !== -1) return 'Oxidbürste'; if (title.indexOf('reinigungsvlies') !== -1) return 'Reinigungsvlies'; if (title.indexOf('kraftband') !== -1) return 'Kraftband'; if (title.indexOf('spiralrundbürste') !== -1 || title.indexOf('spiralrundbuerste') !== -1) return 'Spiralrundbürste'; if (title.indexOf('tellerbürste') !== -1 || title.indexOf('tellerburste') !== -1) return 'Tellerbürste'; return ''; } function getBesatzBasePath() { var title = (window.MX_PRODUCT_TITLE || '').toLowerCase(); var folder = null; for (var key in BESATZ_PRODUCT_FOLDERS) { if (BESATZ_PRODUCT_FOLDERS.hasOwnProperty(key) && title.indexOf(key) !== -1) { folder = BESATZ_PRODUCT_FOLDERS[key]; break; } } if (!folder) return null; // kein bekanntes Produkt → kein Tile-Modus return ASSET_BASE + folder + '/'; } function getAssetBasePath(type) { var dir = ASSET_DIR_BY_TYPE[type] || ''; if (!dir) return ASSET_BASE; var folder = getProductFolderKey(); return ASSET_BASE + dir + '/' + (folder ? (folder + '/') : ''); } var EDITION_PREFIX_BY_EVO = { 'STANDARD': 'S-', 'PROFESSIONAL': 'P-', 'HERO': 'H-', 'PLUS PROFESSIONAL': 'PP-', 'HERO R2': 'HR2-' }; var EDITION_FILE_PART = { 'BLUE': 'Blue', 'BROWN': 'Brown', 'DARK BROWN': 'Dark-Brown', 'DARK-BROWN': 'Dark-Brown', 'GOLD': 'Gold', 'GREEN': 'Green', 'GREY': 'Grey', 'GRAY': 'Grey', 'PURPLE': 'Purple', 'RED': 'Red', 'SYNTHETIC': 'Synthetic', 'CUBITRON II': 'Cubi', '987C CUBITRON II': '987C CUBITRON II', '982C CUBITRON II': '982C CUBITRON II', 'ACTIROX AF799': 'ACTIROX AF799', 'ACTIROX AF890': 'ACTIROX AF890', 'VLIESBAND': 'Vliesband', 'VLIESBOGEN': 'Vliesbogen', 'KRAFTBAND': 'Kraftband', 'KRAFTBAND BG': 'Kraftband BG' }; var EDITION_NO_EVO = { '987C CUBITRON II': true, '982C CUBITRON II': true, 'ACTIROX AF799': true, 'ACTIROX AF890': true, 'VLIESBAND': true, 'VLIESBOGEN': true, 'KRAFTBAND': true, 'KRAFTBAND BG': true }; function ensureEditionDisabledStyles() { if (document.getElementById('mx-edition-disabled-style')) return; var css = ".mkl_pc_viewer.mx-variant-loading { cursor: progress; } " + "ul.layers > li.layers-list-item.mx-edition-layer li.choice.mx-disabled, " + "ul.layers > li.layers-list-item.mx-edition-layer li.choice.not-available { " + "opacity: .35; filter: grayscale(1); pointer-events: auto !important; cursor: not-allowed !important; " + "} " + "ul.layers > li.layers-list-item.mx-edition-layer li.choice.mx-disabled button.choice-item, " + "ul.layers > li.layers-list-item.mx-edition-layer li.choice.not-available button.choice-item { " + "pointer-events: none !important; cursor: not-allowed !important; " + "} "; var style = document.createElement('style'); style.id = 'mx-edition-disabled-style'; style.type = 'text/css'; style.appendChild(document.createTextNode(css)); document.head.appendChild(style); } var AUFNAHME_CATEGORY_PATTERNS = { 'BOHRUNG': [/^BOHRUNG/i, /^(?:◯|Ø)?\s*\d+(?:,\d+)?\s*MM/i], 'GEWINDE': [/^GEWINDE/i, /^M\d+/i], 'SCHNELLSPANN': [/SCHNELLSPANN/i, /^COSTA/i, /^QUICK/i], 'SCHAFT': [/^SCHAFT/i], 'AUFNAHMEBOLZEN': [/^AUFNAHMEBOLZEN/i] }; var AUFNAHME_CATEGORY_ORDER = ['BOHRUNG', 'GEWINDE', 'SCHNELLSPANN', 'SCHAFT', 'AUFNAHMEBOLZEN']; var MANUFACTURER_SELECT = '#form-field-herstellerAuswahl,' + '#herstellerAuswahl,' + 'select#hersteller,' + 'select[id*="herstellerAuswahl"],' + 'select[name*="herstellerAuswahl"],' + 'select[id*="hersteller"],' + 'select[name*="hersteller"]'; var HAS_INITIAL_CONFIG = !!( window.MX_INITIAL_CONFIG && typeof window.MX_INITIAL_CONFIG === 'object' && Object.keys(window.MX_INITIAL_CONFIG).length > 0 ); window.MX_HAS_INITIAL_CONFIG = false; var URL_HAS_LOAD_CONFIG_FROM_CART = window.location.search.indexOf('load_config_from_cart=') !== -1; var URL_HAS_LOAD_CONFIG_FROM_ORDER = window.location.search.indexOf('load_config_from_order=') !== -1; if (URL_HAS_LOAD_CONFIG_FROM_CART || URL_HAS_LOAD_CONFIG_FROM_ORDER) { HAS_INITIAL_CONFIG = false; } var MX_APPLYING_FALLBACK = false; var MX_AVAILABILITY_REENTRY_GUARD = false; var MX_SUPPRESS_AVAIL = false; var MX_AVAIL_DIRTY = false; var MX_RECALC_TIMER = null; function mxBeginBatchAvailability() { MX_SUPPRESS_AVAIL = true; MX_AVAIL_DIRTY = false; mxLog('Begin batch availability (suppress requests)'); } function mxEndBatchAvailability(cb) { MX_SUPPRESS_AVAIL = false; mxLog('End batch availability', { dirty: MX_AVAIL_DIRTY }); if (MX_AVAIL_DIRTY) { MX_AVAIL_DIRTY = false; mxLog('Batch dirty -> firing one availability request'); sendAvailability(false, false, cb); } else { if (typeof cb === 'function') cb(); } } function mxScheduleRecalc() { if (MX_SUPPRESS_AVAIL) { MX_AVAIL_DIRTY = true; mxLog('Recalc requested while suppressed -> marked dirty'); return; } if (MX_RECALC_TIMER) return; MX_RECALC_TIMER = setTimeout(function () { MX_RECALC_TIMER = null; if (MX_AVAIL_DIRTY) { MX_AVAIL_DIRTY = false; mxLog('Scheduled recalc fired -> sending availability'); sendAvailability(false, false); } }, 120); } function txt($el) { // FIX-1: Nach Translation enthält das Element BEIDE Texte (DE original + EN .mx-tl span). // .text() würde z.B. "Zweireihig Double Row" zurückgeben → Match schlägt fehl. // Lösung: .mx-tl bevorzugen, sonst Original ohne .mx-tl Kinder. var $tl = $el.find('.mx-tl').first(); if ($tl.length) { var tlText = $.trim(($tl.text() || '').replace(/\s+/g, ' ')); if (window.MX_DBG_TXT) console.log('[MX-TXT] using .mx-tl:', tlText, '| from:', $el[0]); return tlText; } var $clone = $el.clone(); $clone.find('.mx-tl').remove(); var origText = $.trim(($clone.text() || '').replace(/\s+/g, ' ')); if (window.MX_DBG_TXT) console.log('[MX-TXT] using original:', origText, '| from:', $el[0]); return origText; } function objSize(o) { return (o && typeof o === 'object') ? Object.keys(o).length : 0; } function parseChoiceId(id) { var m = String(id || '').match(/^choice_(\d+)_(.+)$/); return m ? { layerId: String(m[1]), choiceId: String(m[2]) } : null; } // --- Guided Mode: First layer always shows all possible values (unfiltered) --- function mxGetFirstLayerId() { // first visible layer in configurator list var $first = $('ul.layers > li.layers-list-item:visible').first(); if (!$first.length) return null; var layerId = String($first.attr('data-layer') || ''); if (!layerId) { var $ul = $first.find('.layer_choices .choices-list ul[data-layer-id]').first(); if ($ul.length) layerId = String($ul.attr('data-layer-id') || ''); } return layerId || null; } function isChoiceEnabled($choice) { if (!$choice || !$choice.length) return false; var $btn = $choice.find('button.choice-item').first(); if (!$btn.length) return false; var disabledByClass = $choice.hasClass('mx-disabled') || $choice.hasClass('not-available'); var disabledByAttr = !!$btn.prop('disabled') || $btn.attr('aria-disabled') === 'true'; return !disabledByClass && !disabledByAttr; } function setChoiceDisabled($choice, disabled) { if (!$choice || !$choice.length) return; var $btn = $choice.find('button.choice-item').first(); if (!$btn.length) return; // ✅ FIX: Dirty-check — nur DOM ändern wenn nötig var isCurrentlyDisabled = $choice.hasClass('mx-disabled'); if (disabled && isCurrentlyDisabled) return; if (!disabled && !isCurrentlyDisabled) return; if (disabled) { $choice.addClass('mx-disabled not-available'); $btn .prop('disabled', true) .attr('aria-disabled', 'true') .attr('tabindex', '-1'); } else { $choice.removeClass('mx-disabled not-available'); $btn .prop('disabled', false) .removeAttr('disabled') .removeAttr('aria-disabled') .removeAttr('tabindex'); } } function getActiveChoice($layer) { var $active = $layer.find( '.layer_choices li.choice.active, ' + '.layer_choices li.choice.selected, ' + '.layer_choices li.choice.mxactive' ).first(); if (!$active.length) { $active = $layer.find('.layer_choices li.choice button.choice-item[aria-pressed="true"]').closest('li.choice').first(); } return $active; } function setCookie(name, value, days) { var expires = ''; if (days) { var d = new Date(); d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000)); expires = '; expires=' + d.toUTCString(); } document.cookie = name + '=' + encodeURIComponent(value || '') + expires + '; path=/'; } function getCookie(name) { var m = document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)'); return m ? decodeURIComponent(m.pop()) : ''; } function normalizeManufacturerValue(raw) { raw = decodeURIComponent((raw || '') + '').trim(); if (!raw) return ''; var target = raw.toLowerCase(); var found = ''; // 1. Versuch: gegen geladene