From e23f2745ddc3a3d8e723485a29f2be2ebb6a3457 Mon Sep 17 00:00:00 2001 From: Shogun Date: Fri, 18 Mar 2022 12:36:55 +0100 Subject: [PATCH] doc: refactored api script --- doc/api_assets/api.js | 182 ++++++++++++++++++++++++--------------- doc/api_assets/style.css | 9 +- 2 files changed, 121 insertions(+), 70 deletions(-) diff --git a/doc/api_assets/api.js b/doc/api_assets/api.js index 1816f7b2c79ce4..546722cd908ce7 100644 --- a/doc/api_assets/api.js +++ b/doc/api_assets/api.js @@ -1,87 +1,131 @@ 'use strict'; -// Check if we have JavaScript support -document.querySelector(':root').classList.add('has-js'); +function setupTheme() { + const kCustomPreference = 'customDarkTheme'; + const userSettings = sessionStorage.getItem(kCustomPreference); + const themeToggleButton = document.getElementById('theme-toggle-btn'); -// Restore user mode preferences -const kCustomPreference = 'customDarkTheme'; -const userSettings = sessionStorage.getItem(kCustomPreference); -const themeToggleButton = document.getElementById('theme-toggle-btn'); -if (userSettings === null && window.matchMedia) { - const mq = window.matchMedia('(prefers-color-scheme: dark)'); - if ('onchange' in mq) { - function mqChangeListener(e) { - document.documentElement.classList.toggle('dark-mode', e.matches); + if (userSettings === null && window.matchMedia) { + const mq = window.matchMedia('(prefers-color-scheme: dark)'); + + if ('onchange' in mq) { + function mqChangeListener(e) { + document.documentElement.classList.toggle('dark-mode', e.matches); + } + mq.addEventListener('change', mqChangeListener); + if (themeToggleButton) { + themeToggleButton.addEventListener('click', function() { + mq.removeEventListener('change', mqChangeListener); + }, { once: true }); + } } - mq.addEventListener('change', mqChangeListener); - if (themeToggleButton) { - themeToggleButton.addEventListener('click', function() { - mq.removeEventListener('change', mqChangeListener); - }, { once: true }); + + if (mq.matches) { + document.documentElement.classList.add('dark-mode'); } - } - if (mq.matches) { + } else if (userSettings === 'true') { document.documentElement.classList.add('dark-mode'); } -} else if (userSettings === 'true') { - document.documentElement.classList.add('dark-mode'); -} -if (themeToggleButton) { - themeToggleButton.hidden = false; - themeToggleButton.addEventListener('click', function() { - sessionStorage.setItem( - kCustomPreference, - document.documentElement.classList.toggle('dark-mode') - ); - }); + + if (themeToggleButton) { + themeToggleButton.hidden = false; + themeToggleButton.addEventListener('click', function() { + sessionStorage.setItem( + kCustomPreference, + document.documentElement.classList.toggle('dark-mode') + ); + }); + } } -// Handle pickers with click/taps rather than hovers -const pickers = document.querySelectorAll('.picker-header'); -for (const picker of pickers) { - picker.addEventListener('click', (e) => { - if (!e.target.closest('.picker')) { - e.preventDefault(); +function setupPickers() { + function closeAllPickers() { + for (const picker of pickers) { + picker.parentNode.classList.remove('expanded'); } - if (picker.classList.contains('expanded')) { - picker.classList.remove('expanded'); - } else { - for (const other of pickers) { - other.classList.remove('expanded'); - } + window.removeEventListener('click', closeAllPickers); + window.removeEventListener('keydown', onKeyDown); + } - picker.classList.add('expanded'); + function onKeyDown(e) { + if (e.key === 'Escape') { + closeAllPickers(); } - }); + } + + const pickers = document.querySelectorAll('.picker-header > a'); + + for (const picker of pickers) { + const parentNode = picker.parentNode; + + picker.addEventListener('click', (e) => { + e.preventDefault(); + + /* + closeAllPickers as window event trigger already closed all the pickers, + if it already closed there is nothing else to do here + */ + if (parentNode.classList.contains('expanded')) { + return; + } + + /* + In the next frame reopen the picker if needed and also setup events + to close pickers if needed. + */ + + requestAnimationFrame(() => { + parentNode.classList.add('expanded'); + window.addEventListener('click', closeAllPickers); + window.addEventListener('keydown', onKeyDown); + }); + }); + } } -// Track when the header is in sticky position -const header = document.querySelector('.header'); -let ignoreNextIntersection = false; -new IntersectionObserver( - ([e]) => { - const currentStatus = header.classList.contains('is-pinned'); - const newStatus = e.intersectionRatio < 1; - - // Same status, do nothing - if (currentStatus === newStatus) { - return; - } else if (ignoreNextIntersection) { - ignoreNextIntersection = false; - return; - } +function setupStickyHeaders() { + const header = document.querySelector('.header'); + let ignoreNextIntersection = false; + + new IntersectionObserver( + ([e]) => { + const currentStatus = header.classList.contains('is-pinned'); + const newStatus = e.intersectionRatio < 1; + + // Same status, do nothing + if (currentStatus === newStatus) { + return; + } else if (ignoreNextIntersection) { + ignoreNextIntersection = false; + return; + } - /* - To avoid flickering, ignore the next change event that is triggered - as the visible elements in the header change once we pin it. + /* + To avoid flickering, ignore the next changes event that is triggered + as the visible elements in the header change once we pin it. - The timer is reset anyway after few milliseconds - */ - ignoreNextIntersection = true; - setTimeout(() => ignoreNextIntersection = false, 50); + The timer is reset anyway after few milliseconds. + */ + ignoreNextIntersection = true; + setTimeout(() => { + ignoreNextIntersection = false; + }, 50); - header.classList.toggle('is-pinned', newStatus); - }, - { threshold: [1] } -).observe(header); + header.classList.toggle('is-pinned', newStatus); + }, + { threshold: [1] } + ).observe(header); +} + +// Check if we have JavaScript support +document.querySelector(':root').classList.add('has-js'); + +// Restore user mode preferences +setupTheme(); + +// Handle pickers with click/taps rather than hovers +setupPickers(); + +// Track when the header is in sticky position +setupStickyHeaders(); diff --git a/doc/api_assets/style.css b/doc/api_assets/style.css index 4a64160edd20df..14302edc061a1d 100644 --- a/doc/api_assets/style.css +++ b/doc/api_assets/style.css @@ -811,13 +811,20 @@ kbd { background-color: var(--color-fill-app); } -@media not screen, (max-width: 600px), (max-height: 1000px) { +@media not screen, (max-width: 600px) { .header { position: relative; top: 0; } } +@media not screen, (max-height: 1000px) { + :root:not(.has-js) .header { + position: relative; + top: 0; + } +} + .header .pinned-header { display: none; margin-right: 0.4rem;