PageSourceSearch

https://uflgame.com/wp-content/themes/theme/blocks/news-archive/tabs.js?ver=1789650020

js uflgame.com collected 2026-09-24 10:47:17 UTC 6,473 bytes, 234 lines download raw bytes

1(() => {
2  'use strict';
3
4  function qs(root, sel) {
5    return root.querySelector(sel);
6  }
7
8  function qsa(root, sel) {
9    return Array.from(root.querySelectorAll(sel));
10  }
11
12  function setActiveTab(links, tag) {
13    links.forEach(a => {
14      a.classList.toggle('active', (a.getAttribute('data-tab') || 'all') === tag);
15    });
16  }
17
18  async function postForm(url, data) {
19    const body = new URLSearchParams(data);
20    const res = await fetch(url, {
21      method: 'POST',
22      headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
23      body: body.toString(),
24      credentials: 'same-origin',
25    });
26    return res.json();
27  }
28
29  function normalizeBaseUrl(u) {
30    try {
31      const url = new URL(u, window.location.origin);
32      if (!url.pathname.endsWith('/')) url.pathname += '/';
33      return url.toString();
34    } catch (e) {
35      return '/news/';
36    }
37  }
38
39  function buildPrettyUrl(baseUrl, tag, page) {
40    baseUrl = normalizeBaseUrl(baseUrl);
41    tag = (tag || 'all').trim() || 'all';
42    page = parseInt(page || '1', 10) || 1;
43
44    const base = new URL(baseUrl, window.location.origin);
45    let p = base.pathname;
46
47    if (tag !== 'all') {
48      p += encodeURIComponent(tag) + '/';
49    }
50    if (page > 1) {
51      p += 'page/' + page + '/';
52    }
53
54    base.pathname = p;
55    base.search = '';
56    base.hash = '';
57    return base.toString();
58  }
59
60  function parseFromHref(baseUrl, href) {
61    const out = {tag: 'all', page: 1};
62
63    let base;
64    let url;
65    try {
66      base = new URL(normalizeBaseUrl(baseUrl), window.location.origin);
67      url = new URL(href, window.location.origin);
68    } catch (e) {
69      return out;
70    }
71
72    // relative path after base
73    let rel = url.pathname;
74    if (rel.startsWith(base.pathname)) {
75      rel = rel.slice(base.pathname.length);
76    }
77    rel = rel.replace(/^\/+|\/+$/g, '');
78    if (!rel) return out;
79
80    const parts = rel.split('/').filter(Boolean);
81
82    // all: page/2
83    if (parts[0] === 'page' && parts[1]) {
84      out.tag = 'all';
85      out.page = parseInt(parts[1], 10) || 1;
86      return out;
87    }
88
89    // tag
90    out.tag = decodeURIComponent(parts[0] || 'all') || 'all';
91
92    // tag/page/2
93    if (parts[1] === 'page' && parts[2]) {
94      out.page = parseInt(parts[2], 10) || 1;
95    }
96
97    return out;
98  }
99
100  function init(root) {
101    const tabs = qs(root, '.tabs');
102    if (!tabs) return;
103
104    const tabLinks = qsa(tabs, 'a[data-tab]');
105    const cardsWrap = qs(root, '.news__cards');
106
107    const paginationSection =
108      root.parentElement?.querySelector('.pagination__content') ||
109      document.querySelector('.pagination__content');
110
111    const perPage = parseInt(root.getAttribute('data-per-page') || '6', 10) || 6;
112    const maxExcerpt = parseInt(root.getAttribute('data-max-excerpt') || '150', 10) || 150;
113
114    const baseUrl =
115      root.getAttribute('data-base-url') ||
116      (window.NEWS_ARCHIVE && NEWS_ARCHIVE.page_url) ||
117      '/news/';
118
119    if (!cardsWrap || !paginationSection) return;
120    if (!window.NEWS_ARCHIVE || !NEWS_ARCHIVE.ajax_url || !NEWS_ARCHIVE.action || !NEWS_ARCHIVE.nonce) return;
121
122    async function load(tag, page, replaceState) {
123      tag = (tag || 'all').trim() || 'all';
124      page = parseInt(page || '1', 10) || 1;
125
126      setActiveTab(tabLinks, tag);
127      root.classList.add('is-loading');
128
129      try {
130        const lang = (() => {
131          try {
132            const p = new URL(normalizeBaseUrl(baseUrl), window.location.origin).pathname;
133            const m = p.match(/^\/([a-z]{2}(?:-[a-z]{2})?)\/news(?:\/|$)/i);
134            return m ? m[1].toLowerCase() : '';
135          } catch (e) {
136            return '';
137          }
138        })();
139
140        const defaultH1 = root.getAttribute('data-default-h1') || '';
141
142        const json = await postForm(NEWS_ARCHIVE.ajax_url, {
143          action: NEWS_ARCHIVE.action,
144          nonce: NEWS_ARCHIVE.nonce,
145          tag: tag,
146          page: page,
147          per_page: perPage,
148          max_excerpt: maxExcerpt,
149          base_url: normalizeBaseUrl(baseUrl),
150          lang: lang,
151          page_head_h1: defaultH1,
152        });
153
154        if (!json || !json.success) return;
155
156        cardsWrap.innerHTML = json.data.cards_html;
157        paginationSection.innerHTML = json.data.pagination_html;
158
159        if (json.data && json.data.head) {
160          const head = json.data.head;
161
162          // H1
163          if (head.h1) {
164            const h1El = document.querySelector('.intro__title');
165            if (h1El) h1El.textContent = head.h1;
166          }
167
168          // <title>
169          if (head.title) {
170            document.title = head.title;
171          }
172
173          // <meta name="description">
174          const desc = (head.description || '').trim();
175          let meta = document.querySelector('meta[name="description"]');
176          if (!meta) {
177            meta = document.createElement('meta');
178            meta.setAttribute('name', 'description');
179            document.head.appendChild(meta);
180          }
181          meta.setAttribute('content', desc);
182        }
183
184        const pretty = buildPrettyUrl(baseUrl, tag, page);
185        if (replaceState) {
186          window.history.replaceState({}
186, '', pretty);
187        } else {
188          window.history.pushState({}, '', pretty);
189        }
190      } finally {
191        root.classList.remove('is-loading');
192      }
193    }
194
195    // Tabs click -> AJAX + pretty URL
196    tabLinks.forEach(a => {
197      a.addEventListener('click', async (e) => {
198        e.preventDefault();
199        const tag = (a.getAttribute('data-tab') || 'all').trim() || 'all';
200        await load(tag, 1, true);
201      });
202    });
203
204    // Pagination click -> AJAX + pretty URL
205    paginationSection.addEventListener('click', async (e) => {
206      const a = e.target.closest('a');
207      if (!a) return;
208
209      // ignore disabled
210      if (a.closest('.disabled')) {
211        e.preventDefault();
212        return;
213      }
214
215      const href = a.getAttribute('href') || '';
216      if (!href || href === '#') return;
217
218      e.preventDefault();
219
220      const parsed = parseFromHref(baseUrl, href);
221      await load(parsed.tag, parsed.page, true);
222    });
223
224    // Back/Forward support
225    window.addEventListener('popstate', () => {
226      const parsed = parseFromHref(baseUrl, window.location.href);
227      load(parsed.tag, parsed.page, true);
228    });
229  }
230
231  document.addEventListener('DOMContentLoaded', () => {
232    document.querySelectorAll('section.news__content.alternate').forEach(init);
233  });
234})();

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.