{"version":3,"sources":["webpack:///./app/webpacker/src/javascripts/www/display.dropdowns.js","webpack:///./app/webpacker/src/javascripts/www/utils.js","webpack:///./app/webpacker/src/javascripts/www/search.offcanvas.js","webpack:///./app/webpacker/src/javascripts/www/search.identifiers.js","webpack:///./app/webpacker/src/javascripts/_browser-update.ts","webpack:///./app/webpacker/src/javascripts/www/display.hours.js","webpack:///./app/webpacker/src/javascripts/www/display.events.js","webpack:///./app/webpacker/src/javascripts/_utils.ts","webpack:///./app/webpacker/src/javascripts/www/main.js","webpack:///./app/webpacker/src/javascripts/www/display.to-top.js","webpack:///./app/webpacker/src/javascripts/www/display.anchors.js","webpack:///./app/webpacker/src/javascripts/www/modal.map.js","webpack:///./app/webpacker/src/javascripts/www/search.highlight.js","webpack:///./app/webpacker/src/javascripts/www/display.chat.js","webpack:///./app/webpacker/src/javascripts/www/display.basics.js","webpack:///./app/webpacker/src/javascripts/www/display.alerts.js","webpack:///./app/webpacker/src/javascripts/www/search-dropdowns.js","webpack:///./app/webpacker/packs/base.js.erb"],"names":["DropdownManager","constructor","config","arguments","length","undefined","_defineProperty","renderDivider","item","classes","parent_id","index","renderIcon","icon","renderInfoIcons","icons","text","parent_text","url","this","resolveURL","classStrings","mega_icon_links","icon_classes","renderAnnotation","mega_link_annotation","annotation","renderText","is_last","dropdown_last_item","templates","renderDropdownLink","renderHours","cid","renderMegaMenuLink","caret_icon","info_icons","inner","mega_links","renderMegaMenuList","group_obj","list","items","indexOf","id","type","renderDropdownList","entry","children","renderDropdownMenu","minWidth","min_width","dropdown_menu","renderGroupHeading","inner_content","mega_heading_links","heading","mega_headings","renderGroupList","renderColumnGroup","renderMegaColumnGroups","column_obj","groups","renderMegaColumn","renderColumns","columns","cols","renderMegaMenu","mega_menu","obj","baseURL","window","location","origin","dataSrc","wwwJsShims","dropdowns","ready","Promise","resolve","resolveReady","init","async","data","fetchData","timeout","retries","retryDelay","console","error","defaultBehaviorNoDropdownData","renderAllMenus","path","URL","protocol","e","href","document","querySelectorAll","forEach","toggle","removeAttribute","svg","querySelector","classList","add","menu_obj","dropdown_config","rendered","insertRenderedMenu","insertion_point","insertAdjacentHTML","initNewTooltip","element","tooltip","bootstrap","Tooltip","setWithExpiry","key","value","ttl","version","useSessionStorage","expiry","Date","getTime","sessionStorage","localStorage","setItem","JSON","stringify","getWithExpiry","storage","itemStr","getItem","parse","removeItem","attempt","controller","AbortController","timeoutId","setTimeout","abort","shouldRetry","response","fetch","signal","clearTimeout","ok","status","delay","json","message","ms","togglePasswordVisibility","togglePasswordButtons","button","addEventListener","target","getAttribute","input","setAttribute","onDomReady","callback","readyState","optInTooltips","selector","warn","optInPopovers","container","Popover","OffCanvasSearch","offCanvasSearch","offCanvasSearchInput","offCanvasSearchTrigger","focusOnRevealedSearchInput","setupEventListeners","event","focus","handleEscapeKey","Collapse","getOrCreateInstance","hide","handleClickOutside","contains","handleSlashKey","includes","tagName","preventDefault","show","bind","remove","removeEventListener","IdentifierHelper","doiRegex","urlRegex","proxyUrl","urls","ill","proxyTools","proxyString","queryString","prxyTyp","doiPrefix","openDOIString","doi","summonDOIString","illiadURLString","encodeURIComponent","selectors","doiInputs","doiText","strings","header","label","instructions","note","ifPaywall","endMsg","directAccess","doiOpenAccess","summon","illiad","illiadNote","externalLinkText","buildModal","prxyStr","existingModal","destroyModal","listGroupItems","listGroupItemFlex","externalLink","listGroupItemBold","join","summonFallback","illiadFallback","learnMore","makeBody","isDoi","makeDialogEl","makeModal","body","fragement","createDocumentFragment","modalEl","createElement","innerHTML","appendChild","pasted","clipboardData","getData","handlePaste","initializeModalEventListeners","modalInput","proxyableDirectAccess","doiSummonAccess","itemIlliadAccess","initiatedItem","resetModal","inputStr","handleIcon","closest","Modal","clickHandler","match","trim","replace","showTooltip","modalInstance","getInstance","dispose","trigger","title","required","f","o","s","c","insecure","unsupported","msg","msgmore","bupdate","bignore","remind","bnever","style","onshow","info","log","browser","t","dayjs","extend","utc","timezone","advancedFormat","dropdownConfig","untLib","dropdownManager","contentSection","h2Elements","skippedH2Count","h2","shouldSkipInsertion","toTopSnippet","generateToTopSnippet","el","hours","currentVersion","then","storedHours","storageKey","fetchHours","setTodaysDate","setHTMLElementHours","week","generateWeeklyTable","weekHours","parseInt","hoursData","find","lid","days","textContent","time","todayElement","tz","format","spacesArray","spaces","map","space","calendarUrl","endPoint","today","todayFormatted","nextWeek","name","dates","Object","keys","date","formatHours","storeData","todayData","day","expires","currentDay","from","to","hourTableDiv","lidFilter","split","filteredData","filter","hour","String","baseDate","tableHTML","i","className","headerDate","dateKey","dayInfo","displayTime","start","end","allday","apiURL","URLSearchParams","apiArgs","events","isValidEvent","isCampusIncluded","campus","public","registration","seats","reoccurs_future","future_dates","category","categorizeEvent","combinedText","description","presenter","toLowerCase","ignoreList","ignore","term","campusId","allowedCampusIds","searchFields","categories","some","keyword","now","filterEventsByCriteria","_ref","campuses","campusCondition","categoryCondition","groupEventsByDate","reduce","groupedEvents","push","makeDay","group","isLastItem","dateParts","monthName","makeItem","rangeStr","formatTimeStr","shortTitle","substring","makeShortTitle","eventElement","calendarIcon","month","itemContent","itemEl","makeList","insertEventsToDom","wrapper","kind","max","maxDays","eventBody","campusFilter","categoryFilter","filteredEvents","slice","maxDate","isBefore","isAfter","eventDates","noEvents","noEventsMessage","fetchAndProcessEvents","headings","makeAnchorLinks","copyToClipBoardListener","jumpToTopOfPage","hasAttribute","idValue","createIcon","link","pathname","navigator","clipboard","writeText","catch","scrollTo","top","behavior","modal","image","downloadLink","infoLink","listeners","triggerEl","relatedTarget","src","alt","contentArea","urlParams","search","searchText","get","Mark","markInstance","mark","totalMarks","chat","expireTime","apiUrl","chat_config","concat","endpoint","widgetUrl","chatBtn","chatBtnText","offCanvasAsUs","getFallbackText","chatStatus","checkStorage","fetchChatStatus","loadChat","showBtn","offlineStatus","online","setStorage","script","ask_us_text","active","alerts","js_config","expireDays","days_expire_dismiss","publishOn","publish_on","hideOn","hide_on","alertElement","dismissBtn","checkAlertVisibility","attachDismissEvent","globalAlert","publishDate","hideDate","isWithinDateRange","isSame","showAlert","hideAlert","display","SearchDropdown","dropdownId","watchId","initDropdown","attachEventListeners","getElementById","urlTemplate","searchTerm","changeLocation","fullUrl","searchDropdowns","browserUpdate"],"mappings":"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","file":"js/base-6f071d3b657faa67e84c.chunk.js","sourcesContent":["// Changes from source noted below with \"EDITED\"\nimport { fetchData } from './utils.js';\n\nexport class DropdownManager {\n\tconstructor(config = {}) {\n\t\tthis.config = {\n\t\t\tbaseURL: window.location.origin, // Default to current domain for relative paths\n\t\t\tdataSrc: '/assets/omni/data/dropdowns.json',\n\t\t\t...config,\n\t\t};\n\t\tthis.classStrings = {\n\t\t\tdropdown_menu: window.wwwJsShims.dropdowns.classes.dropdown_menu, // EDITED to use config on window object\n\t\t\tdropdown_last_item: window.wwwJsShims.dropdowns.classes.dropdown_last_item, // EDITED to use config on window object\n\t\t\tmega_menu: window.wwwJsShims.dropdowns.classes.mega_menu, // EDITED to use config on window object\n\t\t\tmega_headings: window.wwwJsShims.dropdowns.classes.mega_headings, // EDITED to use config on window object\n\t\t\tmega_heading_links: window.wwwJsShims.dropdowns.classes.mega_heading_links, // EDITED to use config on window object\n\t\t\tmega_links: window.wwwJsShims.dropdowns.classes.mega_links, // EDITED to use config on window object\n\t\t\tmega_icon_links: window.wwwJsShims.dropdowns.classes.mega_icon_links, // EDITED to use config on window object\n\t\t\tmega_link_annotation: window.wwwJsShims.dropdowns.classes.mega_link_annotation, // EDITED to use config on window object\n\t\t};\n\t\tthis.ready = new Promise(resolve => {\n\t\t\tthis.resolveReady = resolve;\n\t\t});\n\t\tthis.init();\n\t}\n\n\tasync init() {\n\t\tconst data = await fetchData(this.resolveURL(this.config.dataSrc), { timeout: 5000, retries: 3, retryDelay: 500 });\n\t\t// break if data fetch fails\n\t\tif (!data) {\n\t\t\tconsole.error('Initialization failed due to fetch error.');\n\t\t\tthis.defaultBehaviorNoDropdownData();\n\t\t\treturn;\n\t\t}\n\t\tthis.renderAllMenus(data);\n\t\tthis.resolveReady();\n\t}\n\n\tresolveURL(path) {\n\t\ttry {\n\t\t\t// If the path is already an absolute URL, the constructor will parse it successfully\n\t\t\tconst url = new URL(path);\n\t\t\t// Check if it's a valid absolute URL\n\t\t\tif (url.protocol === \"http:\" || url.protocol === \"https:\") {\n\t\t\t\treturn path; // Return the original absolute URL\n\t\t\t}\n\t\t} catch (e) {\n\t\t\t// If URL constructor fails, it's a relative path\n\t\t}\n\t\t// Combine baseURL with relative path\n\t\treturn new URL(path, this.config.baseURL).href;\n\t}\n\n\tdefaultBehaviorNoDropdownData() {\n\t\tconst dropdownToggles = document.querySelectorAll('[data-bs-toggle=\"dropdown\"]');\n\t\tdropdownToggles.forEach(toggle => {\n\t\t\ttoggle.removeAttribute('data-bs-toggle');\n\t\t\ttoggle.removeAttribute('aria-expanded');\n\t\t\tconst svg = toggle.querySelector('svg');\n\t\t\tif (svg) {\n\t\t\t\tsvg.classList.add('d-none');\n\t\t\t}\n\t\t});\n\t}\n\n\trenderAllMenus(data) {\n\t\tfor (let menu_obj in data) {\n\t\t\tfor (let obj of data[menu_obj]) {\n\t\t\t\tlet index = data[menu_obj].indexOf(obj) + 1;\n\t\t\t\tif (obj.type === 'dropdown') {\n\t\t\t\t\tthis.renderDropdownMenu(obj, menu_obj, index);\n\t\t\t\t} else if (obj.type === 'mega-menu') {\n\t\t\t\t\tthis.renderMegaMenu(obj, menu_obj, index);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\trenderDropdownMenu(obj, menu_obj, index) {\n\t\tlet dropdown_config = {\n\t\t\tid: `${menu_obj}-item-${index}`,\n\t\t\tmin_width: obj.min_width,\n\t\t\tchildren: obj.items\n\t\t};\n\t\tlet rendered = this.templates.renderDropdownMenu(dropdown_config, this.classStrings);\n\t\tthis.insertRenderedMenu(rendered, dropdown_config.id);\n\t}\n\n\trenderMegaMenu(obj, menu_obj, index) {\n\t\tlet dropdown_config = {\n\t\t\tid: `${menu_obj}-item-${index}`,\n\t\t\tobj: obj,\n\t\t};\n\t\tlet rendered = this.templates.renderMegaMenu(dropdown_config, this.classStrings);\n\t\tthis.insertRenderedMenu(rendered, dropdown_config.id);\n\t}\n\n\tinsertRenderedMenu(rendered, id) {\n\t\tlet insertion_point = document.querySelector(`#${id}-dropdown`);\n\t\t// test for existence of insertion point\n\t\tif (!insertion_point) {\n\t\t\treturn;\n\t\t}\n\t\tinsertion_point.insertAdjacentHTML('beforeend', rendered);\n\t\t//this.initNewTooltip(insertion_point);\n\t}\n\n\tinitNewTooltip(element) {\n\t\tconst tooltips = element.querySelectorAll('[data-bs-toggle=\"tooltip\"]');\n\t\ttooltips.forEach(tooltip => new bootstrap.Tooltip(tooltip));\n\t}\n\n\ttemplates = {\n\t\trenderDivider: (item) => {\n\t\t\tconst divider = `<li class=\"${item.classes ? item.classes : ''}\"\n id=\"${item.parent_id}-dropdown-item-${item.index}\">\n <hr class=\"dropdown-divider\">\n </li>`;\n\t\t\treturn divider;\n\t\t},\n\t\trenderIcon: (icon) => {\n\t\t\tconst span = icon ? `<span class=\"${icon}\"></span>` : '';\n\t\t\treturn span;\n\t\t},\n\t\trenderInfoIcons: (item) => {\n\t\t\tlet icons = \"\";\n\t\t\tfor (let icon of item.icons) {\n\t\t\t\ticon.text = icon.text ? icon.text : item.parent_text;\n\n\t\t\t\tif(icon.url){\n\t\t\t\t\tlet url = this.resolveURL(icon.url);\n\t\t\t\t\ticons += `<a href=\"${url}\"\n class=\"${this.classStrings.mega_icon_links}\"\n data-bs-toggle=\"tooltip\"\n data-bs-title=\"${icon.text}\">\n <span class=\"${icon.icon_classes} fa-fw\"></span>\n </a>`;\n\t\t\t\t} else {\n\t\t\t\t\ticons += `<span data-bs-toggle=\"tooltip\"\n data-bs-title=\"${icon.text}\">\n <span class=\"${icon.icon_classes} text-body-tertiary fa-fw\"></span>\n </span>`;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn icons;\n\t\t},\n\t\trenderAnnotation: (item) => {\n\t\t\tconst annotation = `<div class=\"${this.classStrings.mega_link_annotation}\">\n ${item.annotation}\n </div>`;\n\t\t\treturn annotation;\n\t\t},\n\t\trenderText: (item) => {\n\t\t\t// null values to empty string\n\t\t\titem.classes = item.classes ? item.classes : '';\n\t\t\t// append classStrings.dropdown_last_item to the last item in the list\n\t\t\titem.classes += item.is_last ? ` ${this.classStrings.dropdown_last_item}` : '';\n\t\t\tconst text = `<li class=\"text-unset px-3 fw-light ${item.classes}\"\n id=\"${item.parent_id}-dropdown-item-${item.index}\">\n ${this.templates.renderIcon(item.icon_classes)}\n ${item.text}\n </li>`;\n\t\t\treturn text;\n\t\t},\n\t\trenderDropdownLink: (item) => {\n\t\t\t// null values to empty string\n\t\t\titem.classes = item.classes ? item.classes : '';\n\t\t\t// append classStrings.dropdown_last_item to the last item in the list\n\t\t\titem.classes += item.is_last ? ` ${this.classStrings.dropdown_last_item}` : '';\n\t\t\tconst url = this.resolveURL(item.url);\n\t\t\tconst link = `<li id=\"${item.parent_id}-dropdown-item-${item.index}\">\n <a href=\"${url}\"\n class=\"dropdown-item darker ${item.classes}\">\n ${this.templates.renderIcon(item.icon_classes)}\n ${item.text}\n </a>\n </li>`;\n\t\t\treturn link;\n\t\t},\n\t\trenderHours: (item) => {\n\t\t\t// null values to empty string\n\t\t\titem.classes = item.classes ? item.classes : '';\n\t\t\t// append classStrings.dropdown_last_item to the last item in the list\n\t\t\titem.classes += item.is_last ? ` ${this.classStrings.dropdown_last_item}` : '';\n\t\t\tconst url = this.resolveURL(item.url);\n\t\t\tconst elem = `<li id=\"${item.parent_id}-dropdown-item-${item.index}\">\n <a href=\"${url}\"\n class=\"dropdown-item darker d-flex justify-content-between ${item.classes}\">\n <span>\n ${this.templates.renderIcon(item.icon_classes)}\n ${item.text}\n </span>\n <span class=\"live-hours badge text-secondary-emphasis small\"\n data-untl-hours-id=\"${item.cid}\"></span>\n </a>\n </li>`;\n\t\t\treturn elem;\n\t\t},\n\t\trenderMegaMenuLink: (item) => {\n\t\t\t// null values to empty string\n\t\t\titem.classes = item.classes ? item.classes : '';\n\t\t\titem.caret_icon = item.caret_icon ? item.caret_icon : 'fas fa-caret-right text-success';\n\t\t\titem.parent_text = item.text;\n\t\t\tconst info_icons = item.icons ? this.templates.renderInfoIcons(item) : '';\n\t\t\tconst annotation = item.annotation ? this.templates.renderAnnotation(item) : '';\n\t\t\tconst url = this.resolveURL(item.url);\n\t\t\tlet inner = \"\";\n\t\t\tif (info_icons === \"\") {\n\t\t\t\tinner = `<a href=\"${url}\"\n class=\"${this.classStrings.mega_links} ${item.classes}\">\n ${this.templates.renderIcon(item.icon_classes)}\n ${item.text}\n </a>`;\n\t\t\t} else {\n\t\t\t\tinner = `<span class=\"d-flex justify-content-between\">\n <a href=\"${url}\"\n class=\"flex-fill ${this.classStrings.mega_links} ${item.classes}\">\n ${this.templates.renderIcon(item.icon_classes)}\n ${item.text}\n </a>\n <span>\n ${info_icons}\n </span>\n </span>`;\n\t\t\t}\n\t\t\tconst link = `<li class=\"mb-2 py-1\">\n <span class=\"fa-li d-none d-md-block\">\n <span class=\"${item.caret_icon}\"></span>\n </span>\n ${inner}\n ${annotation}\n </li>`;\n\t\t\treturn link;\n\t\t},\n\t\trenderMegaMenuList: (group_obj) => {\n\t\t\tlet list = '';\n\t\t\tfor (let item of group_obj.items) {\n\t\t\t\t// the forloop index + 1\n\t\t\t\titem.index = group_obj.items.indexOf(item) + 1;\n\t\t\t\titem.parent_id = group_obj.id;\n\t\t\t\tif (item.type === 'divider') {\n\t\t\t\t\tlist += this.templates.renderDivider(item);\n\t\t\t\t}\n\t\t\t\telse if (item.type === 'link') {\n\t\t\t\t\tlist += this.templates.renderMegaMenuLink(item);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn list;\n\t\t},\n\t\trenderDropdownList: (entry) => {\n\t\t\tlet list = '';\n\t\t\tfor (let item of entry.children) {\n\t\t\t\t// the forloop index + 1\n\t\t\t\titem.index = entry.children.indexOf(item) + 1;\n\t\t\t\titem.parent_id = entry.id;\n\t\t\t\t// set a boolean value to indicate if this is the last item in the list\n\t\t\t\titem.is_last = item.index === entry.children.length;\n\t\t\t\tif (item.type === 'divider') {\n\t\t\t\t\tlist += this.templates.renderDivider(item);\n\t\t\t\t}\n\t\t\t\telse if (item.type === 'text') {\n\t\t\t\t\tlist += this.templates.renderText(item);\n\t\t\t\t}\n\t\t\t\telse if (item.type === 'link') {\n\t\t\t\t\tlist += this.templates.renderDropdownLink(item);\n\t\t\t\t}\n\t\t\t\telse if (item.type === 'hour') {\n\t\t\t\t\tlist += this.templates.renderHours(item);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn list;\n\t\t},\n\t\trenderDropdownMenu: (entry) => {\n\t\t\tconst minWidth = entry.min_width ? `style=\"min-width:${entry.min_width}px;\"` : '';\n\t\t\tconst menu = `<ul class=\"${this.classStrings.dropdown_menu}\" ${minWidth}\n id=\"${entry.id}-dropdown-menu\">\n ${this.templates.renderDropdownList(entry)}\n </ul>`;\n\t\t\treturn menu;\n\t\t},\n\t\trenderGroupHeading: (group_obj) => {\n\t\t\tconst inner_content = group_obj.url ? `<a href=\"${this.resolveURL(group_obj.url)}\" class=\"${this.classStrings.mega_heading_links}\">${group_obj.heading}</a>` : `${group_obj.heading}`;\n\t\t\tconst heading = `<h3 class=\"${this.classStrings.mega_headings}\">\n ${inner_content}\n </h3>`;\n\t\t\treturn heading;\n\t\t},\n\t\trenderGroupList: (group_obj) => {\n\t\t\tgroup_obj.classes = 'test_string';\n\t\t\tconst list = `<ul class=\"fa-ul ms-0 ms-lg-4 mb-0 mb-lg-2 ${group_obj.classes || \"\"}\">\n ${this.templates.renderMegaMenuList(group_obj)}\n </ul>`;\n\t\t\treturn list;\n\t\t},\n\t\trenderColumnGroup: (group_obj) => {\n\t\t\tconst column = `<div class=\"m-lg-3 mx-0 my-3 ${group_obj.classes || \"\" }\">\n ${group_obj.heading ? this.templates.renderGroupHeading(group_obj) : ''}\n ${group_obj.items ? this.templates.renderGroupList(group_obj) : ''}\n </div>`;\n\t\t\treturn column;\n\t\t},\n\t\trenderMegaColumnGroups: (column_obj) => {\n\t\t\tlet groups = '';\n\t\t\tfor (let group_obj of column_obj.groups) {\n\t\t\t\tgroups += this.templates.renderColumnGroup(group_obj);\n\t\t\t}\n\t\t\treturn groups;\n\t\t},\n\t\trenderMegaColumn: (column_obj) => {\n\t\t\tconst column = `<div class=\"${column_obj.classes}\">\n ${this.templates.renderMegaColumnGroups(column_obj)}\n </div>`;\n\t\t\treturn column;\n\t\t},\n\t\trenderColumns: (columns) => {\n\t\t\tlet cols = '';\n\t\t\tfor (let column_obj of columns) {\n\t\t\t\tcols += this.templates.renderMegaColumn(column_obj);\n\t\t\t}\n\t\t\treturn cols;\n\t\t},\n\t\trenderMegaMenu: (entry) => {\n\t\t\tconst menu = `<div class=\"${this.classStrings.mega_menu}\"\n id=\"${entry.id}-dropdown-menu\">\n <div class=\"container-fluid\">\n <div class=\"container-3xl px-0 px-lg-2\">\n <div class=\"row g-2\">\n ${this.templates.renderColumns(entry.obj.columns)}\n </div>\n </div>\n </div>\n </div>`;\n\t\t\treturn menu;\n\t\t}\n\t}\n}\n","// utils.js\n\n/**\n * Stores a value with an expiration time into either localStorage or sessionStorage.\n *\n * @param {string} key - The key under which the value will be stored.\n * @param {any} value - The value to be stored.\n * @param {number} ttl - Time to live in milliseconds.\n * @param {string} version - The version of the data being stored. Allows for forced updates.\n * @param {boolean} useSessionStorage - If true, uses sessionStorage instead of localStorage.\n */\nexport function setWithExpiry(key, value, ttl, version, useSessionStorage = false) {\n const now = new Date();\n const item = {\n value: value,\n expiry: now.getTime() + ttl,\n version: version\n };\n const storage = useSessionStorage ? sessionStorage : localStorage;\n storage.setItem(key, JSON.stringify(item));\n}\n\n/**\n * Retrieves an item from either localStorage or sessionStorage if it hasn't expired or the version string is mismatched.\n *\n * @param {string} key - The key of the item to retrieve.\n * @param {string} version - The version of the data being stored. Allows for forced updates.\n * @param {boolean} useSessionStorage - If true, uses sessionStorage instead of localStorage.\n * @returns {any|null} Returns the stored item if it hasn't expired; otherwise, null.\n */\nexport function getWithExpiry(key, version, useSessionStorage = false) {\n const storage = useSessionStorage ? sessionStorage : localStorage;\n const itemStr = storage.getItem(key);\n if (!itemStr) {\n return null;\n }\n const item = JSON.parse(itemStr);\n const now = new Date();\n if (now.getTime() > item.expiry || item.version !== version) {\n storage.removeItem(key);\n return null;\n }\n return item.value;\n}\n\n/**\n * Fetch data from a specified source with error handling, timeout, and retry logic.\n * @param {string} url - The URL to fetch data from.\n * @param {object} [options={}] - Configuration options\n * @param {number} [options.timeout=5000] - Timeout in milliseconds.\n * @param {number} [options.retries=0] - Number of retry attempts before giving up.\n * @param {number} [options.retryDelay=500] - Initial delay between retries in milliseconds (will use exponential backoff).\n * @returns {Promise<object[]|false>} - Promise resolving to parsed JSON or false if all attempts fail.\n */\nexport async function fetchData(url, { timeout = 5000, retries = 0, retryDelay = 500 } = {}) {\n for (let attempt = 0; attempt <= retries; attempt++) {\n let controller = new AbortController();\n let timeoutId = setTimeout(() => controller.abort(), timeout);\n let shouldRetry = attempt < retries; // Determine if we can attempt another retry after this one\n\n try {\n const response = await fetch(url, { signal: controller.signal });\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n console.error(`HTTP error! Status: ${response.status}`);\n if (shouldRetry) {\n await delay(retryDelay * (2 ** attempt)); // Exponential backoff\n continue; // Retry the fetch\n } else {\n return false;\n }\n }\n\n return await response.json();\n } catch (error) {\n clearTimeout(timeoutId);\n console.error('Fetch error:', error.message);\n\n // If this was our last attempt, return false\n if (!shouldRetry) {\n return false;\n }\n\n // Otherwise, wait before retrying\n await delay(retryDelay * (2 ** attempt));\n }\n }\n\n // If we exit the loop without returning, something unexpected happened\n return false;\n}\n\nfunction delay(ms) {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n\nexport function makeSVG(useID, title = '') {\n const svgNS = \"http://www.w3.org/2000/svg\";\n const xlinkNS = \"http://www.w3.org/1999/xlink\";\n const svg = document.createElementNS(svgNS, 'svg');\n svg.setAttribute('class', \"svg-inline--fa fa-lg fa-fw\");\n svg.setAttribute('role', 'img');\n svg.setAttribute('xmlns', svgNS);\n svg.setAttribute('viewBox', \"0 0 640 640\");\n const titleEl = document.createElementNS(svgNS, 'title');\n titleEl.textContent = title;\n const use = document.createElementNS(svgNS, 'use');\n use.setAttributeNS(xlinkNS, 'xlink:href', `#${useID}`);\n svg.appendChild(titleEl);\n svg.appendChild(use);\n return svg;\n\n}\n\n/**\n * Toggle an input between type password and text based on button click.\n */\nexport function togglePasswordVisibility() {\n const togglePasswordButtons = document.querySelectorAll('[data-untl-toggle=\"password\"]');\n if (!togglePasswordButtons.length) {\n return;\n }\n togglePasswordButtons.forEach(button => {\n button.addEventListener('click', () => {\n const target = button.getAttribute('data-untl-target');\n const input = document.querySelector(target);\n const icon = button.querySelector('svg');\n const type = input.getAttribute('type') === 'password' ? 'text' : 'password';\n input.setAttribute('type', type);\n // set the class of the button to eye-slash if password and eye if text\n icon.classList.toggle('fa-eye-slash', type === 'text');\n icon.classList.toggle('fa-eye', type === 'password');\n });\n });\n}\n/**\n * Utility function to wait for DOM ready.\n * Executes the callback when the DOM is fully loaded.\n * @param {Function} callback\n */\nexport function onDomReady(callback) {\n if (document.readyState !== 'loading') {\n callback();\n } else {\n document.addEventListener('DOMContentLoaded', callback);\n }\n}\n\n/**\n * Opt-in for Bootstrap tooltips.\n * Binds to a wrapper element, allowing for dynamic content insertion.\n * @param {string} selector - The CSS selector for tooltips.\n */\nexport function optInTooltips(selector = '[data-bs-toggle=\"tooltip\"]') {\n if (typeof bootstrap === 'undefined') {\n console.warn('Bootstrap is not defined.');\n return;\n }\n new bootstrap.Tooltip('body', { selector });\n}\n\n/**\n * Opt-in for Bootstrap popovers.\n * Binds to a wrapper element, allowing for dynamic content insertion.\n * @param {string} container - The container selector for popovers.\n * @param {string} selector - The CSS selector for popovers.\n */\nexport function optInPopovers(\n container = '#main-container',\n selector = '[data-bs-toggle=\"popover\"]'\n) {\n if (typeof bootstrap === 'undefined') {\n console.warn('Bootstrap is not defined.');\n return;\n }\n new bootstrap.Popover(container, { selector });\n}\n","import { onDomReady } from './utils.js';\n\nexport class OffCanvasSearch {\n constructor() {\n this.offCanvasSearch = document.querySelector('#offcanvas-search');\n this.offCanvasSearchInput = document.querySelector(\"#bento-offcanvas-q\");\n this.offCanvasSearchTrigger = document.querySelector('button.top-bar-item[data-bs-target=\"#offcanvas-search\"]');\n // autorun\n onDomReady(() => {\n this.init();\n });\n }\n\n init() {\n this.focusOnRevealedSearchInput();\n this.setupEventListeners();\n }\n\n focusOnRevealedSearchInput() {\n this.offCanvasSearch.addEventListener('shown.bs.collapse', event => {\n this.offCanvasSearchInput.focus();\n });\n }\n\n handleEscapeKey(event) {\n if (event.key === 'Escape') {\n const searchWrapper = bootstrap.Collapse.getOrCreateInstance('#offcanvas-search');\n searchWrapper.hide();\n }\n }\n\n handleClickOutside(event) {\n if (!this.offCanvasSearch.contains(event.target)) {\n const searchWrapper = bootstrap.Collapse.getOrCreateInstance('#offcanvas-search');\n searchWrapper.hide();\n }\n }\n\n handleSlashKey(event) {\n if (event.key !== '/') {\n return;\n }\n // Check if the key pressed is \"/\" and the target is not an input or textarea\n if (event.key === '/' && !['INPUT', 'TEXTAREA'].includes(event.target.tagName)) {\n event.preventDefault(); // Prevent default behavior (like quick find in Firefox)\n const searchWrapper = bootstrap.Collapse.getOrCreateInstance('#offcanvas-search');\n searchWrapper.show();\n }\n }\n\n setupEventListeners() {\n this.offCanvasSearch.addEventListener('show.bs.collapse', () => {\n this.offCanvasSearchTrigger.classList.add(\"dashed-focus\");\n document.addEventListener('keydown', this.handleEscapeKey.bind(this));\n document.addEventListener('click', this.handleClickOutside.bind(this), true);\n });\n\n this.offCanvasSearch.addEventListener('hidden.bs.collapse', () => {\n this.offCanvasSearchTrigger.classList.remove(\"dashed-focus\");\n document.removeEventListener('keydown', this.handleEscapeKey.bind(this));\n document.removeEventListener('click', this.handleClickOutside.bind(this), true);\n this.offCanvasSearchTrigger.focus();\n });\n document.addEventListener('keydown', this.handleSlashKey.bind(this));\n }\n\n}\n","import { onDomReady } from './utils.js';\n\nexport class IdentifierHelper {\n constructor() {\n this.doiRegex = /10.\\d{4,9}\\/[-._;()\\/:A-Z0-9]+/ig;\n this.urlRegex = /https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)/;\n this.proxyUrl = 'https://libproxy.library.unt.edu:443/login?url=';\n this.urls = {\n ill: 'https://library.unt.edu/services/ill-document-delivery/',\n proxyTools: 'https://library.unt.edu/proxy-tools',\n };\n this.proxyString = (queryString, prxyTyp) => {\n const doiPrefix = prxyTyp === 'doi' ? 'https://doi.org/' : '';\n return `${this.proxyUrl}${doiPrefix}${queryString}`;\n };\n this.openDOIString = (doi) => {\n return `https://unpaywall.org/${doi}`;\n };\n this.summonDOIString = (doi) => {\n return `https://untexas.summon.serialssolutions.com/search#!/search?ho=f&l=en&q=(DOI:(${doi}))`;\n };\n this.illiadURLString = (queryString, prxyTyp) => {\n if (prxyTyp === 'url') {\n queryString = encodeURIComponent(queryString);\n }\n const queryArgs = prxyTyp === 'doi' ? `&doi=${queryString}` : `¬es=${queryString}`;\n return `https://ill.library.unt.edu/illiad/illiad.dll?Action=10&Form=22${queryArgs}`;\n };\n this.selectors = {\n doiInputs: document.querySelectorAll(\"input.proxyable-target\"),\n doiText: document.querySelector('#proxyable-string'),\n };\n this.strings = {\n doi: {\n tooltip: 'DOI found. See options.',\n header: 'Accessing Items with a Digital Object Identifier (DOI)',\n label: 'We think your search contains a DOI:',\n instructions: 'Try these first:',\n note: 'Note: you may be directed to a login prompt first.',\n ifPaywall: 'If you hit a paywall:',\n endMsg: '*DOI not valid? Look for spaces, trailing punctuation, and/or check your source.',\n directAccess: '1. Direct Access',\n doiOpenAccess: '2. Find Open Access Copy',\n summon: `3. Try this search, then look for the buttons <strong>\"Find It\"</strong> or\n <strong>\"Check More Sources\"</strong> on the results\n page, and follow those links.`,\n illiad: '4. Submit an Interlibrary Loan request.',\n illiadNote: `Items not found in a subscription services can\n typically be requested and delivered to you.`,\n externalLinkText: 'opens in a new tab',\n },\n url: {\n tooltip: 'URL found. See options.',\n header: 'Getting Access to Paywalled Content',\n label: 'Your search contains a URL:',\n instructions: `Never pay for articles! The library\n can usually get them to you for free.*`,\n note: `You will be routed through a library\n login prompt. If we subscribe to the source, you should\n have instant access. Note: If we don't subscribe to the source,\n you'll hit a white screen and will need to try a different option.`,\n ifPaywall: null,\n endMsg: '*Current Students, Faculty, & Staff.',\n directAccess: `1. Try to \"Proxify\" the URL. `,\n doiOpenAccess: 'Find Open Access Copy',\n summon: null,\n illiad: '2. Submit an Interlibrary Loan request.',\n illiadNote: `Items not found in a subscription services can\n typically be requested and delivered to you. You will\n need to provide publication details on the request form.`,\n externalLinkText: 'opens in a new tab',\n },\n }\n // autorun\n onDomReady(() => {\n this.init();\n });\n }\n buildModal(prxyStr, prxyTyp) {\n const existingModal = document.querySelector('#proxyable-modal');\n if (existingModal) {\n this.destroyModal(existingModal);\n }\n const strings = prxyTyp === 'doi' ? this.strings.doi : this.strings.url;\n const classes = {\n listGroupItems: [\"list-group-item\", \"list-group-item-action\", \"link-success\"],\n listGroupItemFlex: [\"d-flex\", \"justify-content-between\", \"align-items-center\"],\n externalLink: [\"far\", \"fa-external-link\"],\n listGroupItemBold: [\"list-group-item\", \"fw-bold\"],\n };\n const search = () => {\n return `<div class=\"list-group-item\">\n <div class=\"form-floating mb-3\">\n <input class=\"form-control fw-bolder\"\n id=\"proxyable-string\"\n value=\"${ prxyStr }\" />\n <label class=\"fw-light\"\n for=\"proxyable-string\">\n ${ strings.label }\n </label>\n </div>\n </div>`;\n };\n const instruct = () => {\n return `<div class=\"${ classes.listGroupItemBold.join(' ') }\">\n ${ strings.instructions }\n </div>`;\n };\n const directAccess = () => {\n return `<a id=\"proxyable-direct-access\"\n target=\"_blank\"\n class=\"${ classes.listGroupItems.join(' ') }\"\n href=\"${ this.proxyString(prxyStr, prxyTyp) } \">\n <div class=\"${ classes.listGroupItemFlex.join(' ') } pb-1\">\n ${ strings.directAccess }\n <span class=\"${ classes.externalLink.join(' ') }\"\n title=\"${ strings.externalLinkText }\"></span>\n </div>\n <div class=\"small fst-italic text-secondary\">\n ${ strings.note }\n </div>\n </a>`;\n };\n const doiOpenAccess = () => {\n return `<a id=\"doi-open-access\"\n target=\"_blank\"\n class=\"${ classes.listGroupItems.join(' ') } ${ classes.listGroupItemFlex.join(' ') }\"\n href=\"${ this.openDOIString(prxyStr) }\">\n ${ strings.doiOpenAccess }\n <span class=\"${ classes.externalLink.join(' ') }\"\n title=\"${ strings.externalLinkText }\"></span>\n </a>`;\n };\n const summonFallback = () => {\n return `<a id=\"doi-summon-access\"\n target=\"_blank\"\n class=\"${ classes.listGroupItems.join(' ') } ${ classes.listGroupItemFlex.join(' ') }\"\n href=\"${ this.summonDOIString(prxyStr) }\">\n <span>${ strings.summon }</span>\n <span class=\"${ classes.externalLink.join(' ') }\"\n title=\"${ strings.externalLinkText }\"></span>\n </a>`;\n };\n const illiadFallback = () => {\n return `<a id=\"proxyable-illiad-access\"\n target=\"_blank\"\n class=\"${ classes.listGroupItems.join(' ') }\"\n href=\"${ this.illiadURLString(prxyStr, prxyTyp) }\">\n <div class=\"${ classes.listGroupItemFlex.join(' ') } pb-1\">\n <span>${ strings.illiad }</span>\n <span class=\"${ classes.externalLink.join(' ') }\"\n title=\"${ strings.externalLinkText }\"></span>\n </div>\n <div class=\"small fst-italic text-secondary\">\n ${ strings.illiadNote }\n </div>\n </a>`;\n };\n const learnMore = () => {\n return `<div class=\"list-group-item ${ classes.listGroupItemFlex.join(' ') } pb-1\">\n <span>\n For additional help see:\n <a class=\"link-success\"\n target=\"_blank\"\n href=\"${this.urls.ill}\">\n Interlibrary Loan</a>,\n <a class=\"link-success\"\n target=\"_blank\"\n href=\"${this.urls.proxyTools}\">Proxy Tools</a>.\n </span>\n </div>`;\n };\n const ifPaywall = () => {\n return `<div class=\"${ classes.listGroupItemBold.join(' ') }\">\n ${ strings.ifPaywall }\n </div>`;\n };\n const endMsg = () => {\n return `<div class=\"list-group-item font-italic\">\n ${ strings.endMsg }\n </div>`;\n };\n const makeBody = () => {\n const isDoi = prxyTyp === 'doi';\n return `<div class=\"modal-body\">\n <div class=\"list-group list-group-flush\">\n ${search()}\n ${instruct()}\n ${directAccess()}\n ${isDoi ? doiOpenAccess() : '' }\n ${isDoi ? ifPaywall() : '' }\n ${isDoi ? summonFallback() : '' }\n ${illiadFallback()}\n ${learnMore()}\n ${endMsg()}\n </div>\n </div>`;\n };\n const makeHeader = () => {\n return `<div class=\"modal-header\">\n <h5 class=\"modal-title\">\n ${ strings.header }\n </h5>\n <button type=\"button\"\n class=\"btn-close\"\n data-bs-dismiss=\"modal\"\n aria-label=\"Close\"></button>\n </div>`;\n };\n const makeDialogEl = () => {\n return `<div class=\"modal-dialog modal-lg modal-dialog-centered\">\n <div class=\"modal-content\">\n ${ makeHeader() }\n ${ makeBody() }\n </div>\n </div>`;\n };\n const makeModal = () => {\n const body = document.querySelector('body');\n const fragement = document.createDocumentFragment();\n const modalEl = document.createElement('div');\n modalEl.classList.add('modal', 'fade');\n modalEl.setAttribute('id', 'proxyable-modal');\n modalEl.setAttribute('tabindex', '-1');\n modalEl.setAttribute('aria-hidden', 'true');\n modalEl.innerHTML = makeDialogEl();\n fragement.appendChild(modalEl);\n body.appendChild(fragement);\n return modalEl;\n };\n return makeModal();\n }\n\n init() {\n // exit early if no doiInputs\n if (this.selectors.doiInputs.length === 0) {\n return;\n }\n this.selectors.doiInputs.forEach((input) => {\n input.addEventListener(\"paste\", (e) => {\n const pasted = (e.clipboardData || window.clipboardData).getData(\"text\");\n this.handlePaste(pasted, input);\n });\n });\n }\n\n initializeModalEventListeners(modalEl, prxyStr, prxyTyp) {\n const modalInput = modalEl.querySelector('#proxyable-string');\n const proxyableDirectAccess = modalEl.querySelector(\"#proxyable-direct-access\");\n const doiOpenAccess = modalEl.querySelector(\"#doi-open-access\");\n const doiSummonAccess = modalEl.querySelector(\"#doi-summon-access\");\n const itemIlliadAccess = modalEl.querySelector(\"#proxyable-illiad-access\");\n modalEl.addEventListener('hidden.bs.modal', () => {\n this.destroyModal(modalEl);\n const initiatedItem = document.querySelector('.initiated');\n this.resetModal(initiatedItem);\n initiatedItem.focus();\n initiatedItem.classList.remove('initiated');\n });\n modalInput.addEventListener('input', (event) => {\n const inputStr = event.target.value;\n if (proxyableDirectAccess) {\n proxyableDirectAccess.setAttribute( 'href', this.proxyString(inputStr, prxyTyp) );\n }\n if (doiOpenAccess) {\n doiOpenAccess.setAttribute( 'href', this.openDOIString(inputStr) );\n }\n if (doiSummonAccess) {\n doiSummonAccess.setAttribute( 'href', this.summonDOIString(inputStr) );\n }\n if (itemIlliadAccess) {\n itemIlliadAccess.setAttribute( 'href', this.illiadURLString(inputStr, prxyTyp) );\n }\n });\n }\n\n handleIcon(input, modalEl) {\n const closestForm = input.closest('form');\n const icon = closestForm.querySelector('.proxyable-icon');\n const modal = bootstrap.Modal.getOrCreateInstance(modalEl);\n icon.removeEventListener('click', icon.clickHandler);\n icon.clickHandler = () => {\n const modal = bootstrap.Modal.getOrCreateInstance(modalEl);\n modal.show();\n };\n icon.addEventListener('click', icon.clickHandler);\n icon.classList.remove(\"d-none\");\n input.classList.add(\"initiated\");\n return icon;\n }\n\n handlePaste(value, input) {\n value = value.trim();\n value = value.replace(/%2f/gi, '/');\n let match = value.match(this.doiRegex) || value.match(this.urlRegex);\n if (match) {\n const prxyStr = match[0];\n const prxyTyp = value.match(this.doiRegex) ? 'doi' : 'url';\n const modalEl = this.buildModal(prxyStr, prxyTyp);\n const icon = this.handleIcon(input, modalEl);\n this.showTooltip(icon, prxyTyp);\n this.initializeModalEventListeners(modalEl, prxyStr, prxyTyp);\n } else {\n this.resetModal(input);\n }\n }\n\n destroyModal(modalEl) {\n if (!modalEl) return;\n const modalInstance = bootstrap.Modal.getInstance(modalEl);\n if (modalInstance) {\n modalInstance.dispose();\n }\n modalEl.remove();\n }\n\n showTooltip(icon, prxyTyp) {\n const text = prxyTyp === 'doi' ? this.strings.doi.tooltip : this.strings.url.tooltip;\n let tooltip = new bootstrap.Tooltip(icon, {\n trigger: 'manual',\n title: text,\n });\n tooltip.show();\n setTimeout(() => icon.focus(), 100);\n icon.addEventListener('blur', () => tooltip.hide());\n }\n\n resetModal(input) {\n const closestForm = input.closest('form');\n const icon = closestForm.querySelector('.proxyable-icon');\n icon.classList.add(\"d-none\");\n let tooltip = bootstrap.Tooltip.getInstance(icon);\n if (tooltip) {\n tooltip.hide();\n }\n }\n}\n","import browserUpdate from 'browser-update';\n\nconst config = {\n required: {\n e: -3,\n f: -3,\n o: -3,\n s: -1,\n c: -3,\n },\n insecure: true,\n unsupported: true,\n text: {\n msg: 'Your web browser ({brow_name}) is out of date.',\n msgmore: 'Some features on this site may not work.',\n bupdate: 'Update browser',\n bignore: 'Ignore',\n remind: 'You will be reminded in {days} days.',\n bnever: 'Never show again',\n },\n style: 'bottom',\n onshow(info: { browser: { t: string; }; }) {\n console.log(`Browser ${info.browser.t} is out of date.`);\n },\n};\n\nexport default function runBrowserUpdate() {\n // @ts-ignore\n browserUpdate(config);\n}\n","// Changes from source noted below with \"EDITED\"\nimport dayjs from 'dayjs'; // EDITED to import dayjs\nimport utc from 'dayjs/plugin/utc'; // EDITED to import utc\nimport timezone from 'dayjs/plugin/timezone'; // EDITED to import timezone\nimport { setWithExpiry, getWithExpiry, fetchData } from './utils.js';\nimport { DropdownManager } from './display.dropdowns.js';\n\n// Extend day.js with the plugins\ndayjs.extend(utc); // EDITED to extend utc\ndayjs.extend(timezone); // EDITED to extend timezone\n\n/**\n * Manages operational hours fetched from the LibCal API, updates DOM elements, and constructs weekly tables.\n */\nexport class LibraryHours {\n constructor(dropdownManager) {\n this.config = window.wwwJsShims.hours; // EDITED to use config on window object\n this.currentVersion = 'v1.1.1'; // Update this version as needed to force resets\n dropdownManager.ready.then(() => this.init());\n }\n\n async init() {\n let storedHours = getWithExpiry(this.config.storageKey, this.currentVersion, true); // Attempt to get stored hours from session storage\n if (storedHours === null) {\n storedHours = await this.fetchHours(); // Fetch and store hours if not present\n }\n this.setTodaysDate();\n this.setHTMLElementHours(storedHours.week); // Update the DOM using today's hours\n this.generateWeeklyTable(storedHours.week); // Generate weekly hours table if applicable\n }\n\n setHTMLElementHours(weekHours) {\n const liveHoursElements = document.querySelectorAll(\".live-hours\");\n liveHoursElements.forEach(element => {\n const id = parseInt(element.getAttribute('data-untl-hours-id'), 10);\n // get the hours for the first day\n\n const hoursData = weekHours.find(item => item.lid === id).days[0];\n if (hoursData) {\n element.textContent = hoursData.time; // Update the text content with the hours\n }\n else {\n element.textContent = \"Call\";\n }\n });\n }\n\n setTodaysDate() {\n const todayElement = document.querySelector('#todays-date');\n if (todayElement) {\n todayElement.textContent = dayjs().tz('America/Chicago').format('dddd, MMMM D.');\n }\n }\n\n async fetchHours() {\n const spacesArray = this.config.spaces.map(space => space.cid);\n //const url = `${this.config.calendarUrl}${this.config.endPoint}${spacesArray.join(',')}?key=${this.config.pubKey}`;\n const url = `${this.config.calendarUrl}${this.config.endPoint}${spacesArray.join(',')}`;\n const today = dayjs().tz('America/Chicago');\n const todayFormatted = today.format('YYYY-MM-DD');\n const nextWeek = today.add(7, 'days').format('YYYY-MM-DD');\n const hoursData = await fetchData(`${url}?from=${todayFormatted}&to=${nextWeek}`, { timeout: 30000, retries: 3, retryDelay: 500 }); // 30-second timeout // with proxy!\n\n if (!hoursData) {\n console.error('Failed to fetch library hours');\n return;\n }\n\n let weekHours = hoursData.map(el => {\n return {\n lid: el.lid,\n name: el.name,\n days: el.dates ? Object.keys(el.dates).map(date => ({\n date: date,\n time: this.formatHours(el.dates[date])\n })) : []\n };\n });\n\n const todayHours = weekHours.map(location => {\n const todayData = location.days.find(day => day.date === todayFormatted);\n return {\n lid: location.lid,\n name: location.name,\n time: todayData ? this.formatHours(todayData.time) : \"Call\" // Provide default if no data found\n };\n });\n\n const storeData = { today: todayHours, week: weekHours };\n setWithExpiry(this.config.storageKey, storeData, this.config.expires, this.currentVersion, true);\n console.log(\"Hours refreshed.\");\n return storeData;\n }\n\n formatHours(currentDay) {\n if (!currentDay) return \"Call\";\n const status = currentDay.status;\n const hours = currentDay.hours && currentDay.hours.length > 0 && currentDay.hours[0].from && currentDay.hours[0].to\n ? `${currentDay.hours[0].from}-${currentDay.hours[0].to}`\n : \"Call\";\n switch (status) {\n case \"24hours\":\n return \"Open 24 hours\";\n case \"ByApp\":\n return \"By appointment\";\n case \"closed\":\n return \"Closed\";\n default:\n return hours;\n }\n }\n\n generateWeeklyTable(weekHours) {\n const hourTableDiv = document.querySelector('[data-untl-hours-table]');\n if (!hourTableDiv) return;\n\n const lidFilter = hourTableDiv.getAttribute('data-untl-hours-table').split(',');\n const filteredData = weekHours.filter(hour => lidFilter.includes(String(hour.lid)));\n const baseDate = dayjs().tz('America/Chicago'); // Starting from today\n\n let tableHTML = '<table class=\"table table-striped table-hover\"><tr class=\"table-success\"><th>Location</th>';\n for (let i = 0; i < 7; i++) {\n const className = i === 0 ? 'table-dark opacity-75' : '';\n const headerDate = baseDate.add(i, 'days');\n tableHTML += `<th class=\"${className}\">${headerDate.format('MMM DD</br />dddd')}</th>`;\n }\n tableHTML += '</tr>';\n\n filteredData.forEach(location => {\n tableHTML += `<tr><td>${location.name}</td>`;\n for (let i = 0; i < 7; i++) {\n // if first iteration store classnames for today\n const className = i === 0 ? 'bg-info bg-opacity-10' : '';\n const dateKey = baseDate.add(i, 'days').format('YYYY-MM-DD');\n const dayInfo = location.days.find(day => day.date === dateKey);\n const displayTime = dayInfo ? dayInfo.time : 'Call'; // Ensuring a value is always displayed\n tableHTML += `<td class=\"${className}\">${displayTime}</td>`;\n }\n tableHTML += '</tr>';\n });\n\n tableHTML += '</table>';\n hourTableDiv.innerHTML = tableHTML;\n }\n}\n","// Changes from source noted below with \"EDITED\"\n// utils.js imports\nimport { onDomReady, fetchData, setWithExpiry, getWithExpiry } from './utils.js';\nimport dayjs from 'dayjs'; // EDITED to import dayjs\nimport advancedFormat from 'dayjs/plugin/advancedFormat'; // EDITED to import advancedFormat\ndayjs.extend(advancedFormat); // EDITED to extend advancedFormat\n\nexport class EventManager {\n constructor() {\n this.config = window.wwwJsShims.events; // EDITED to use config on window object\n this.now = dayjs();\n this.currentVersion = 'v1.2'; // Update this version as needed to force resets\n // autorun\n onDomReady(() => {\n this.init();\n });\n }\n\n formatTimeStr = (start, end, allday) => {\n if (allday) {\n return 'All Day';\n } else {\n let startStr = dayjs(start).format('h:mm A');\n let endStr = dayjs(end).format('h:mm A');\n return `${startStr}-${endStr}`;\n }\n }\n\n /**\n * Fetch, filter, and return a map of events.\n */\n fetchAndProcessEvents = async () => {\n const apiURL = `${this.config.apiURL}?${new URLSearchParams(this.config.apiArgs)}`;\n const data = await fetchData(apiURL, { timeout: 5000, retries: 3, retryDelay: 500 });\n return data.events\n .filter(\n event => this.isValidEvent(event) && this.isCampusIncluded(event.campus.id)\n )\n .map(event => ({\n //...event,\n title: event.title,\n allday: event.allday || false,\n url: event.url.public,\n location: event.location.name || false,\n campus: event.campus.name || false,\n registration: event.registration || false,\n seats: event.seats || false,\n reoccurs_future: event.future_dates.length > 0 || false,\n start: new Date(event.start),\n end: event.end ? new Date(event.end) : false,\n category: this.categorizeEvent(event)\n }));\n }\n\n /**\n * valid events must have a title, public url and not include 'private' in the title\n */\n isValidEvent = (event) => {\n // Check that the event has the minimal requirements\n if (!event.title || !event.url || !event.url.public) {\n return false;\n }\n // Check these fields for ignored words\n const fieldsToCheck = [\n event.title,\n event.description || '',\n event.presenter || ''\n ];\n const combinedText = fieldsToCheck.join(' ').toLowerCase();\n const ignoreList = this.config.ignore || [];\n // Check if any of the ignore terms appear in the combined text\n for (const term of ignoreList) {\n if (combinedText.includes(term.toLowerCase().trim())) {\n return false; // Found an ignored term, so this event is not valid.\n }\n }\n // If we get here, no ignored terms were found\n return true;\n }\n\n /**\n * Check if the event's campus is included in the allowedCampusIds array in config\n */\n isCampusIncluded = (campusId) => {\n return this.config.allowedCampusIds.includes(campusId);\n }\n\n /**\n * Categorize events based on keywords in the title, description, or campus name, default to genera\n * cats are based on values in config.categories.\n */\n categorizeEvent = (event) => {\n const searchFields = [event.title, event.description, event.campus.name].join(' ').toLowerCase();\n return Object.keys(this.config.categories).find(category =>\n this.config.categories[category].some(keyword => searchFields.includes(keyword))\n ) || 'general';\n }\n\n /**\n * Filter events based on the provided criteria\n */\n filterEventsByCriteria(events, {campuses = [], categories = []}) {\n return events.filter(event => {\n const campusCondition = campuses.length === 0 || campuses.includes(event.campus);\n const categoryCondition = categories.length === 0 || categories.includes(event.category);\n return campusCondition && categoryCondition;\n });\n }\n\n /**\n * group an array of items by their start date\n */\n groupEventsByDate(events) {\n return events.reduce((groupedEvents, event) => {\n const date = dayjs(event.start).format('YYYY-MM-DD');\n if (!groupedEvents[date]) {\n groupedEvents[date] = [];\n }\n groupedEvents[date].push(event);\n return groupedEvents;\n }, {});\n }\n\n /**\n * generate events for a single day\n */\n makeDay(group, date, isLastItem) {\n const dateParts = date.split('-');\n const month = dateParts[1];\n // get the 3 letter version of the month\n const monthName = dayjs(date).format('MMM');\n const day = dateParts[2];\n const items = group[date];\n\n // calendar icon\n const calendarIcon = (month, day) => {\n return `\n <div class=\"text-center\">\n <span class=\"fa-layers fa-fw fa-5x d-block mb-2\">\n <i class=\"fad fa-calendar\"></i>\n <span class=\"fa-layers-text fa-inverse text-uppercase\"\n data-fa-transform=\"shrink-14 up-4\">${monthName}</span>\n <span class=\"fa-layers-text fa-inverse\"\n data-fa-transform=\"shrink-8 down-3\">${day}</span>\n </span>\n </div>`;\n }\n\n // shorten titles, cause some of these things are looooong.\n const makeShortTitle = (title) => {\n let shortTitle = title;\n // check if the title contains a colon\n if (title.includes(':') && title.toLowerCase().includes('spark')) {\n shortTitle = title.split(':')[1].trim();\n }\n // add spaces between / and alphanumeric characters to prevent runons\n if (shortTitle.includes('/')) {\n shortTitle = shortTitle.replace(/\\/([a-zA-Z0-9])/g, '/ $1');\n }\n // truncate and add ellipsis to shorTitles longer than 50 characters.\n if (shortTitle.length > 50) {\n shortTitle = shortTitle.substring(0, 50) + '...';\n }\n return shortTitle;\n }\n\n // a single list item in the day.\n const makeItem = (item) => {\n const rangeStr = this.formatTimeStr(item.start, item.end, item.allday);\n const shortTitle = makeShortTitle(item.title);\n // first letter of each word in campus\n //const abbrev = item.campus.split(' ').map(word => word[0]).join('');\n const locationStr = item.location ? `${item.location}, ${item.campus}` : '${item.campus}';\n return `\n <li>\n <span class=\"badge text-bg-dark\">${rangeStr}</span>\n <a href=\"${item.url}\" class=\"text-decoration-none link-dark-green\">\n ${shortTitle}\n </a>\n </li>`;\n }\n\n // make an unordered list of titles from items.\n const makeList = (items) => {\n const list = document.createElement('ul');\n list.classList.add('list-unstyled');\n let itemContent = '';\n items.forEach(item => {\n const itemEl = makeItem(item);\n itemContent += itemEl;\n });\n list.innerHTML = itemContent;\n return list;\n }\n\n // create a div\n const eventElement = document.createElement('div');\n eventElement.className = 'd-flex py-2 border-bottom border-secondary position-relative';\n\n // if last item remove the border classes\n if (isLastItem) {\n eventElement.classList.remove('border-bottom');\n }\n // make an icon\n const icon = calendarIcon(month, day);\n // make and return the element\n eventElement.innerHTML = icon;\n eventElement.appendChild(makeList(items));\n return eventElement;\n }\n\n\n /**\n * Build event DOM elements using configs set on DOM data- attributes.\n */\n insertEventsToDom(events) {\n // gather all the event wrapper elements\n const eventWrappers = document.querySelectorAll('.event-wrapper');\n eventWrappers.forEach(wrapper => {\n // get parse details for each dom element which will control which events show in this element\n const campuses = wrapper.getAttribute('data-untl-event-campuses');\n const categories = wrapper.getAttribute('data-untl-event-categories');\n const kind = wrapper.getAttribute('data-untl-event-kind') || 'standard';\n let max = wrapper.getAttribute('data-untl-event-max');\n let maxDays = wrapper.getAttribute('data-untl-event-max-days') || 30;\n const eventBody = wrapper.querySelector(\".card-body\");\n\n // filter lists, categories and campuses\n let campusFilter = campuses ? campuses.split(',').map(item => item.trim()) : [];\n let categoryFilter = categories ? categories.split(',').map(item => item.trim()) : [];\n\n let filteredEvents = this.filterEventsByCriteria(events, {\n campuses: campusFilter,\n categories: categoryFilter\n });\n // max items filter\n if (max) {\n max = parseInt(max, 10);\n filteredEvents = filteredEvents.slice(0, max);\n }\n // max days filter\n let maxDate = null;\n if (maxDays){\n maxDays = parseInt(maxDays, 10);\n maxDate = this.now.add(maxDays, 'day');\n filteredEvents = filteredEvents.filter(event => dayjs(event.start).isBefore(maxDate));\n }\n // filter out events in the past\n filteredEvents = filteredEvents.filter(event => dayjs(event.end).isAfter(this.now));\n\n // for now everything is a standard display. TODO support other kinds in the future.\n if (kind === 'standard') {\n let groupedEvents = this.groupEventsByDate(filteredEvents);\n let eventDates = Object.keys(groupedEvents);\n eventDates.map((date, index) => {\n if (groupedEvents[date].length > 0) {\n // Determine if this is the last item in the array\n const isLastItem = index === eventDates.length - 1;\n // Pass isLastItem as the third argument to this.makeDay\n const makeDay = this.makeDay(groupedEvents, date, isLastItem);\n eventBody.appendChild(makeDay);\n }\n });\n // test to see if groupedEvents is false. Append no events message if so.\n if (Object.keys(groupedEvents).length === 0) {\n const noEvents = document.createElement('p');\n\n const upcomingFragment = maxDays ? `There are no events scheduled between now and ${maxDate.format('MMMM D, YYYY')}` : 'There are no upcoming events.';\n\n const noEventsMessage = `\n ${upcomingFragment}. <a href=\"{{ site.data.urls.calendar.events }}\">See our complete calendar for future events.</a>\n `;\n noEvents.innerHTML = noEventsMessage;\n eventBody.appendChild(noEvents);\n\n }\n }\n });\n }\n\n async init() {\n // get existing events from storage\n let events = getWithExpiry(this.config.storageKey, this.currentVersion, true);\n if (!events) {\n // no events fetch fresh events from libcal\n events = await this.fetchAndProcessEvents();\n // refresh every 30 minutes or when script version change.\n setWithExpiry(this.config.storageKey, events, 30 * 60000, this.currentVersion, true);\n }\n // build the display\n this.insertEventsToDom(events);\n };\n}\n","// utility function to create function with timeout, used in ga events\nexport function actWithTimeOut(callback: () => void, optTimeout?: number) {\n let called = false;\n function fn() {\n if (!called) {\n called = true;\n callback();\n }\n }\n setTimeout(fn, optTimeout ?? 1000);\n return fn;\n}\n\n/**\n * This function overrides the same function from upstream www/utils.js\n * Utility function to wait for DOM ready.\n * Executes the callback when the DOM is fully loaded.\n * @param {Function} callback\n */\nexport function onDomReady(callback: () => void) {\n document.addEventListener('turbolinks:load', callback);\n}\n","// Changes from source noted below with \"EDITED\"\nimport { OffCanvasSearch } from './search.offcanvas.js';\nimport { DropdownManager } from './display.dropdowns.js';\nimport { LibraryHours } from './display.hours.js';\nimport { EventManager } from './display.events.js';\nimport { AnchorUtility } from './display.anchors.js';\nimport { ModalMapHandler } from './modal.map.js';\nimport { HighlightSearchTermMatch } from './search.highlight.js';\nimport { IdentifierHelper } from './search.identifiers.js';\n// import { ShortcutManager } from './home.shortcuts.js'; // EDITED to remove home.shortcuts.js\nimport { ChatManager } from './display.chat.js';\nimport { DisplayBasics } from './display.basics.js';\n// import { DidYouKnowRenderer } from './display.dyk.js'; // EDITED to remove display.dyk.js\n\nimport { InsertToTopButtons } from './display.to-top.js';\n\nimport { optInTooltips, optInPopovers } from './utils.js'; // EDITED to not import onDomReady\nimport { onDomReady } from '../_utils.ts'; // EDITED to override onDomReady function\n\n// Initialize tooltips and popovers if needed\nonDomReady(() => {\n optInTooltips();\n optInPopovers();\n});\n\n// Override dropdown configuration if it is set in the global window object\nconst dropdownConfig = window.untLib?.dropdownConfig || {};\n\nconst insertToTopButtons = new InsertToTopButtons();\nconst offCanvasSearchUtil = new OffCanvasSearch();\nconst dropdownManager = new DropdownManager(dropdownConfig); // EDITED to use config on window object\nconst libraryHours = new LibraryHours(dropdownManager);\nconst eventManager = new EventManager();\nconst anchorUtility = new AnchorUtility();\nconst identifierHelper = new IdentifierHelper();\nconst modalMapHandler = new ModalMapHandler();\nconst highlightSearchTermMatch = new HighlightSearchTermMatch();\n// const shortcutManager = new ShortcutManager('#shortcuts', '.shortcuts-toggle', 4); // EDITED to remove home.shortcuts.js\nconst chatManager = new ChatManager();\nconst displayBasics = new DisplayBasics();\n// const displayDyk = new DidYouKnowRenderer() // EDITED to remove display.dyk.js\n","import { onDomReady, setWithExpiry, getWithExpiry } from './utils.js';\n\nexport class InsertToTopButtons {\n constructor() {\n onDomReady(() => {\n this.init();\n });\n }\n\n init() {\n const contentSection = document.querySelector('#content');\n if (!contentSection) return;\n\n const h2Elements = contentSection.querySelectorAll('h2');\n if (h2Elements.length < 3) return;\n\n let skippedH2Count = 0;\n\n h2Elements.forEach((h2) => {\n if (this.shouldSkipInsertion(h2)) return;\n\n if (skippedH2Count < 2) {\n skippedH2Count++;\n return;\n }\n\n const toTopSnippet = this.generateToTopSnippet();\n h2.insertAdjacentHTML('beforebegin', toTopSnippet);\n });\n\n // Also insert before elements with the `.to-top-before` class\n document.querySelectorAll('.to-top-before').forEach((el) => {\n if (!this.shouldSkipInsertion(el)) {\n const toTopSnippet = this.generateToTopSnippet();\n el.insertAdjacentHTML('beforebegin', toTopSnippet);\n }\n });\n }\n\n shouldSkipInsertion(element) {\n return element.closest(\"[data-untl-to-top-of-page='false']\");\n }\n\n generateToTopSnippet() {\n return `\n <div class=\"clearfix\"></div>\n <div class=\"border-top my-5 position-relative\" markdown=\"0\">\n <a href=\"#top\" class=\"to-top-btn bg-white btn btn-outline-light-green opacity-75 p-1 position-absolute rounded-circle start-50 translate-middle\"\n data-bs-toggle=\"tooltip\"\n data-bs-placement=\"right\"\n title=\"Back to Top\">\n <span class=\"fa-kit fa-unt-eagle fa-lg\" aria-hidden=\"true\" title=\"UNT Eagle\"></span>\n </a>\n </div>\n `;\n }\n}\n","import { onDomReady } from './utils.js';\n\nexport class AnchorUtility {\n constructor() {\n this.selectors = '.content h2, .content h3, .content h4, .content h5, .content h6, .content .anchored';\n // autorun\n onDomReady(() => {\n this.init();\n });\n }\n\n init() {\n const headings = document.querySelectorAll(this.selectors);\n // create the anchor links\n this.makeAnchorLinks(headings);\n // attach the copy to clipboard event listener\n this.copyToClipBoardListener();\n // add a scroll to top behavior to top of page links\n this.jumpToTopOfPage();\n }\n\n makeAnchorLinks(headings) {\n headings.forEach(heading => {\n // test if heading has and id\n if (!heading.classList.contains('no-toc') && heading.hasAttribute('id') && heading.id !== '' ) {\n const idValue = heading.id;\n const icon = this.createIcon(idValue);\n heading.appendChild(icon);\n }\n });\n }\n\n copyToClipBoardListener() {\n const links = document.querySelectorAll('.anchor-link');\n links.forEach(link => {\n link.addEventListener('click', (event) => {\n //event.preventDefault();\n const url = `${window.location.origin}${window.location.pathname}#${link.href.split('#')[1]}`;\n navigator.clipboard.writeText(url).then(() => {\n link.setAttribute('data-bs-title', 'Copied to Clipboard');\n }).catch((error) => {\n console.error('Failed to copy:', error);\n });\n });\n });\n }\n\n createIcon(idValue) {\n const link = document.createElement('a');\n link.classList.add(\n 'anchor-link',\n 'ms-2'\n )\n link.href = `#${idValue}`;\n const icon = document.createElement('span');\n icon.className = 'fas fa-link text-secondary-subtle';\n icon.setAttribute('title', 'Update URL to this section');\n link.setAttribute('data-bs-toggle', 'tooltip');\n link.setAttribute('data-bs-title', 'Link to this section');\n link.appendChild(icon);\n return link;\n }\n\n jumpToTopOfPage(){\n const jumpButtons = document.querySelectorAll(\".to-top-btn\");\n // for each button add an event listener, prevent default behaviour and scroll to the top of the pages\n jumpButtons.forEach(button => {\n button.addEventListener(\"click\", (e) => {\n e.preventDefault();\n window.scrollTo({\n top: 0,\n behavior: \"smooth\"\n });\n });\n });\n }\n}\n","import { onDomReady } from './utils.js';\n\nexport class ModalMapHandler {\n constructor() {\n this.config = {\n selectors: {\n modal: document.querySelector('#map-dialog'),\n image: document.querySelector(\"#map-dialog-image\"),\n downloadLink: document.querySelector(\"#map-dialog-download-link\"),\n infoLink: document.querySelector(\"#map-dialog-info-link\"),\n }\n };\n // autorun\n onDomReady(() => {\n this.init();\n });\n }\n listeners() {\n this.config.selectors.modal.addEventListener('show.bs.modal', (event) => {\n const triggerEl = event.relatedTarget;\n const info = {\n 'src': triggerEl.getAttribute('data-untl-map-src'),\n 'alt': triggerEl.getAttribute('data-untl-map-alt'),\n 'href': triggerEl.getAttribute('data-untl-map-href'),\n }\n this.config.selectors.image.src = info.src;\n // set image alt\n this.config.selectors.image.alt = info.alt;\n this.config.selectors.downloadLink.href = info.src;\n this.config.selectors.infoLink.href = info.href;\n });\n this.config.selectors.modal.addEventListener('hidden.bs.modal', (event) => {\n this.config.selectors.image.src = '';\n this.config.selectors.downloadLink.href = '';\n this.config.selectors.infoLink.href = '';\n });\n\n }\n init() {\n if (!this.config.selectors.modal) {\n return;\n }\n this.listeners();\n }\n}\n","import { onDomReady } from './utils.js';\n\nexport class HighlightSearchTermMatch {\n constructor() {\n this.contentArea = document.querySelector('#content');\n this.urlParams = new URLSearchParams(window.location.search);\n this.searchText = this.urlParams.get('h');\n // autorun\n onDomReady(() => {\n this.init(this.searchText);\n });\n\n }\n\n init(text) {\n if (!this.contentArea || !text || Mark === 'undefined') {\n return;\n }\n const markInstance = new Mark(this.contentArea);\n let totalMarks = 0;\n markInstance.mark(text, {\n 'element': 'span',\n 'className': 'bg-warning fw-semibold bg-opacity-20',\n 'separateWordSearch': true,\n 'accuracy': 'complementary',\n 'each': (element) => {\n totalMarks++;\n }\n });\n }\n}\n","// Changes from source noted below with \"EDITED\"\nimport { onDomReady, setWithExpiry, getWithExpiry } from './utils.js';\n\n/**\n * Manages the display and loading of the chat widget.\n * Check against springshare's api to see if chat is online and\n * store value for 15 minutes before checking again.\n */\nexport class ChatManager {\n /**\n * Constructor.\n */\n constructor() {\n this.storageKey = window.wwwJsShims.chat.storageKey; // EDITED to use config on window object\n this.expireTime = (5 * 60000); // 5 minutes\n this.apiUrl = window.wwwJsShims.chat.chat_config.apiURL.concat(window.wwwJsShims.chat.chat_config.endpoint); // EDITED to use config on window object\n this.widgetUrl = window.wwwJsShims.chat.chat_config.widgetUrl; // EDITED to use config on window object\n this.chatBtn = document.querySelector('#global-chat-btn');\n this.chatBtnText = document.querySelector('#global-chat-btn-text');\n this.offCanvasAsUs = document.querySelector('#offcanvas-ask-us');\n this.currentVersion = 'v1.0'; // Update this version as needed to force resets\n // autorun\n onDomReady(() => {\n this.init();\n });\n }\n\n /**\n * Initializes on content load.\n */\n init() {\n // exit early if no chat button or off canvas element\n if (!this.chatBtn || !this.offCanvasAsUs) return;\n // append fallback text to offCanvasAsUs no matter the circumstances.\n this.offCanvasAsUs.innerHTML = this.getFallbackText();\n // check storage\n const chatStatus = this.checkStorage();\n if (chatStatus === null) {\n // status doesn't exist; it has expired or never existed. Check status.\n this.fetchChatStatus();\n } else {\n if (chatStatus) {\n // chat is available, load the widget\n this.loadChat();\n this.showBtn();\n } else {\n // chat is not available, do nothing.\n // 'false' state will expire within 15 min.\n // and a re-check will result in null\n //this.loadChat(); // testing.\n this.offlineStatus();\n this.showBtn();\n }\n }\n }\n\n /**\n * Fetch chat status from springshare api using async\n * set storage with the boolean value and return the value.\n */\n async fetchChatStatus() {\n try {\n const response = await fetch(this.apiUrl);\n const data = await response.json();\n let status = false;\n if (data.online) {\n this.setStorage(true);\n this.loadChat();\n this.showBtn();\n status = true;\n } else {\n this.setStorage(false);\n this.offlineStatus();\n this.showBtn();\n }\n return status;\n } catch (error) {\n console.error('Error:', error);\n return false;\n }\n }\n\n /**\n * Note offline status.\n */\n offlineStatus() {\n this.chatBtnText.innerHTML = \"Chat is offline\";\n }\n\n /**\n * reveal button.\n */\n showBtn() {\n this.chatBtn.classList.remove('d-none');\n }\n\n /**\n * load chat widget by appending script element to body\n */\n loadChat() {\n const script = document.createElement('script');\n script.src = this.widgetUrl;\n script.async = true;\n document.body.appendChild(script);\n }\n\n /**\n * fallBack Text\n *\n */\n getFallbackText() {\n return window.wwwJsShims.chat.ask_us_text; // EDITED to use config on window object\n }\n\n /**\n * Set storage with current chat status and a 5 minute expiry.\n * @param {boolean} active - true if chat is active, false if not.\n * @returns {boolean} - true if chat is active, false if not.\n */\n setStorage(active) {\n setWithExpiry(this.storageKey, active, this.expireTime, this.currentVersion, true);\n }\n\n /**\n * Check storage if chat is currently active. returning true or null.\n * @returns {boolean | null} - true if chat is active, null if not.\n */\n checkStorage() {\n const storageVal = getWithExpiry(this.storageKey, this.currentVersion, true);\n return storageVal;\n }\n}\n\n// Usage example:\n// new ChatManager();\n","import { onDomReady, togglePasswordVisibility } from './utils.js';\nexport class DisplayBasics {\n constructor(){\n // autorun\n onDomReady(() => {\n this.init();\n });\n }\n init(){\n togglePasswordVisibility();\n }\n}\n","// Changes from source noted below with \"EDITED\"\n// alert.js\nimport { onDomReady, setWithExpiry, getWithExpiry } from './utils.js';\nimport dayjs from 'dayjs'; // EDITED\nimport utc from 'dayjs/plugin/utc'; // EDITED\n\n// Extend day.js with the plugins\ndayjs.extend(utc); // EDITED to extend utc plugin\n\n/**\n * Manages the display and dismissal of global alerts on the website.\n */\nclass AlertManager {\n /**\n * Constructs the alert manager setting up the basic properties and initiating event listeners.\n */\n constructor() {\n this.storageKey = window.wwwJsShims.alerts.js_config.storageKey; // EDITED to use window object\n this.expireDays = window.wwwJsShims.alerts.alerts.days_expire_dismiss; // EDITED to use window object\n this.publishOn = window.wwwJsShims.alerts.alerts.publish_on; // EDITED to use window object\n this.hideOn = window.wwwJsShims.alerts.alerts.hide_on; // EDITED to use window object\n this.currentVersion = window.wwwJsShims.alerts.alerts.version; // EDITED to use window object\n this.alertElement = document.querySelector('#global-alert');\n this.dismissBtn = document.querySelector('#global-alert-dismiss');\n // autorun\n onDomReady(() => {\n this.init();\n });\n }\n\n /**\n * Initializes the alert system.\n */\n init() {\n this.checkAlertVisibility();\n if (this.alertElement && this.dismissBtn) {\n this.attachDismissEvent();\n }\n }\n\n /**\n * Checks the visibility of the global alert based on local storage settings and publish/hide dates.\n * If no setting is found, the setting has expired, or the alert is within the publish/hide date range, shows the alert.\n */\n checkAlertVisibility() {\n const globalAlert = getWithExpiry(this.storageKey, this.currentVersion);\n\n // Parse the publish and hide dates using Day.js in UTC\n const publishDate = this.publishOn ? dayjs(this.publishOn).utc() : null;\n const hideDate = this.hideOn ? dayjs(this.hideOn).utc() : null;\n\n // Get the current date/time in UTC\n const now = dayjs().utc();\n\n // Check if the alert should be shown based on date conditions\n const isWithinDateRange =\n (!publishDate || now.isAfter(publishDate) || now.isSame(publishDate)) &&\n (!hideDate || now.isBefore(hideDate) || now.isSame(hideDate));\n\n if (!globalAlert && isWithinDateRange) {\n this.showAlert();\n } else {\n this.hideAlert();\n }\n }\n\n /**\n * Hides the alert element by setting its display style to 'none'.\n */\n hideAlert() {\n if (this.alertElement) this.alertElement.style.display = 'none';\n }\n\n /**\n * Shows the alert element by removing 'display: none' style if it exists.\n */\n showAlert() {\n if (this.alertElement) this.alertElement.style.display = '';\n }\n\n /**\n * Attaches a click event listener to the dismiss button that will store a dismissal record in local storage\n * and hide the alert element. The record expiry is set based on `expireDays`.\n */\n attachDismissEvent() {\n this.dismissBtn.addEventListener('click', () => {\n setWithExpiry(\n this.storageKey,\n true,\n this.expireDays * 24 * 60 * 60 * 1000, // X days in the future\n this.currentVersion\n );\n this.hideAlert();\n });\n }\n}\n\n// Create an instance of AlertManager when the script is loaded\nnew AlertManager();\n","// Changes from source noted below with \"EDITED\"\n\n// EDITED to export SearchDropdown class\nexport default class SearchDropdown {\n constructor(dropdownId, watchId, data) {\n this.dropdownId = dropdownId;\n this.watchId = watchId;\n this.data = data;\n this.initDropdown();\n this.attachEventListeners();\n }\n\n initDropdown() {\n const dropdownMenu = document.getElementById(this.dropdownId);\n dropdownMenu.innerHTML = this.data.map(item => {\n if (item.type === 'divider') {\n return `<div class=\"dropdown-divider\"></div>`; // Bootstrap's class for dividers\n } else {\n return `\n <button class=\"dropdown-item\" type=\"button\" data-url-template=\"${item.urlTemplate}\">\n ${item.label}\n </button>\n `;\n }\n }).join('');\n }\n\n\n attachEventListeners() {\n const dropdownMenu = document.getElementById(this.dropdownId);\n dropdownMenu.addEventListener('click', (event) => {\n if (event.target.classList.contains('dropdown-item')) {\n event.preventDefault();\n const urlTemplate = event.target.getAttribute('data-url-template');\n const searchTerm = document.getElementById(this.watchId).value;\n this.changeLocation(urlTemplate, searchTerm);\n }\n });\n }\n\n changeLocation(urlTemplate, searchTerm) {\n const fullUrl = urlTemplate.replace('{query}', encodeURIComponent(searchTerm));\n window.location.href = fullUrl;\n }\n}\n","// Script files that should be included in all pages\nimport 'intersection-observer';\nimport Rails from '@rails/ujs';\nimport Turbolinks from 'turbolinks';\nimport * as bootstrap from 'bootstrap';\nimport runBrowserUpdate from '../src/javascripts/_browser-update';\nimport { initPrefilters, searchSelector } from '../src/javascripts/_search';\nimport { animateSearchIcon, bindDismissBannerCookie, linkify } from \"../src/javascripts/_ui\";\nimport './base.scss';\n\n// Javascript inherited from www\nimport '../src/javascripts/www/main'; // This is the main entry point for the www pack\nimport '../src/javascripts/www/display.alerts';\nimport SearchDropdown from '../src/javascripts/www/search-dropdowns.js';\n\ndocument.addEventListener('turbolinks:load', () => {\n // Initialize search dropdowns using window object\n new SearchDropdown('bento-offcanvas-other-search-options', 'bento-offcanvas-q', window.wwwJsShims.searchDropdowns['default_bento']);\n});\n\ndocument.addEventListener(\"DOMContentLoaded\", () => {\n Rails.start();\n Turbolinks.start();\n});\n\n// Blacklight Frontend javascript\nimport 'blacklight-frontend/app/javascript/blacklight/core';\nimport 'blacklight-frontend/app/javascript/blacklight/modal';\nimport 'blacklight-frontend/app/javascript/blacklight/button_focus';\nimport 'blacklight-frontend/app/javascript/blacklight/search_context';\n\ndocument.addEventListener('turbolinks:load', () => {\n animateSearchIcon();\n initPrefilters();\n searchSelector();\n linkify();\n bindDismissBannerCookie();\n runBrowserUpdate();\n});\n"],"sourceRoot":""}