111 lines
3.8 KiB
JavaScript
111 lines
3.8 KiB
JavaScript
(function (root, factory) {
|
|
if (typeof module === 'object' && module.exports) module.exports = factory;
|
|
else root.createMobileInsights = factory;
|
|
})(typeof self !== 'undefined' ? self : this, function (o) {
|
|
const route = '#/insights';
|
|
const events = o.eventTarget || self;
|
|
const location = o.location || self.location;
|
|
let active = false;
|
|
let previous = '#/my-work';
|
|
let retries = 0;
|
|
let backgroundInert = null;
|
|
|
|
function attr(element, name, value) {
|
|
if (value === null) element.removeAttribute(name);
|
|
else element.setAttribute(name, value);
|
|
}
|
|
|
|
function containBackground() {
|
|
if (backgroundInert) return;
|
|
backgroundInert = new Map(o.backgrounds.map(element => [element, element.inert]));
|
|
backgroundInert.forEach((_wasInert, element) => { element.inert = true; });
|
|
}
|
|
|
|
function releaseBackground() {
|
|
if (!backgroundInert) return;
|
|
backgroundInert.forEach((wasInert, element) => { element.inert = wasInert; });
|
|
backgroundInert = null;
|
|
}
|
|
|
|
function render(open, focus = false) {
|
|
const wasActive = active;
|
|
active = Boolean(open && o.mediaQuery.matches);
|
|
const detour = active ? o.detour?.() : null;
|
|
const started = detour?.beginDetour('insights');
|
|
if (detour && !started && retries++ < 40) setTimeout(sync, 250);
|
|
else if (started && retries) { retries = 0; setTimeout(sync, 500); }
|
|
else retries = 0;
|
|
if (wasActive && !active) o.detour?.()?.finishDetour();
|
|
attr(o.root, 'data-mobile-open', active ? 'true' : null);
|
|
attr(o.root, 'role', active ? 'dialog' : null);
|
|
attr(o.root, 'aria-modal', active ? 'true' : null);
|
|
attr(o.root, 'aria-hidden', active || !o.mediaQuery.matches ? null : 'true');
|
|
o.root.inert = !active && o.mediaQuery.matches;
|
|
if (active) containBackground();
|
|
else releaseBackground();
|
|
o.dock.hidden = active;
|
|
attr(o.hud, 'data-overlay-hidden', active ? 'true' : null);
|
|
if (active) o.closeButton.focus();
|
|
else if (focus) o.launcher.focus();
|
|
}
|
|
|
|
function url(hash) {
|
|
return (location.pathname || '') + (location.search || '') + hash;
|
|
}
|
|
|
|
function open() {
|
|
if (!o.mediaQuery.matches || active) return false;
|
|
previous = location.hash && location.hash !== route ? location.hash : '#/my-work';
|
|
const menu = o.menu || o.launcher.closest?.('details');
|
|
if (menu) menu.open = false;
|
|
o.history.pushState({ ...(o.history.state || {}), mobileInsights:true, previousHash:previous }, '', url(route));
|
|
render(true);
|
|
return true;
|
|
}
|
|
|
|
function sync() {
|
|
render(location.hash === route, active && location.hash !== route);
|
|
}
|
|
|
|
function close() {
|
|
if (!active) return false;
|
|
if (o.history.state?.mobileInsights) o.history.back();
|
|
else {
|
|
const state = { ...(o.history.state || {}) };
|
|
delete state.mobileInsights;
|
|
delete state.previousHash;
|
|
o.history.replaceState(state, '', url(previous));
|
|
render(false, true);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function returnToToday() {
|
|
if (!active) return false;
|
|
const state = { ...(o.history.state || {}) };
|
|
delete state.mobileInsights;
|
|
delete state.previousHash;
|
|
o.history.replaceState(state, '', url(previous));
|
|
render(false);
|
|
return true;
|
|
}
|
|
|
|
function start() {
|
|
o.launcher.addEventListener('click', open);
|
|
o.closeButton.addEventListener('click', close);
|
|
(o.returnButton || o.root.querySelector?.('[data-return-from-detour]'))?.addEventListener('click', returnToToday);
|
|
events.addEventListener('popstate', sync);
|
|
events.addEventListener('hashchange', sync);
|
|
events.addEventListener('keydown', event => {
|
|
if (active && event.key === 'Escape') {
|
|
event.preventDefault?.();
|
|
close();
|
|
}
|
|
});
|
|
o.mediaQuery.addEventListener?.('change', sync);
|
|
sync();
|
|
}
|
|
|
|
return { start, open, close, sync, current:() => active };
|
|
});
|