Files
wordpress-theme-aksrt/assets/js/header-newadd.js
T
kate522 0d9db942f8 feat(nav): close P0/P1 parity gaps (nav style, history, plate, admin build)
Wire header_nav_style transparent/blur, login history sync, plate publish
type, clean dead search CSS, rebuild admin SPA locally (build gitignored).
2026-07-22 17:38:48 +08:00

178 lines
5.0 KiB
JavaScript

/**
* Header multi-type publish menu: portal dropdown to document.body.
*
* Keeps the pink chip content-sized. The menu is position:fixed under the
* toggle and never participates in the chip's layout width.
*
* @package AKSRT
*/
(function () {
'use strict';
var openRoot = null;
var openMenu = null;
var openToggle = null;
var closeTimer = null;
function clearCloseTimer() {
if (closeTimer) {
clearTimeout(closeTimer);
closeTimer = null;
}
}
function placeMenu(toggle, menu) {
var rect = toggle.getBoundingClientRect();
var menuWidth = 168;
var left = rect.right - menuWidth;
if (left < 8) left = 8;
if (left + menuWidth > window.innerWidth - 8) {
left = Math.max(8, window.innerWidth - menuWidth - 8);
}
menu.style.position = 'fixed';
menu.style.top = Math.round(rect.bottom + 6) + 'px';
menu.style.left = Math.round(left) + 'px';
menu.style.right = 'auto';
menu.style.width = menuWidth + 'px';
menu.style.minWidth = menuWidth + 'px';
menu.style.maxWidth = menuWidth + 'px';
menu.style.zIndex = '2000';
}
function closeMenu() {
clearCloseTimer();
if (!openMenu) return;
openMenu.classList.remove('is-open');
openMenu.setAttribute('hidden', '');
openMenu.setAttribute('aria-hidden', 'true');
if (openToggle && openToggle.setAttribute) openToggle.setAttribute('aria-expanded', 'false');
if (openRoot) openRoot.classList.remove('is-open');
// Return menu to original root so SSR structure stays consistent.
if (openRoot && openMenu.parentNode !== openRoot) {
openRoot.appendChild(openMenu);
}
openRoot = null;
openMenu = null;
openToggle = null;
}
function openMenuFor(root) {
var toggle = root.querySelector('.newadd-btns__toggle');
var menu = root.querySelector('.drop-newadd');
if (!toggle || !menu) return;
if (toggle.tagName === 'SPAN' || toggle.tagName === 'DIV') {
toggle.setAttribute('role', 'button');
toggle.setAttribute('tabindex', '0');
if (!toggle.hasAttribute('aria-expanded')) toggle.setAttribute('aria-expanded', 'false');
}
if (openRoot && openRoot !== root) closeMenu();
clearCloseTimer();
openRoot = root;
openMenu = menu;
openToggle = toggle;
if (menu.parentNode !== document.body) {
document.body.appendChild(menu);
}
menu.removeAttribute('hidden');
menu.setAttribute('aria-hidden', 'false');
menu.classList.add('is-open');
root.classList.add('is-open');
if (toggle.setAttribute) toggle.setAttribute('aria-expanded', 'true');
placeMenu(toggle, menu);
}
function scheduleClose() {
clearCloseTimer();
closeTimer = setTimeout(closeMenu, 160);
}
function onPointerEnterRoot(e) {
var root = e.currentTarget;
openMenuFor(root);
}
function onPointerLeaveRoot() {
scheduleClose();
}
function onPointerEnterMenu() {
clearCloseTimer();
}
function onPointerLeaveMenu() {
scheduleClose();
}
function onToggleClick(e) {
e.preventDefault();
e.stopPropagation();
var root = e.currentTarget.closest('[data-aksrt-newadd="1"]');
if (!root) return;
if (openRoot === root) {
closeMenu();
} else {
openMenuFor(root);
}
}
function onDocPointerDown(e) {
if (!openRoot) return;
if (openRoot.contains(e.target)) return;
if (openMenu && openMenu.contains(e.target)) return;
closeMenu();
}
function onKey(e) {
if (e.key === 'Escape') closeMenu();
}
function onScrollOrResize() {
if (!openToggle || !openMenu) return;
placeMenu(openToggle, openMenu);
}
function bindRoot(root) {
if (root.getAttribute('data-aksrt-newadd-bound') === '1') return;
root.setAttribute('data-aksrt-newadd-bound', '1');
var toggle = root.querySelector('.newadd-btns__toggle');
var menu = root.querySelector('.drop-newadd');
if (!toggle || !menu) return;
if (toggle.tagName === 'SPAN' || toggle.tagName === 'DIV') {
toggle.setAttribute('role', 'button');
toggle.setAttribute('tabindex', '0');
if (!toggle.hasAttribute('aria-expanded')) toggle.setAttribute('aria-expanded', 'false');
}
// CSS hover no longer drives this control.
root.classList.add('is-js-portal');
root.addEventListener('mouseenter', onPointerEnterRoot);
root.addEventListener('mouseleave', onPointerLeaveRoot);
toggle.addEventListener('click', onToggleClick);
toggle.addEventListener('focus', function () {
openMenuFor(root);
});
menu.addEventListener('mouseenter', onPointerEnterMenu);
menu.addEventListener('mouseleave', onPointerLeaveMenu);
}
function init() {
document.querySelectorAll('[data-aksrt-newadd="1"]').forEach(bindRoot);
document.addEventListener('pointerdown', onDocPointerDown, true);
document.addEventListener('keydown', onKey);
window.addEventListener('scroll', onScrollOrResize, true);
window.addEventListener('resize', onScrollOrResize);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();