PageSourceSearch

https://www.pcmag.com/js/alpine/content-list-show-more.js

js pcmag.com collected 2026-09-24 06:04:10 UTC 7,738 bytes, 216 lines download raw bytes

1window.contentListShowMore = function (url, trackingModule, filters = []) {
2  return {
3    filters,
4    selectedFilter: {},
5    showMore: !!url,
6    showMoreUrl: url ?? "",
7    trackingModule,
8    lastScrollPosition: 0,
9    template: window?.template ?? "",
10    currentPage: 1,
11    selectFilter: function (item = null) {
12      this.selectedFilter = item;
13      this.currentPage = this.selectedFilter?.currentPage ?? 1;
14
15      if (this.selectedFilter?.showMore !== undefined) {
16        this.showMore = this.selectedFilter.showMore;
17      }
18
19      if (this.selectedFilter?.showMoreUrl) {
20        this.showMoreUrl = this.selectedFilter.showMoreUrl;
21      }
22
23      this.updatePaginationDisplay();
24
25      if (this.shouldUseFullReload()) {
26        const url = new URL(window.location.href);
27
28        if (this.selectedFilter.model === "all") {
29          url.searchParams.delete("model");
30        } else {
31          url.searchParams.set("model", this.selectedFilter.model);
32        }
33
34        if (this.selectedFilter?.id !== undefined && this.selectedFilter?.id !== null && this.selectedFilter?.id !== "") {
35          url.searchParams.set("id", this.selectedFilter.id);
36        } else {
37          url.searchParams.delete("id");
38        }
39
40        url.searchParams.delete("type");
41
42        url.searchParams.set("page", "1");
43
44        // Save scroll position before reload
45        sessionStorage.setItem('contentListScrollPosition', window.scrollY.toString());
46
47        window.location.href = url.toString();
48
49        return;
50      }
51
52      const containerId = this.selectedFilter.slug
53        ? `${this.selectedFilter.slug}-show-more-content-${this.trackingModule}`
54        : `show-more-content-${this.trackingModule}`;
55      const container = document.getElementById(containerId);
56
57      if (container && container.children.length) {
58        return;
59      }
60
61      this.getNextPage();
62    },
63    shouldUseFullReload: function () {
64      return Boolean(this.selectedFilter?.requires_full_reload);
65    },
66    updatePaginationDisplay: function () {
67      if (typeof window !== "undefined" && typeof window.dispatchEvent === "function") {
68        const detail = {
69          totalPages: this.selectedFilter?.totalPages ?? this.currentPage,
70          currentPage: this.selectedFilter?.currentPage ?? this.currentPage,
71          filterModel: this.selectedFilter?.model ?? "all",
72        };
73
74        window.dispatchEvent(new CustomEvent("filter-changed", { detail }));
75      }
76    },
77    getNextPage: async function () {
78      const includeId = this.selectedFilter?.id !== undefined && this.selectedFilter?.id !== null && this.selectedFilter?.id !== "";
79
80      const updates = {
81        type: this.selectedFilter.slug,
82        model: this.selectedFilter.model,
83        ajax: "1",
84      };
85
86      if (includeId) {
87        updates.id = this.selectedFilter.id;
88      }
89
90      const searchParams = new URLSearchParams(this.showMoreUrl.split("?")[1]);
91      Object.entries(updates).forEach(([key, value]) => searchParams.set(key, value));
92
93      if (!includeId) {
94        searchParams.delete("id");
95      }
96
97      // Update page parameter for the current filter
98      const nextPage = this.currentPage + 1;
99      searchParams.set("page", nextPage);
100
101      const url = `${this.showMoreUrl.split("?")[0]}?${searchParams.toString()}`;
102      try {
103        const response = await fetch(url);
104        if (!response.ok) throw { status: response.status, statusText: response.statusText, url: response.url };
105        const { showMore, showMoreUrl, contentHubStrips, totalPages, currentPage, totalItems } = await response.json();
106        this.showMore = showMore;
107        this.showMoreUrl = showMoreUrl;
108        this.selectedFilter.showMore = showMore;
109        this.selectedFilter.showMoreUrl = showMoreUrl;
110
111        // Update pagination info from server response
112        if (totalPages !== undefined) {
113          this.selectedFilter.totalPages = totalPages;
114        }
115        if (totalItems !== undefined) {
116          this.selectedFilter.totalItems = totalItems;
117        }
118
119        // Update current page after successful load
120        this.currentPage = currentPage || nextPage;
121        this.selectedFilter.currentPage = currentPage || nextPage;
122
123        let str = contentHubStrips;
124        const regexp = /data-id=\"([^\"]+)\"/g;
125        const matches = [...str.matchAll(regexp)];
126
127        matches.forEach((value) => {
128          if (document.querySelectorAll(`[${value[0]}]`).length) {
129            const dataValue = `${value[1]}" class="`;
130            const position = str.indexOf(dataValue) + dataValue.length;
131            str = str.substr(0, position) + str.substr(position);
132          }
133        });
134
135        this.lastScrollPosition = window.scrollY;
136        const showMoreContentContainerId = this.selectedFilter.slug
137          ? `${this.selectedFilter.slug}-show-more-content-${this.trackingModule}`
138          : `show-more-content-${this.trackingModule}`;
139        document.getElementById(showMoreContentContainerId).insertAdjacentHTML("beforeend", str);
140        this.$nextTick(() => {
141          window.scrollTo({ top: this.lastScrollPosition + 1, behavior: "auto" });
142          // Update pagination display after loading new content
143          this.updatePaginationDisplay();
144        });
145      } catch (error) {
146        console.error("Error fetching data:", error);
147      }
148    },
149    init: function () {
150      if (this.filters.length) {
151        // Check URL parameters to determine initial filter
152        const urlParams = new URLSearchParams(window.location.search);
153        const modelFromUrl = urlParams.get("model") || "all";
154        const idFromUrl = urlParams.get("id");
155        const typeFromUrl = urlParams.get("type");
156
157        const potentialPageKeys = [typeFromUrl, modelFromUrl, "page"].filter(Boolean);
158        let pageFromUrl = "1";
159        for (const key of potentialPageKeys) {
160          const value = urlParams.get(key);
161          if (value) {
162            pageFromUrl = value;
163            break;
164          }
165        }
166
167        // Find the filter that matches the URL parameters as closely as possible
168        const initialFilter = this.filters.find((filter) => {
169          if (filter.model !== modelFromUrl) {
170            return false;
171          }
172
173          if (idFromUrl) {
174            return String(filter.id ?? "") === idFromUrl;
175          }
176
177          if (typeFromUrl) {
178            return filter.slug === typeFromUrl;
179          }
180
181          return true;
182        }) || this.filters[0];
183
184        this.selectedFilter = initialFilter;
185        const currentPage = parseInt(pageFromUrl, 10) || 1;
186        this.selectedFilter.currentPage = currentPage;
187
188        // Only show "Show More" if there are more pages available
189        if (this.selectedFilter.totalPages !== undefined) {
190          this.selectedFilter.showMore = !!url && (this.selectedFilter.totalPages > currentPage);
191        }
192
193        this.selectedFilter.showMoreUrl = this.selectedFilter.showMoreUrl ?? url;
194        this.currentPage = currentPage;
195        this.showMore = this.selectedFilter.showMore ?? !!url;
196        this.updatePaginationDisplay();
197
198        // Initialize each filter with its current page if not already set
199        this.filters.forEach((filter) => {
200          if (!filter.currentPage) {
201            filter.currentPage = 1;
202          }
203        });
204      }
205
206      // Restore scroll position after full page reload
207      const savedScrollPosition = sessionStorage.getItem('contentListScrollPosition');
208      if (savedScrollPosition !== null) {
209        setTimeout(() => {
210          window.scrollTo({ top: parseInt(savedScrollPosition, 10), behavior: 'auto' });
211          sessionStorage.removeItem('contentListScrollPosition');
212        }, 100);
213      }
214    },
215  };
216};

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.