PageSourceSearch

https://www.chiragjpgroup.org/site_libs/quarto-listing/quarto-listing.js

js chiragjpgroup.org collected 2026-10-02 07:19:06 UTC 6,638 bytes, 243 lines download raw bytes

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.