/** * AKSRT 文章导航页 — admin settings modal + HTML5 drag-sort (no SortableJS dependency). * TOC generation is handled by section-navs.js via [data-nav] + .posts-nav-box. * * @package AKSRT */ (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 ajaxUrl() { if (window.aksrtData && window.aksrtData.ajaxUrl) return window.aksrtData.ajaxUrl; if (window.ajaxurl) return window.ajaxurl; return '/wp-admin/admin-ajax.php'; } function toast(msg, type) { if (window.aksrt && typeof window.aksrt.toast === 'function') { window.aksrt.toast(msg, type || 'info'); return; } // eslint-disable-next-line no-alert window.alert(msg); } function initModal() { var modal = qs('#post-navs-sz'); if (!modal) return; function openModal(e) { if (e) e.preventDefault(); modal.classList.add('is-open', 'show'); modal.setAttribute('aria-hidden', 'false'); } function closeModal(e) { if (e) e.preventDefault(); modal.classList.remove('is-open', 'show'); modal.setAttribute('aria-hidden', 'true'); } qsa('[data-toggle="modal"][data-target="#post-navs-sz"], a[href="#post-navs-sz"]').forEach(function (el) { el.addEventListener('click', openModal); }); // Title [设置] uses data-target. qsa('[data-target="#post-navs-sz"]').forEach(function (el) { el.addEventListener('click', openModal); }); qsa('[data-dismiss="modal"]', modal).forEach(function (btn) { btn.addEventListener('click', closeModal); }); modal.addEventListener('click', function (e) { if (e.target === modal) closeModal(e); }); document.addEventListener('keydown', function (e) { if (e.key === 'Escape' && modal.classList.contains('is-open')) closeModal(e); }); } function initDragSort() { var left = qs('#cat-sortable'); var right = qs('#cat-sortable-ok'); if (!left || !right) return; var dragEl = null; function onDragStart(e) { dragEl = e.currentTarget; dragEl.classList.add('is-dragging'); try { e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/plain', dragEl.getAttribute('data-id') || ''); } catch (err) { /* IE */ } } function onDragEnd() { if (dragEl) dragEl.classList.remove('is-dragging'); dragEl = null; qsa('.cat-group').forEach(function (g) { g.classList.remove('is-drop-target'); }); } function bindItem(el) { el.setAttribute('draggable', 'true'); el.addEventListener('dragstart', onDragStart); el.addEventListener('dragend', onDragEnd); } qsa('.sortable-cat-item', left).forEach(bindItem); qsa('.sortable-cat-item', right).forEach(bindItem); [left, right].forEach(function (group) { group.addEventListener('dragover', function (e) { e.preventDefault(); group.classList.add('is-drop-target'); if (!dragEl) return; var after = getDragAfterElement(group, e.clientY); if (after == null) { group.appendChild(dragEl); } else { group.insertBefore(dragEl, after); } }); group.addEventListener('dragleave', function () { group.classList.remove('is-drop-target'); }); group.addEventListener('drop', function (e) { e.preventDefault(); group.classList.remove('is-drop-target'); }); }); function getDragAfterElement(container, y) { var els = qsa('.sortable-cat-item:not(.is-dragging)', container); var closest = { offset: Number.NEGATIVE_INFINITY, element: null }; els.forEach(function (child) { var box = child.getBoundingClientRect(); var offset = y - box.top - box.height / 2; if (offset < 0 && offset > closest.offset) { closest = { offset: offset, element: child }; } }); return closest.element; } } function initSave() { var form = qs('#aksrt-posts-navs-settings'); if (!form) return; form.addEventListener('submit', function (e) { e.preventDefault(); var ids = []; qsa('#cat-sortable-ok .sortable-cat-item').forEach(function (item) { var id = item.getAttribute('data-id'); if (id) ids.push(id); }); if (!ids.length) { toast('请选择需要显示的分类', 'danger'); return; } var fd = new FormData(form); fd.set('action', 'aksrt_post_navs_settings'); // PHP accepts array; append each. fd.delete('navs_show_cat_id'); ids.forEach(function (id) { fd.append('navs_show_cat_id[]', id); }); var btn = qs('button[type="submit"]', form); if (btn) btn.disabled = true; fetch(ajaxUrl(), { method: 'POST', body: fd, credentials: 'same-origin', }) .then(function (r) { return r.json(); }) .then(function (data) { if (!data || data.error) { toast((data && data.msg) || '保存失败', 'danger'); return; } toast(data.msg || '保存成功', 'success'); if (data.reload) { window.setTimeout(function () { window.location.reload(); }, 400); } }) .catch(function () { toast('网络错误', 'danger'); }) .finally(function () { if (btn) btn.disabled = false; }); }); } /** * Build simple TOC into .posts-nav-box if section-navs hasn't already. * Uses category h2 headings inside .posts-navs. */ function initFallbackToc() { var box = qs('.posts-nav-box'); var root = qs('.posts-navs[data-nav]'); if (!box || !root) return; if (box.querySelector('.posts-nav-lists, .aksrt-section-nav, .toc-list')) return; var headings = qsa('.title-theme h2, h2', root); if (headings.length < 1) return; var title = box.getAttribute('data-title') || '导航目录'; var list = ''; headings.forEach(function (h, i) { if (!h.id) h.id = 'navs-sec-' + i; list += '