(function () { 'use strict'; function qs(sel, root) { return (root || document).querySelector(sel); } function qsa(sel, root) { return Array.prototype.slice.call((root || document).querySelectorAll(sel)); } function getCfg() { return (window.SU_PRODUCTS_CARDS || {}); } function postAjax(action, data) { var cfg = getCfg(); var fd = new FormData(); fd.append('action', action); fd.append('nonce', cfg.nonce || ''); // ✅ critical: pass master_id for access gate (user#7 only in own cabinet) if (typeof cfg.master_id !== 'undefined' && cfg.master_id !== null) { fd.append('master_id', String(cfg.master_id)); } for (var k in data) { if (!Object.prototype.hasOwnProperty.call(data, k)) continue; fd.append(k, data[k]); } return fetch(cfg.ajax_url, { method: 'POST', credentials: 'same-origin', body: fd }).then(function (r) { return r.json(); }); } // ===== View switch (list/grid) ===== function initViewSwitch() { var wrap = qs('.su-products-cards-wrap'); if (!wrap) return; var buttons = qsa('.su-products-view-btn', wrap); var panels = qsa('.su-products-view-panel', wrap); function apply(view) { if (!view) view = 'list'; buttons.forEach(function (b) { var isOn = (b.getAttribute('data-view') === view); b.classList.toggle('is-active', isOn); b.setAttribute('aria-selected', isOn ? 'true' : 'false'); }); panels.forEach(function (p) { var isOn = (p.getAttribute('data-panel') === view); p.classList.toggle('is-active', isOn); }); try { window.localStorage.setItem('su_products_cards_view', view); } catch (e) {} } var saved = null; try { saved = window.localStorage.getItem('su_products_cards_view'); } catch (e) {} if (saved === 'grid' || saved === 'list') { apply(saved); } else { apply('list'); } buttons.forEach(function (b) { b.addEventListener('click', function () { apply(b.getAttribute('data-view') || 'list'); }); }); } // ===== Popup: move to BODY so fixed works even inside transformed containers ===== function ensurePopupInBody() { var popup = qs('[data-su-folders-popup]'); if (!popup) return null; if (popup.parentNode && popup.parentNode !== document.body) { document.body.appendChild(popup); } return popup; } function lockBodyScroll(lock) { if (lock) { document.documentElement.classList.add('su-modal-open'); document.body.classList.add('su-modal-open'); } else { document.documentElement.classList.remove('su-modal-open'); document.body.classList.remove('su-modal-open'); } } function renderPopupShell(titleHtml) { // контейнер .su-folders-popup = overlay, всередині .su-folders-popup__inner = вікно return '' + ''; } function escapeHtml(s) { s = String(s == null ? '' : s); return s.replace(/[&<>"']/g, function (m) { return ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[m]; }); } function showPopupNotice(type, text, ms) { var popup = ensurePopupInBody(); if (!popup) return; var body = qs('[data-su-popup-body]', popup); if (!body) return; var notice = document.createElement('div'); notice.className = 'su-folders-popup__msg ' + (type === 'err' ? 'is-err' : 'is-ok'); notice.textContent = String(text || ''); // показуємо над контентом попапа body.prepend(notice); window.setTimeout(function () { if (notice && notice.parentNode) { notice.parentNode.removeChild(notice); } }, (typeof ms === 'number' ? ms : 2000)); } function openPopupForPost(postId) { var cfg = getCfg(); if (!cfg.actions) return; var popup = ensurePopupInBody(); if (!popup) return; popup.setAttribute('aria-hidden', 'false'); popup.style.display = 'block'; popup.innerHTML = renderPopupShell(' Керування папками товару'); lockBodyScroll(true); var body = qs('[data-su-popup-body]', popup); if (body) body.innerHTML = '
' + (cfg.texts && cfg.texts.loading ? cfg.texts.loading : 'Завантаження…') + '
'; postAjax(cfg.actions.popup, { post_id: postId }) .then(function (res) { if (!res || !res.success) { var msg = (res && res.data && res.data.message) ? res.data.message : 'Помилка завантаження.'; if (body) body.innerHTML = '
' + msg + '
'; return; } var used = (res.data && res.data.used) ? res.data.used : []; var current = (res.data && res.data.current) ? res.data.current : []; var currentMap = {}; current.forEach(function (t) { currentMap[String(t.id)] = true; }); var html = ''; html += '
Додати або видалити товар з папки:
'; if (used.length) { html += '
'; used.forEach(function (t) { var isActive = !!currentMap[String(t.id)]; html += '' + '' + ''; }); html += '
'; } else { html += '
Папок ще немає.
'; } html += '
Клік по папці додає або видаляє товар з неї. Видалення папки — видаляє її для усіх товарів.
'; html += '
'; html += '
Створити нову папку:
'; html += '
'; html += ' '; html += ' '; html += '
'; html += '
'; html += '
'; if (body) body.innerHTML = html; }) .catch(function () { if (body) body.innerHTML = '
Помилка запиту.
'; }); } function closePopup() { var popup = ensurePopupInBody(); if (!popup) return; popup.setAttribute('aria-hidden', 'true'); popup.style.display = 'none'; popup.innerHTML = ''; lockBodyScroll(false); } function updateBadgeForPost(postId, tagCount) { var buttons = qsa('[data-su-folder-btn][data-post-id="' + String(postId) + '"]'); buttons.forEach(function (btn) { var badge = qs('.su-folder-badge', btn); if (tagCount > 0) { if (!badge) { badge = document.createElement('span'); badge.className = 'su-folder-badge'; badge.setAttribute('aria-hidden', 'true'); btn.appendChild(badge); } badge.textContent = String(tagCount); } else { if (badge) badge.parentNode.removeChild(badge); } }); } // ✅ FIX: після AJAX-оновлення папок переписуємо href, щоб не вели на admin-ajax.php function fixTopFolderLinks() { var wrap = qs('[data-su-folders-top-list]'); if (!wrap) return; var chips = qsa('a.su-folder-chip', wrap); if (!chips.length) return; var currentUrl; try { currentUrl = new URL(window.location.href); } catch (e) { return; // дуже старий браузер — просто нічого не робимо } chips.forEach(function (a) { var href = a.getAttribute('href') || ''; // якщо це вже нормальний лінк на сторінку кабінету — не чіпаємо if (href && href.indexOf('admin-ajax.php') === -1) return; // витягнути su_folder з "поганого" href var termId = null; try { var bad = new URL(href, window.location.origin); if (bad.searchParams && bad.searchParams.has('su_folder')) { termId = bad.searchParams.get('su_folder'); } } catch (e2) { // fallback regex var m = href.match(/[?&]su_folder=([0-9]+)/); if (m) termId = m[1]; } // зібрати правильний href на поточну сторінку var good = new URL(currentUrl.toString()); // ✅ КРИТИЧНО: прибираємо пагінацію, інакше в папках буде 0 товарів good.searchParams.delete('offset'); good.searchParams.delete('paged'); good.searchParams.delete('page'); if (termId && String(termId) !== '0') { good.searchParams.set('su_folder', String(termId)); } else { good.searchParams.delete('su_folder'); } a.setAttribute('href', good.toString()); }); } function refreshTopFolders(html) { var wrap = qs('[data-su-folders-top-list]'); if (!wrap) return; wrap.innerHTML = html || ''; fixTopFolderLinks(); // ✅ ключова правка } // ===== Delegated events ===== function initFoldersEvents() { var cfg = getCfg(); if (!cfg.actions) return; document.addEventListener('click', function (e) { // open popup var openBtn = e.target.closest && e.target.closest('[data-su-folder-btn]'); if (openBtn) { e.preventDefault(); var postId = parseInt(openBtn.getAttribute('data-post-id') || '0', 10); if (postId) openPopupForPost(postId); return; } // close popup button var closeBtn = e.target.closest && e.target.closest('[data-su-popup-close]'); if (closeBtn) { e.preventDefault(); closePopup(); return; } // click on overlay outside inner -> close var popup = qs('[data-su-folders-popup]'); if (popup && popup.style.display === 'block') { if (e.target === popup) { closePopup(); return; } } // assign/unassign folder var itemBtn = e.target.closest && e.target.closest('[data-su-folder-item]'); if (itemBtn) { e.preventDefault(); var termId = parseInt(itemBtn.getAttribute('data-term-id') || '0', 10); var postId2 = parseInt(itemBtn.getAttribute('data-post-id') || '0', 10); if (!termId || !postId2) return; var isActive = itemBtn.classList.contains('is-active'); var action = isActive ? cfg.actions.unassign : cfg.actions.assign; itemBtn.classList.add('is-loading'); postAjax(action, { post_id: postId2, term_id: termId }) .then(function (res) { itemBtn.classList.remove('is-loading'); if (!res || !res.success) { return; } var tagCount = (res.data && typeof res.data.tag_count !== 'undefined') ? parseInt(res.data.tag_count, 10) : 0; updateBadgeForPost(postId2, tagCount); // оновити top folders (там уже є count) if (res.data && res.data.folders_html) { refreshTopFolders(res.data.folders_html); } // перерисувати стан в попапі if (isActive) { itemBtn.classList.remove('is-active'); var mark = qs('.su-folders-popup__mark', itemBtn); if (mark) mark.textContent = ''; } else { itemBtn.classList.add('is-active'); var mark2 = qs('.su-folders-popup__mark', itemBtn); if (mark2) mark2.textContent = '✓'; } }) .catch(function () { itemBtn.classList.remove('is-loading'); }); return; } // create folder var createBtn = e.target.closest && e.target.closest('[data-su-folder-create]'); if (createBtn) { e.preventDefault(); var postId3 = parseInt(createBtn.getAttribute('data-post-id') || '0', 10); if (!postId3) return; var popup2 = ensurePopupInBody(); var input = popup2 ? qs('[data-su-folder-new-name]', popup2) : null; var msg = popup2 ? qs('[data-su-folder-msg]', popup2) : null; var name = input ? String(input.value || '').trim() : ''; if (!name) { if (msg) { msg.className = 'su-folders-popup__msg is-err'; msg.textContent = 'Вкажи назву папки.'; } return; } createBtn.disabled = true; if (msg) { msg.className = 'su-folders-popup__msg'; msg.textContent = (cfg.texts && cfg.texts.creating) ? cfg.texts.creating : 'Створюю…'; } postAjax(cfg.actions.create, { post_id: postId3, name: name }) .then(function (res) { createBtn.disabled = false; if (!res || !res.success) { var em = (res && res.data && res.data.message) ? res.data.message : 'Помилка.'; if (msg) { msg.className = 'su-folders-popup__msg is-err'; msg.textContent = em; } return; } if (input) input.value = ''; if (msg) { msg.className = 'su-folders-popup__msg is-ok'; msg.textContent = (res.data && res.data.message) ? res.data.message : 'Готово.'; } var tagCount = (res.data && typeof res.data.tag_count !== 'undefined') ? parseInt(res.data.tag_count, 10) : 0; updateBadgeForPost(postId3, tagCount); if (res.data && res.data.folders_html) { refreshTopFolders(res.data.folders_html); } // Перевідкрити попап, щоб список папок був актуальний openPopupForPost(postId3); }) .catch(function () { createBtn.disabled = false; if (msg) { msg.className = 'su-folders-popup__msg is-err'; msg.textContent = 'Помилка запиту.'; } }); return; } // delete folder (БЕЗ confirm) + коротке повідомлення, що зникає var delBtn = e.target.closest && e.target.closest('[data-su-folder-delete]'); if (delBtn) { e.preventDefault(); var termId2 = parseInt(delBtn.getAttribute('data-term-id') || '0', 10); if (!termId2) return; delBtn.disabled = true; postAjax(cfg.actions.delete, { term_id: termId2 }) .then(function (res) { delBtn.disabled = false; if (!res || !res.success) { showPopupNotice('err', 'Не вдалося видалити папку.', 2200); return; } // оновити верхній список папок if (res.data && res.data.folders_html) { refreshTopFolders(res.data.folders_html); } // прибрати рядок папки з попапа (item + trash) var popup3 = ensurePopupInBody(); if (popup3) { var item = qs('[data-su-folder-item][data-term-id="' + String(termId2) + '"]', popup3); var trash = qs('[data-su-folder-delete][data-term-id="' + String(termId2) + '"]', popup3); if (item && item.parentNode) item.parentNode.removeChild(item); if (trash && trash.parentNode) trash.parentNode.removeChild(trash); } // коротке повідомлення showPopupNotice('ok', 'Папку видалено.', 1800); }) .catch(function () { delBtn.disabled = false; showPopupNotice('err', 'Помилка запиту.', 2200); }); return; } }); // ESC close document.addEventListener('keydown', function (e) { if (e.key === 'Escape' || e.keyCode === 27) { var popup = qs('[data-su-folders-popup]'); if (popup && popup.style.display === 'block') { closePopup(); } } }); } // ===== init ===== document.addEventListener('DOMContentLoaded', function () { initViewSwitch(); ensurePopupInBody(); // критично для модалки initFoldersEvents(); // ✅ на всяк випадок виправимо href-и одразу після завантаження сторінки fixTopFolderLinks(); }); })();

403 Forbidden

Ваш IP (216.73.216.110) заблокований системою безпеки.