1document.addEventListener("DOMContentLoaded", function () { 2 3 // ------------------------------------------------------------ 4 // Show the demo button only when the page is slightly scrolled 5 // ------------------------------------------------------------ 6 const demoButton = document.querySelector(".annoying-button"); 7 const demoObserverTarget = document.createElement("div"); 8 9 demoObserverTarget.style.cssText = "position: absolute; z-index: -1; top: 10px; left: 0; width: 1px; height: 1px;"; 10 document.body.appendChild(demoObserverTarget); 11 12 const demoObserver = new IntersectionObserver(function (entries) { 13 if (!entries[0].isIntersecting) { 14 demoButton.classList.add("visible"); 15 } else { 16 demoButton.classList.remove("visible"); 17 } 18 }); 19 20 demoObserver.observe(demoObserverTarget); 21 22 // ----------------------------------------------- 23 // Close any modal dialog by clicking its backdrop 24 // ----------------------------------------------- 25 document.querySelectorAll("dialog").forEach(function (dialog) { 26 dialog.addEventListener("click", function (event) { 27 const rect = this.getBoundingClientRect(); 28 if ( 29 event.clientY < rect.top || 30 event.clientY > rect.bottom || 31 event.clientX < rect.left || 32 event.clientX > rect.right 33 ) { 34 this.close(); 35 } 36 ; 37 }); 38 }); 39 40 // -------------------------------------------------- 41 // Custom "loaded" helper for NodeLists (e.g. images) 42 // -------------------------------------------------- 43 function loaded(elements, callback, jointCallback, ensureCallback) { 44 let len = elements.length; 45 if (len > 0) { 46 elements.forEach(function (el) { 47 el.addEventListener("load", function handler(event) {
48 // With { once: true } we don't need to remove the listener manually. 49 if (typeof callback === "function") { 50 callback.call(el, event); 51 } 52 len--; 53 if (len <= 0 && typeof jointCallback === "function") { 54 jointCallback.call(el); 55 } 56 }, {once: true}); 57 // If the element is already loaded (e.g. an image), trigger the load event 58 if (el.complete) { 59 var evt = new Event("load"); 60 el.dispatchEvent(evt); 61 } 62 }); 63 } else if (ensureCallback && typeof jointCallback === "function") { 64 jointCallback.call(elements); 65 } 66 } 67 68 // ------------------------------- 69 // Show/hide dome panel and images 70 // ------------------------------- 71 const demoPanel = document.querySelector(".demo-panel"); 72 const demoSwitch = document.querySelector(".annoying-button"); 73 const contentPanel = document.querySelector(".content-panel"); 74 const html = document.documentElement; // equivalent to $("html") 75 76 function paintImages() { 77 const thumbnails = demoPanel.querySelectorAll(".load-on-click"); 78 thumbnails.forEach(function (thumb) { 79 thumb.srcset = thumb.getAttribute("data-srcset"); 80 }); 81 loaded(thumbnails, function () { 82 // When an image is loaded, add the class "thumb-loaded" to its nearest ".demo-thumb" parent. 83 const demoThumb = this.closest(".demo-thumb"); 84 if (demoThumb) { 85 demoThumb.classList.add("thumb-loaded"); 86 } 87 }); 88 } 89 90 // Attach a one-time click event to the demo switch (using the { once: true } option) 91 demoSwitch.addEventListener("click", function () { 92 paintImages(); 93 }, {once: true}); 94 95 // ----------------------- 96 // Filter logic 97 // ----------------------- 98 const categoriesList = document.querySelector(".filter-panel .categories-wrap"); 99 // Use :scope to select direct children if needed. 100 const categorySelected = categoriesList.querySelector(":scope > .category-selected"); 101 const filterLinks = categoriesList.querySelectorAll("nav > a"); 102 const demos = contentPanel.querySelectorAll("a"); 103 const contentHolder = contentPanel.querySelector(".content-wrap"); 104 105 // Toggle the categories list when clicking the currently selected category 106 categorySelected.addEventListener("click", function () { 107 categoriesList.classList.toggle("is-open"); 108 }); 109 110 // Also toggle when clicking any element with class "showing-caption" 111 document.querySelectorAll(".showing-caption").forEach(function (el) { 112 el.addEventListener("click", function () { 113 categoriesList.classList.toggle("is-open"); 114 }); 115 }); 116 117 // Set up filtering when clicking any filter link 118 filterLinks.forEach(function (link) { 119 link.addEventListener("click", function (event) { 120 event.preventDefault(); 121 const filterClass = link.getAttribute("data-filter"); 122 123 // Scroll the content panel to the top 124 contentPanel.scrollTop = 0; 125 126 // Remove the "act" class from all filter links 127 filterLinks.forEach(function (l) { 128 l.classList.remove("act"); 129 }); 130 // Close the categories list 131 categoriesList.classList.remove("is-open"); 132 // Update the selected category's text 133 categorySelected.textContent = link.textContent; 134 // Mark the clicked link as active 135 link.classList.add("act"); 136 137 // Hide all demo links 138 demos.forEach(function (demo) { 139 demo.style.display = "none"; 140 }); 141 // Also hide the content holder 142 contentHolder.style.display = "none"; 143 144 // Show only demos that have the matching filter class 145 demos.forEach(function (demo) { 146 if (demo.classList.contains(filterClass)) { 147 demo.style.display = ""; 148 } 149 }); 150 // Fade in the content holder over 300ms 151 fadeIn(contentHolder, 300); 152 }); 153 }); 154 155 // -------------------------- 156 // Simple fadeIn implementation 157 // -------------------------- 158 function fadeIn(element, duration) { 159 element.style.opacity = 0; 160 element.style.display = ""; // Reset display in case it was set to "none" 161 let start = null; 162 163 function step(timestamp) { 164 if (!start) start = timestamp; 165 let progress = timestamp - start; 166 element.style.opacity = Math.min(progress / duration, 1); 167 if (progress < duration) { 168 window.requestAnimationFrame(step); 169 } 170 } 171 172 window.requestAnimationFrame(step); 173 } 174 175});
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.