const flagIcon = ``; const homeIcon = ``; const starIcon = ``; const calendarIcon = ``; const mIcon = ``; const searchIcon = ``; const chevronIcon = ``; const Colors = { white: '#fff', offWhite: '#f1f1f1', grayLight: '#e6e6e6', gray: '#222', grayDark: '#454545', red: '#e21833', redDark: '#951022', yellow: '#FFD200', green: '#70ebd6', }; const Breakpoints = { largeMobileMax: 767, tabletMax: 1023, desktopMin: 1024, }; const ELEMENT_NAME = 'umd-utility-header'; const ALERTS_URL = 'https://umd.edu/api/alerts'; const SEARCH_URL = 'https://search.umd.edu'; const MOBILE_MENU_ID = 'umd-global-mobile-menu'; const SEARCH_FORM_ID = 'umd-global-search'; const ALERT_ELEMENT_ID = 'umd-global-alert'; const LOCK_CLASS = `umd-global-header-lock`; const MOBILE_BUTTON_CLASS = `umd-global-header-mobile_button`; const LOGO_CLASS = 'umd-global-header-logo'; const SR_ONLY_CLASS = 'umd-global-sr-only'; const ALERT_TIME_REF = 'umd-alert-time'; const ALERT_REF = 'umd-alert'; const ALERT_ID_REF = 'umd-alert-id'; const ANIMATION_IN_SPEED = 800; const ANIMATION_OUT_SPEED = 400; const isDesktop = () => window.innerWidth >= Breakpoints.desktopMin; const template = document.createElement('template'); template.innerHTML = ` `; const isValidUrl = (url) => { try { new URL(url); } catch (e) { return false; } return true; }; const makeLinkElement = ({ name, icon, url, }) => { const tag = document.createElement('a'); tag.setAttribute('href', url); tag.setAttribute('target', '_blank'); tag.setAttribute('rel', 'noopener noreferrer'); tag.innerHTML = `${icon} ${name}`; return tag; }; const toggleExpandElements = ({ expandElement, elements, button, }) => { const isOpen = expandElement.getAttribute('aria-hidden') === 'false'; const elementToFocus = () => { const formElement = elements.find((element) => element.nodeName === 'DIV'); const isFirstNodeAnchor = elements[0].nodeName === 'A'; if (!formElement) return elements[0]; if (!isFirstNodeAnchor && formElement) { const input = formElement.querySelector('input'); return input; } return elements[0]; }; const eventKeyDown = (event) => { if (event.key === 'Esc' || event.keyCode == 27) { close(true); } }; const eventKeyUp = (event) => { const path = event.composedPath(); const currentElement = path[0]; if (!expandElement) return; if (event.key === 'Tab' || event.keyCode == 9) { if (!expandElement.contains(currentElement)) { close(); } } if (event.key === 'ArrowDown' || event.keyCode == 40) { const nextElement = currentElement.nextElementSibling; if (expandElement.contains(nextElement)) { nextElement.focus(); } } if (event.key === 'ArrowUp' || event.keyCode == 38) { const previousElement = currentElement.previousElementSibling; if (expandElement.contains(previousElement)) { previousElement.focus(); } } }; const eventClick = (event) => { const globalHeaderElement = event.target; if (globalHeaderElement.nodeName !== ELEMENT_NAME.toUpperCase()) { close(); } }; const open = () => { const focusElement = elementToFocus(); expandElement.style.display = expandElement.nodeName === 'FORM' ? 'block' : 'flex'; setTimeout(() => { const size = elements.reduce((accumulator, currentValue) => { return accumulator + currentValue.offsetHeight; }, 0); expandElement.setAttribute('aria-hidden', 'false'); expandElement.style.height = `${size}px`; focusElement.focus(); window.addEventListener('keydown', eventKeyDown); window.addEventListener('keyup', eventKeyUp); window.addEventListener('click', eventClick); }, 100); }; const close = (focus = false) => { expandElement.style.height = `0`; setTimeout(() => { expandElement.style.display = 'none'; expandElement.setAttribute('aria-hidden', 'true'); if (focus) { button.focus(); } window.removeEventListener('keydown', eventKeyDown); window.removeEventListener('keyup', eventKeyUp); window.removeEventListener('click', eventClick); }, ANIMATION_OUT_SPEED + 100); }; isOpen ? close() : open(); }; const makeMobileMenuButton = ({ expandElement, }) => { const button = document.createElement('button'); const elements = Array.from(expandElement.querySelectorAll('a, form')); button.innerHTML = `${chevronIcon}`; button.setAttribute('type', 'button'); button.setAttribute('aria-label', 'toggle mobile menu'); button.setAttribute('aria-controls', MOBILE_MENU_ID); button.classList.add(MOBILE_BUTTON_CLASS); button.addEventListener('click', () => { toggleExpandElements({ expandElement, elements, button }); }); return button; }; const makeSearchFormButton = ({ expandElement, }) => { const button = document.createElement('button'); const elements = Array.from(expandElement.querySelectorAll('div')); button.setAttribute('aria-label', 'enable the search form'); button.setAttribute('type', 'button'); button.innerHTML = `${searchIcon}`; button.setAttribute('aria-controls', SEARCH_FORM_ID); button.addEventListener('click', () => { toggleExpandElements({ expandElement, elements, button }); }); return button; }; const makeLogoElement = () => { const logo = document.createElement('a'); logo.innerHTML = 'University of Maryland'; logo.setAttribute('href', 'https://umd.edu'); logo.setAttribute('target', '_blank'); logo.setAttribute('rel', 'noopener noreferrer'); logo.classList.add(LOGO_CLASS); return logo; }; const makeFormElement = () => { const form = document.createElement('form'); const wrapper = document.createElement('div'); const inputTextLabel = document.createElement('label'); const inputText = document.createElement('input'); const inputSubmit = document.createElement('input'); inputTextLabel.innerHTML = 'Search input'; inputTextLabel.setAttribute('for', 'input-text'); inputTextLabel.classList.add(SR_ONLY_CLASS); inputText.setAttribute('type', 'text'); inputText.setAttribute('id', 'input-text'); inputText.setAttribute('name', 'query'); inputText.setAttribute('placeholder', 'Search for People, places and things'); inputText.setAttribute('required', ''); inputSubmit.setAttribute('type', 'submit'); inputSubmit.value = 'Submit'; form.setAttribute('id', SEARCH_FORM_ID); form.setAttribute('aria-hidden', isDesktop().toString()); wrapper.appendChild(inputTextLabel); wrapper.appendChild(inputText); wrapper.appendChild(inputSubmit); form.appendChild(wrapper); return form; }; const checkAlertTime = () => { const alertDate = window.localStorage.getItem(ALERT_TIME_REF); const currentDate = new Date(); const futureDate = new Date(currentDate.getTime() + 1000 * 60); const shouldCheckMessage = (alertDate) => { const storedDate = new Date(Date.parse(alertDate)); if (storedDate instanceof Date && currentDate > storedDate) { localStorage.setItem(ALERT_TIME_REF, futureDate.toString()); return true; } return false; }; if (!alertDate) { localStorage.setItem(ALERT_TIME_REF, futureDate.toString()); return true; } return shouldCheckMessage(alertDate); }; const setAlertStorage = (alert) => { window.localStorage.setItem(ALERT_REF, JSON.stringify(alert)); }; const getAlertStorage = () => window.localStorage.getItem(ALERT_REF); const shouldAlertHide = ({ alert_id }) => window.localStorage.getItem(ALERT_ID_REF) === alert_id; const makeAlert = (data) => { const wrapper = document.createElement('div'); const lock = document.createElement('div'); const titleElement = document.createElement('p'); const textElement = document.createElement('div'); const button = document.createElement('button'); wrapper.setAttribute('data-type', data.alert_type); wrapper.setAttribute('id', ALERT_ELEMENT_ID); lock.classList.add(LOCK_CLASS); titleElement.classList.add('alert-title'); titleElement.innerHTML = data.alert_title; textElement.innerHTML = data.alert_message; button.setAttribute('aria-label', 'remove alert'); button.addEventListener('click', () => { wrapper.style.height = `${wrapper.offsetHeight}px`; window.localStorage.setItem(ALERT_ID_REF, data.alert_id); setTimeout(() => { wrapper.style.height = '0px'; }, 100); setTimeout(() => { wrapper.remove(); }, ANIMATION_IN_SPEED + 100); }); lock.appendChild(button); lock.appendChild(titleElement); lock.appendChild(textElement); wrapper.appendChild(lock); return wrapper; }; export default class UtilityHeaderElement extends HTMLElement { constructor() { super(); this._containerElement = document.createElement('div'); this._menuContainerElement = document.createElement('div'); this._logoElement = makeLogoElement(); this._formElement = makeFormElement(); this._menuElements = []; this._paddingAmount = '20'; this._searchType = null; this._isSearchSet = false; this._isEventsSet = false; this._isNewsSet = false; this._isSchoolsSet = false; this._isAdmissionsSet = false; this._isGiftSet = false; this._shadow = this.attachShadow({ mode: 'open' }); this._shadow.appendChild(template.content.cloneNode(true)); } static get observedAttributes() { return [ 'padding', 'size', 'search', 'events', 'news', 'schools', 'admissions', 'gift', ]; } attributeChangedCallback(name, oldValue, newValue) { if (name === 'padding' && newValue) { this._paddingAmount = newValue; this.paddingContainer({ padding: this._paddingAmount }); } if (name === 'size' && newValue) { const width = newValue === 'full' ? '100%' : newValue; this.sizeContainer({ width }); } if (name === 'admissions' && !this._isAdmissionsSet) { this._isAdmissionsSet = true; const element = makeLinkElement({ name: 'Admissions', url: 'https://umd.edu/admissions', icon: flagIcon, }); this._menuElements.push({ order: 1, element, }); } if (name === 'schools' && !this._isSchoolsSet) { this._isSchoolsSet = true; const element = makeLinkElement({ name: 'Colleges & Schools', url: 'https://umd.edu/colleges-and-schools', icon: homeIcon, }); this._menuElements.push({ order: 2, element, }); } if (name === 'news' && !this._isNewsSet) { this._isNewsSet = true; const element = makeLinkElement({ name: 'News', url: 'https://today.umd.edu/', icon: starIcon, }); this._menuElements.push({ order: 3, element, }); } if (name === 'events' && !this._isEventsSet) { this._isEventsSet = true; const element = makeLinkElement({ name: 'Events', url: 'https://calendar.umd.edu', icon: calendarIcon, }); this._menuElements.push({ order: 4, element, }); } if (name === 'gift' && !this._isGiftSet) { this._isGiftSet = true; const getURL = () => { const defaultURL = 'https://giving.umd.edu/giving'; if (!newValue) return defaultURL; const validURL = newValue ? isValidUrl(newValue) : null; return validURL ? newValue : defaultURL; }; const element = makeLinkElement({ name: 'Make a Gift', url: getURL(), icon: mIcon, }); this._menuElements.push({ order: 5, element, }); } if (name === 'search' && !this._isSearchSet) { const button = makeSearchFormButton({ expandElement: this._formElement, }); this._isSearchSet = true; if (newValue) { this._searchType = newValue; } this._menuElements.push({ order: 6, element: button, }); } } connectedCallback() { const containsMenuItems = this._menuElements.length > 0; const resizeElements = {}; this._containerElement.classList.add(LOCK_CLASS); this._containerElement.appendChild(this._logoElement); if (containsMenuItems) { this.addMenuItems(); this._containerElement.appendChild(makeMobileMenuButton({ expandElement: this._menuContainerElement, })); this._menuContainerElement.setAttribute('id', MOBILE_MENU_ID); this._menuContainerElement.setAttribute('aria-hidden', (!isDesktop()).toString()); this._containerElement.appendChild(this._menuContainerElement); resizeElements['menu'] = this._menuContainerElement; } else { this._containerElement.style.display = 'flex'; this._containerElement.style.justifyContent = 'center'; } if (this._isSearchSet) { resizeElements['form'] = this._formElement; this.searchSubmit(); } if (Object.keys(resizeElements).length > 0) { window.addEventListener('resize', () => { this.resizeEvent(resizeElements); }); } this.alert(); this._shadow.appendChild(this._containerElement); } resizeEvent({ menu, form, }) { if (menu) { menu.setAttribute('aria-hidden', (!isDesktop()).toString()); } if (form) { form.setAttribute('aria-hidden', isDesktop().toString()); } } paddingContainer({ padding }) { this._containerElement.style.paddingLeft = `${padding}px`; } sizeContainer({ width }) { this._containerElement.style.maxWidth = `${width}`; } searchSubmit() { this._formElement.addEventListener('submit', (event) => { event.preventDefault(); const input = this._formElement.querySelector('input[type="text"]'); let searchString = `#gsc.tab=0&gsc`; if (this._searchType === 'domain') { searchString += `.q=site:${window.location.hostname} ${input.value}`; } else { searchString += `.q=${input.value}`; } searchString += `&gsc.sort=`; window.open(`${SEARCH_URL}${encodeURI(searchString)}`, '_blank'); }); } addMenuItems() { const items = this._menuElements.sort((a, b) => a.order > b.order ? 1 : -1); const setPadding = ({ element }) => { const mobileButton = this._shadow.querySelector(MOBILE_BUTTON_CLASS); const padding = parseInt(this._paddingAmount); const elementPadding = padding > 20 ? 20 : padding; element.style.paddingRight = `${elementPadding}px`; if (mobileButton) mobileButton.style.paddingRight = `${elementPadding}px`; if (padding > 20) { this._containerElement.style.paddingRight = `${padding - 20}px`; } }; items.forEach(({ element }, i) => { if (i === items.length - 1) setPadding({ element }); this._menuContainerElement.appendChild(element); }); if (this._isSearchSet) { this._menuContainerElement.appendChild(this._formElement); } } async alert() { const shouldCheck = checkAlertTime(); const setMarkup = (data) => { const domAlert = makeAlert(data); const styleNode = this._shadow.querySelector('style'); const containerNode = styleNode.nextElementSibling; if (shouldAlertHide({ alert_id: data.alert_id })) return; if (containerNode) { this._shadow.insertBefore(domAlert, containerNode); } else { this._shadow.appendChild(domAlert); } }; const fetchAlerts = async () => { try { const params = { method: 'GET', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, }; const response = await fetch(ALERTS_URL, params); return response.json(); } catch (ex) { throw ex; } }; if (shouldCheck) { const { data = [] } = await fetchAlerts(); if (data.length > 0) { if (data[0] == '') return; setMarkup(data[0]); setAlertStorage(data[0]); } else { const alertElement = this._shadow.querySelector(`#${ALERT_ELEMENT_ID}`); window.localStorage.setItem(ALERT_REF, ''); window.localStorage.removeItem(ALERT_REF); if (alertElement) { alertElement.remove(); } } } else { const data = getAlertStorage(); if (data) { setMarkup(JSON.parse(data)); } } } } if (!window.customElements.get(ELEMENT_NAME)) { window.UtilityHeaderElement = UtilityHeaderElement; window.customElements.define(ELEMENT_NAME, UtilityHeaderElement); } //# sourceMappingURL=index.js.map