1const SITE_ALERT_FRAGMENT_PATH = '/site-configuration/site-alert'; 2 3/** 4 * Creates an isolated site-alert loader. 5 * @param {Object} dependencies Loader dependencies 6 * @returns {Object} Site-alert loading and reveal operations 7 */ 8export function createSiteAlertLoader({ 9 loadFragment: configuredLoadFragment, 10 createResizeObserver = (callback) => new ResizeObserver(callback), 11 logger = console, 12} = {}) { 13 let readinessPromise; 14 let resizeObserver; 15 16 function synchronizeHeight(doc) { 17 const alert = doc.querySelector('header > .site-alert'); 18 const alertHeight = alert?.offsetHeight || 0; 19 doc.body.style.setProperty('--site-alert-height', `${alertHeight}px`); 20 21 if (!alert && resizeObserver) { 22 resizeObserver.disconnect(); 23 resizeObserver = undefined; 24 } 25 26 if (alert && !resizeObserver) { 27 resizeObserver = createResizeObserver(() => synchronizeHeight(doc)); 28 resizeObserver.observe(alert); 29 alert.addEventListener('click', (event) => { 30 if (event.target.closest('.site-alert__dismiss')) { 31 synchronizeHeight(doc); 32 } 33 }); 34 } 35 36 return alertHeight; 37 } 38 39 function load(header, fragmentLoader = configuredLoadFragment) { 40 if (!readinessPromise) { 41 const mountedAlert = header?.querySelector(':scope > .site-alert'); 42 readinessPromise = mountedAlert 43 ? Promise.resolve(mountedAlert) 44 : fragmentLoader(SITE_ALERT_FRAGMENT_PATH) 45 .then((fragment) => { 46 const alert = fragment?.querySelector('.site-alert') || null; 47 if (alert && header && !header.querySelector(':scope > .site-alert')) { 48 header.prepend(alert); 49 } 50 return header?.querySelector(':scope > .site-alert') || alert; 51 }) 52 .catch((error) => { 53 logger.error('loadSiteAlert: failed to load site alert fragment', error); 54 return null; 55 }); 56 } 57 return readinessPromise; 58 } 59 60 async function loadPageChrome(header, fragmentLoader, loadHeaderStyles) { 61 const headerStylesReadiness = loadHeaderStyles().catch((error) => { 62 logger.error('loadSiteAlert: failed to load header styles', error); 63 }); 64 const [alert] = await Promise.all([ 65 load(header, fragmentLoader), 66 headerStylesReadiness, 67 ]); 68 return alert; 69 } 70 71 async function revealBody(siteAlertReadiness, doc) { 72 await siteAlertReadiness; 73 doc.body.classList.add('appear'); 74 synchronizeHeight(doc); 75 } 76 77 return { 78 load, 79 loadPageChrome, 80 revealBody, 81 synchronizeHeight, 82 }; 83} 84 85const siteAlertLoader = createSiteAlertLoader(); 86 87export const loadSiteAlert = (header, fragmentLoader) => ( 88 siteAlertLoader.load(header, fragmentLoader) 89); 90export const loadSiteAlertAndHeaderStyles = (header, fragmentLoader, loadHeaderStyles) => ( 91 siteAlertLoader.loadPageChrome(header, fragmentLoader, loadHeaderStyles) 92); 93export const revealBodyAfterSiteAlert = (siteAlertReadiness, doc) => ( 94 siteAlertLoader.revealBody(siteAlertReadiness, doc) 95); 96export const synchronizeSiteAlertHeight = (doc) => siteAlertLoader.synchronizeHeight(doc);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.