1const kProgressiveAttr = "data-src"; 2let categoriesLoaded = false; 3 4window.quartoListingCategory = (category) => { 5 if (categoriesLoaded) { 6 activateCategory(category); 7 setCategoryHash(category); 8 } 9}; 10 11window["quarto-listing-loaded"] = () => { 12 // Process any existing hash 13 const hash = getHash(); 14 15 if (hash) { 16 // If there is a category, switch to that 17 if (hash.category) { 18 activateCategory(hash.category); 19 } 20 // Paginate a specific listing 21 const listingIds = Object.keys(window["quarto-listings"]); 22 for (const listingId of listingIds) { 23 const page = hash[getListingPageKey(listingId)]; 24 if (page) { 25 showPage(listingId, page); 26 } 27 } 28 } 29 30 const listingIds = Object.keys(window["quarto-listings"]); 31 for (const listingId of listingIds) { 32 // The actual list 33 const list = window["quarto-listings"][listingId]; 34 35 // Update the handlers for pagination events 36 refreshPaginationHandlers(listingId); 37 38 // Render any visible items that need it 39 renderVisibleProgressiveImages(list); 40 41 // Whenever the list is updated, we also need to 42 // attach handlers to the new pagination elements 43 // and refresh any newly visible items. 44 list.on("updated", function () { 45 renderVisibleProgressiveImages(list); 46 setTimeout(() => refreshPaginationHandlers(listingId)); 47 48 // Show or hide the no matching message 49 toggleNoMatchingMessage(list); 50 }); 51 } 52}; 53 54window.document.addEventListener("DOMContentLoaded", function (_event) { 55 // Attach click handlers to categories 56 const categoryEls = window.document.querySelectorAll( 57 ".quarto-listing-category .category" 58 ); 59 60 for (const categoryEl of categoryEls) { 61 const category = categoryEl.getAttribute("data-category"); 62 categoryEl.onclick = () => { 63 activateCategory(category); 64 setCategoryHash(category); 65 }; 66 } 67 68 // Attach a click handler to the category title 69 // (there should be only one, but since it is a class name, handle N) 70 const categoryTitleEls = window.document.querySelectorAll( 71 ".quarto-listing-category-title" 72 ); 73 for (const categoryTitleEl of categoryTitleEls) { 74 categoryTitleEl.onclick = () => { 75 activateCategory(""); 76 setCategoryHash(""); 77 }; 78 } 79 80 categoriesLoaded = true; 81}); 82 83function toggleNoMatchingMessage(list) { 84 const selector = `#${list.listContainer.id} .listing-no-matching`; 85 const noMatchingEl = window.document.querySelector(selector); 86 if (noMatchingEl) { 87 if (list.visibleItems.length === 0) { 88 noMatchingEl.classList.remove("d-none"); 89 } else { 90 if (!noMatchingEl.classList.contains("d-none")) { 91 noMatchingEl.classList.add("d-none"); 92 } 93 } 94 } 95} 96 97function setCategoryHash(category) { 98 setHash({ category }); 99} 100 101function setPageHash(listingId, page) { 102 const currentHash = getHash() || {}; 103 currentHash[getListingPageKey(listingId)] = page; 104 setHash(currentHash); 105} 106 107function getListingPageKey(listingId) { 108 return `${listingId}-page`; 109} 110 111function refreshPaginationHandlers(listingId) { 112 const listingEl = window.document.getElementById(listingId); 113 const paginationEls = listingEl.querySelectorAll( 114 ".pagination li.page-item:not(.disabled) .page.page-link" 115 ); 116 for (const paginationEl of paginationEls) { 117 paginationEl.onclick = (sender) => { 118 setPageHash(listingId, sender.target.getAttribute("data-i")); 119 showPage(listingId, sender.target.getAttribute("data-i")); 120 return false; 121 }; 122 } 123} 124 125function renderVisibleProgressiveImages(list) { 126 // Run through the visible items and render any progressive images 127 for (const item of list.visibleItems) { 128 const itemEl = item.elm; 129 if (itemEl) { 130 const progressiveImgs = itemEl.querySelectorAll( 131 `img[${kProgressiveAttr}]` 132 ); 133 for (const progressiveImg of progressiveImgs) { 134 const srcValue = progressiveImg.getAttribute(kProgressiveAttr); 135 if (srcValue) { 136 progressiveImg.setAttribute("src", srcValue); 137 } 138 progressiveImg.removeAttribute(kProgressiveAttr); 139 } 140 } 141 } 142} 143 144function getHash() { 145 // Hashes are of the form 146 // #name:value|name1:value1|name2:value2 147 const currentUrl = new URL(window.location); 148 const hashRaw = currentUrl.hash ? currentUrl.hash.slice(1) : undefined; 149 return parseHash(hashRaw); 150} 151 152const kAnd = "&"; 153const kEquals = "="; 154 155function parseHash(hash) { 156 if (!hash) { 157 return undefined; 158 } 159 const hasValuesStrs = hash.split(kAnd); 160 const hashValues = hasValuesStrs 161 .map((hashValueStr) => { 162 const vals = hashValueStr.split(kEquals); 163 if (vals.length === 2) { 164 return { name: vals[0], value: vals[1] }; 165 } else { 166 return undefined; 167 } 168 }) 169 .filter((value) => { 170 return value !== undefined; 171 }); 172 173 const hashObj = {};
174 hashValues.forEach((hashValue) => { 175 hashObj[hashValue.name] = decodeURIComponent(hashValue.value); 176 }); 177 return hashObj; 178} 179 180function makeHash(obj) { 181 return Object.keys(obj) 182 .map((key) => { 183 return `${key}${kEquals}${obj[key]}`; 184 }) 185 .join(kAnd); 186} 187 188function setHash(obj) { 189 const hash = makeHash(obj); 190 window.history.pushState(null, null, `#${hash}`); 191} 192 193function showPage(listingId, page) { 194 const list = window["quarto-listings"][listingId]; 195 if (list) { 196 list.show((page - 1) * list.page + 1, list.page); 197 } 198} 199 200function activateCategory(category) { 201 // Deactivate existing categories 202 const activeEls = window.document.querySelectorAll( 203 ".quarto-listing-category .category.active" 204 ); 205 for (const activeEl of activeEls) { 206 activeEl.classList.remove("active"); 207 } 208 209 // Activate this category 210 const categoryEl = window.document.querySelector( 211 `.quarto-listing-category .category[data-category='${category}'` 212 ); 213 if (categoryEl) { 214 categoryEl.classList.add("active"); 215 } 216 217 // Filter the listings to this category 218 filterListingCategory(category); 219} 220 221function filterListingCategory(category) { 222 const listingIds = Object.keys(window["quarto-listings"]); 223 for (const listingId of listingIds) { 224 const list = window["quarto-listings"][listingId]; 225 if (list) { 226 if (category === "") { 227 // resets the filter 228 list.filter(); 229 } else { 230 // filter to this category 231 list.filter(function (item) { 232 const itemValues = item.values(); 233 if (itemValues.categories !== null) { 234 const categories = itemValues.categories.split(","); 235 return categories.includes(category); 236 } else { 237 return false; 238 } 239 }); 240 } 241 } 242 } 243}
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.