1const menuButton = document.querySelector("[data-menu-toggle]"); 2const menu = document.querySelector("[data-menu]"); 3 4if (menuButton && menu) { 5 menuButton.addEventListener("click", () => { 6 const open = menuButton.getAttribute("aria-expanded") === "true"; 7 menuButton.setAttribute("aria-expanded", String(!open)); 8 menu.classList.toggle("is-open", !open); 9 document.body.classList.toggle("menu-open", !open); 10 }); 11 12 menu.addEventListener("click", (event) => { 13 if (event.target.closest("a")) { 14 menuButton.setAttribute("aria-expanded", "false"); 15 menu.classList.remove("is-open"); 16 document.body.classList.remove("menu-open"); 17 } 18 }); 19} 20 21const teamupDialog = document.querySelector("[data-teamup-dialog]"); 22const teamupOpenButtons = document.querySelectorAll("[data-teamup-open]"); 23const teamupCloseButton = document.querySelector("[data-teamup-close]"); 24const teamupEmbed = document.querySelector("[data-teamup-embed]"); 25 26if (teamupDialog && teamupOpenButtons.length && teamupEmbed) { 27 let teamupStarted = false; 28 const status = teamupEmbed.querySelector("[data-teamup-status]"); 29 30 const setStatus = (message) => { 31 if (!status) return; 32 status.hidden = false; 33 status.textContent = message; 34 }; 35 36 const loadTeamup = () => { 37 if (teamupStarted) return; 38 teamupStarted = true; 39 setStatus(teamupEmbed.dataset.loading); 40 41 const observer = new MutationObserver(() => { 42 if (teamupEmbed.querySelector("iframe")) { 43 if (status) status.hidden = true; 44 observer.disconnect(); 45 } 46 }); 47 observer.observe(teamupEmbed, { childList: true, subtree: true }); 48 49 const script = document.createElement("script"); 50 script.src = "https://teamupstatic.com/teamup.js"; 51 script.async = true; 52 script.addEventListener("load", () => { 53 if (!window.teamup?.calendar) { 54 observer.disconnect(); 55 setStatus(teamupEmbed.dataset.error); 56 return; 57 } 58 59 window.teamup.calendar({ 60 provider_id: Number(teamupEmbed.dataset.providerId), 61 width: "100%", 62 view: teamupEmbed.dataset.view 63 }); 64 }); 65 script.addEventListener("error", () => { 66 observer.disconnect(); 67 setStatus(teamupEmbed.dataset.error); 68 }); 69 teamupEmbed.append(script); 70 71 window.setTimeout(() => { 72 if (!teamupEmbed.querySelector("iframe")) { 73 observer.disconnect(); 74 setStatus(teamupEmbed.dataset.error); 75 } 76 }, 12000); 77 }; 78 79 teamupOpenButtons.forEach((button) => { 80 button.addEventListener("click", () => { 81 loadTeamup(); 82 if (typeof teamupDialog.showModal === "function") teamupDialog.showModal(); 83 else teamupDialog.setAttribute("open", ""); 84 document.body.classList.add("dialog-open"); 85 }); 86 }); 87 88 const closeTeamup = () => { 89 if (typeof teamupDialog.close === "function") teamupDialog.close(); 90 else teamupDialog.removeAttribute("open"); 91 }; 92 93 teamupCloseButton?.addEventListener("click", closeTeamup); 94 teamupDialog.addEventListener("click", (event) => { 95 if (event.target === teamupDialog) closeTeamup(); 96 }); 97 teamupDialog.addEventListener("close", () => { 98 document.body.classList.remove("dialog-open"); 99 }); 100 teamupDialog.addEventListener("cancel", () => { 101 document.body.classList.remove("dialog-open"); 102 }); 103}
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.