1/** 2 * Popup web component v2.0 3 * 4 * Popup is connected to Cookies modal through Cookies modal events. 5 * 6 */ 7import getCookie from "./getCookie.js"; 8 9class Popup extends HTMLElement { 10 constructor() { 11 super(); 12 13 this.shadow = this.attachShadow({ mode: "open" }); 14 this.initialized = false; 15 this.disabled = (!this.hasAttribute("disabled") || (this.getAttribute("disabled") === "false")) ? false : true; 16 this.debug = this.getAttribute("debug") === "true" ? true : false; 17 this.timeout = parseInt(this.getAttribute("timeout"), 10) || 0; 18 this.backgroundColor = this.getAttribute("background-color") || "#fff"; 19 this.roundCorners = this.getAttribute("round-corners") === "true" ? true : false; 20 this.delay = parseInt(this.getAttribute("delay"), 10) || 2000; 21 this.cookie = this.getAttribute("cookie") || "showPopup"; 22 23 this.dlog('popup disabled:', this.disabled); 24 25 this.dlog('popup constructed'); 26 27 this.render(); 28 29 this.popup = this.shadow.querySelector("#popup"); 30 31 window.addEventListener("consentmodalclose", this.initPopup); 32 window.addEventListener("consentmodalwillnotopen", this.initPopup); 33 this.dlog('popup eventListeners registered'); 34 } 35 36 dlog = (...args) => this.debug && console.log(...args); 37 38 connectedCallback() { 39 let slot = this.shadowRoot.querySelector('slot'); 40 const dlog = this.dlog; 41 const closeClicked = this.setClosePopupElement; 42 43 slot.addEventListener('slotchange', function (e) { 44 const closeButtons = e.target.assignedElements().filter(e => e.matches(`[data-control="close"]`)); 45 closeButtons.map(closeClicked); 46 }); 47 48 } 49 50 setClosePopupElement = (el) => { 51 el.addEventListener("click", (e) => { 52 e.preventDefault(); 53 this.dlog("close clicked"); 54 this.popup.close(); 55 setCookieToTwoWeeks(this.cookie); 56 if (e.target.hasAttribute("href")) { this.dlog("redirection"); window.location.href = e.target.getAttribute("href"); } 57 }); 58 } 59 60 // !!! when called outside eg. listener *this* refernce breaks if classic method definition is used 61 initPopup = () => { 62 this.dlog('popup initPopup'); 63 if (this.initialized || this.disabled) return; 64 this.initialized = true; 65 66 if (getCookie(this.cookie) === "false") return; 67 68 this.dlog('popup init approved'); 69 70 const closePopupButtons = Array.from(this.popup.querySelectorAll(`[data-control="close"]`)); 71 72 this.dlog('popup adding event listener for scroll'); 73 74 let timer = null; 75 76 const openPopup = () => { 77 this.dlog('popup callback called'); 78 if (!this.popup.open && ((window.document.documentElement.scrollTop + window.innerHeight) > document.querySelector("body").offsetHeight * 0.66)) { 79 setTimeout(() => this.popup.showModal(), this.delay); 80 this.dlog('scroll popup initiated, delayed'); 81 this.dlog('removing event listener'); 82 if (timer !== null) clearTimeout(timer); 83 window.removeEventListener("scroll", openPopup); // stops calling openPopup 84 } 85 } 86 87 if (!this.popup.open && this.timeout) { 88 timer = setTimeout(() => { 89 if (this.popup.open) return; 90 this.popup.showModal(); 91 this.dlog('timeout popup initiated'); 92 this.dlog('removing event listener'); 93 if (timer !== null) clearTimeout(timer); 94 window.removeEventListener("scroll", openPopup); // stops calling openPopup 95 }, this.timeout); 96 this.dlog('popup timeout set'); 97 } 98 99 window.addEventListener("scroll", openPopup); 100 101 closePopupButtons.map(this.setClosePopupElement); 102 } 103 104 // *this* works only inside this class calls 105 render() { 106 this.shadow.innerHTML = ` 107 <dialog id="popup" class="popup"> 108 <span class="close" data-control="close">×</span> 109 <div class="popup-content"> 110 <div class="popup-content-text"> 111 <slot></slot> 112 </div> 113 </div> 114 </dialog> 115 116 <style> 117 /*# Popup #*/ 118 119 * { 120 box-sizing: border-box; 121 } 122 .popup { 123 z-index: 500; 124 border: none; 125 overflow: auto; 126 background-color: ${this.backgroundColor}; 127 padding: clamp(24px,4vw,40px); 128 border-radius: ${this.roundCorners ? "20px" : "0"}; 129 } 130 ::backdrop { 131 backdrop-filter: blur(3px); 132 background-color: rgba(0,0,0,0.5); 133 } 134 .popup-content { 135 max-width: min(65ch, 90vw); 136 } 137 .popup .close { 138 color: #a79e82; 139 font-size: 28px; 140 font-weight: bold; 141 position: absolute; 142 right: 10px; 143 top: 0px; 144 cursor: pointer; 145 } 146 .popup-content-text { 147 display: flex; 148 flex-direction: column; 149 align-items: center; 150 } 151 </style> 152 `; 153 } 154} 155 156customElements.define("popup-component", Popup); 157
158const setCookieToTwoWeeks = (cookie) => { 159 let d = new Date(); 160 d.setTime(d.getTime() + (14 * 24 * 60 * 60 * 1000)); 161 let expires = "expires=" + d.toUTCString(); 162 document.cookie = `${cookie}=false;${expires};path=/`; 163} 164
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.