(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 = '';
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 = '';
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 += '';
} else {
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) заблокований системою безпеки.