Wire header_nav_style transparent/blur, login history sync, plate publish type, clean dead search CSS, rebuild admin SPA locally (build gitignored).
178 lines
5.0 KiB
JavaScript
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();
|
|
}
|
|
})();
|