From aab78c71e3a7a0914690a26dd5ecbf374277bbb2 Mon Sep 17 00:00:00 2001 From: Jacek Pyziak Date: Thu, 23 Oct 2025 21:41:20 +0200 Subject: [PATCH] Refactor custom button section: move .custom-buttons to a new position in the category description and add editing mode guard --- themes/classic/assets/js/custom.js | 159 +++++++++++++++++++++++++++-- 1 file changed, 151 insertions(+), 8 deletions(-) diff --git a/themes/classic/assets/js/custom.js b/themes/classic/assets/js/custom.js index 1df03750..5914e9ba 100644 --- a/themes/classic/assets/js/custom.js +++ b/themes/classic/assets/js/custom.js @@ -295,12 +295,155 @@ jQuery(document).ready(function ($) { $btnBox.removeClass('active') } }) -}) - -document.addEventListener('DOMContentLoaded', function() { - const buttons = document.querySelector('#category-description .custom-buttons'); - const target = document.querySelector('.row.\\31 11'); - if (buttons && target) { - target.parentNode.insertBefore(buttons, target); - } }); + +/* custom.js — LEKKIE przeniesienie sekcji .custom-buttons + Góra: klony top-level bloków (dzieci #category-description) z WYŁĄCZNIE .custom-buttons + Dół: oryginał bez sekcji .custom-buttons + NIE DZIAŁA podczas edycji w Elementor/Creative Elements. +*/ +(function () { + 'use strict'; + + // --- GUARD: nie uruchamiaj w trybie edycji (Elementor / Creative Elements) --- +function isEditing() { + var href = String(location.href || ''); + var ref = String(document.referrer || ''); + var topHref = ''; + try { topHref = String(window.top.location.href || ''); } catch (e) { /* cross-origin fallback */ } + + // Zbiorcza „słomka” do przeszukania (ramka, referrer, parent) + var haystack = (href + ' ' + ref + ' ' + topHref).toLowerCase(); + + // 1) Najpewniejsze: kontroler zaplecza CE + if (haystack.indexOf('controller=adminceeditor') !== -1) return true; + + // 2) Podgląd/edycja elementora/CE + if (haystack.indexOf('elementor-preview') !== -1) return true; + + // 3) Klasy/markery edytora na body w tej ramce + var body = document.body; + if (body && /\b(elementor-editor-active|ce-editor-active|ce-editing)\b/i.test(body.className)) return true; + + // 4) Panele edytora w oknie nadrzędnym (gdy front leci w iframe) + if (window.self !== window.top) { + try { + if (window.top.document.querySelector('#elementor-panel, .elementor-panel, #ce-editor, .ce-editor, .ce-panel')) { + return true; + } + } catch (e) { /* ignoruj brak dostępu */ } + } + + // 5) Ręczny wyłącznik + if (window.__CE_DISABLE_MOVE === true) return true; + + return false; +} + +// Wstaw ZARAZ po definicji isEditing() +if (isEditing()) return; + + var SOURCE_SEL = '#category-description'; + var TARGET_SEL = '.row.\\31 11'; // .row.111 (esc) + var WRAP_ID = 'moved-category-structure'; + var BUTTON_SEC = 'section.custom-buttons, section.custom-buttons1'; + var ANY_SEC = 'section'; // lub 'section.elementor-top-section' jeśli chcesz zawęzić + + var didFinish = false; + var obs = null; + var debounceId = null; + + function ensureWrapper(target) { + var wrap = document.getElementById(WRAP_ID); + if (!wrap) { + wrap = document.createElement('div'); + wrap.id = WRAP_ID; + wrap.className = 'moved-category-structure'; + target.parentNode.insertBefore(wrap, target); + } + return wrap; + } + + function topLevelBlocks(src) { + var out = []; + for (var i = 0; i < src.children.length; i++) { + var el = src.children[i]; + if (el.nodeType === 1) out.push(el); + } + return out; + } + + function cloneBlockWithOnlyButtons(block) { + var clone = block.cloneNode(true); + clone.querySelectorAll(ANY_SEC + ':not(.custom-buttons):not(.custom-buttons1)').forEach(function (sec) { + sec.remove(); + }); + clone.querySelectorAll('.ce-edit-btn, .ce-edit-outline').forEach(function (n) { n.remove(); }); + if (!clone.querySelector(BUTTON_SEC)) return null; + return clone; + } + + function syncOnce() { + if (didFinish) return true; + + var src = document.querySelector(SOURCE_SEL); + var target = document.querySelector(TARGET_SEL); + if (!src || !target) return false; + + var blocks = topLevelBlocks(src); + var blocksWithButtons = blocks.filter(function (b) { return !!b.querySelector(BUTTON_SEC); }); + if (!blocksWithButtons.length) return false; + + var wrap = ensureWrapper(target); + + var frag = document.createDocumentFragment(); + blocksWithButtons.forEach(function (b) { + var prunedClone = cloneBlockWithOnlyButtons(b); + if (prunedClone) frag.appendChild(prunedClone); + }); + + if (!frag.firstChild) return false; + + while (wrap.firstChild) wrap.removeChild(wrap.firstChild); + wrap.appendChild(frag); + + src.querySelectorAll(BUTTON_SEC).forEach(function (sec) { + if (sec && sec.parentNode) sec.parentNode.removeChild(sec); + }); + + didFinish = true; + if (obs) obs.disconnect(); + return true; + } + + function trySyncDebounced() { + if (debounceId) return; + debounceId = setTimeout(function () { + debounceId = null; + if (syncOnce() && obs) obs.disconnect(); + }, 50); + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', trySyncDebounced, { once: true }); + } else { + trySyncDebounced(); + } + + obs = new MutationObserver(trySyncDebounced); + obs.observe(document.body || document.documentElement, { childList: true, subtree: true }); + + if (window.prestashop && typeof window.prestashop.on === 'function') { + ['updateProductList', 'updatedCart', 'updatedProduct'].forEach(function (ev) { + window.prestashop.on(ev, trySyncDebounced); + }); + } + + (function hookHistory() { + var _ps = history.pushState, _rs = history.replaceState; + function onNav() { trySyncDebounced(); } + history.pushState = function () { _ps.apply(this, arguments); onNav(); }; + history.replaceState = function () { _rs.apply(this, arguments); onNav(); }; + window.addEventListener('popstate', onNav); + })(); +})();