PageSourceSearch

https://www.uaqwxhnno.cc/usr/themes/Mirages/js/7.10.0/search.js?v=c60e69c

js uaqwxhnno.cc collected 2026-09-26 05:36:09 UTC 34,376 bytes, 865 lines download raw bytes

1;(async function (doc, win, layer, hotRankList, keyword) {
2  const buildSearchUrl = k => `/search/${encodeURIComponent(k)}/`
3  const isSearchPage = () => window.location.pathname.includes("search-page")
4  const HISTORY_KEY = "__GLOBAL_SEARCH_HISTORY__"
5  const escapeHTML = raw =>
6    String(raw ?? "")
7      .replace(/&/g, "&")
8      .replace(/</g, "&lt;")
9      .replace(/>/g, "&gt;")
10      .replace(/"/g, "&quot;")
11      .replace(/'/g, "&#39;")
12
13  const parseKeyword = (raw, domparser) => {
14    const keywordhtml = domparser.parseFromString(String(raw || "").trim(), "text/html")
15    return keywordhtml.body.textContent
16  }
17
18  const initSearchAdLazyLoad = () => {
19    const images = Array.from(doc.querySelectorAll(".horizontal-banner img[data-lazy-ad][data-src]")).filter(
20      img => img.dataset.src
21    )
22    if (!images.length) return
23
24    const loadAd = img => {
25      const src = img.dataset.src
26      if (!src || img.dataset.loaded === "1") return
27      img.dataset.loaded = "1"
28      if (typeof win.loadImage === "function" && img.id) {
29        win.loadImage(src, img.id)
30        return
31      }
32      img.src = src
33    }
34
35    if (!("IntersectionObserver" in win)) {
36      images.forEach(loadAd)
37      return
38    }
39
40    const observer = new IntersectionObserver(
41      entries => {
42        entries.forEach(entry => {
43          if (!entry.isIntersecting) return
44          observer.unobserve(entry.target)
45          loadAd(entry.target)
46        })
47      },
48      { rootMargin: "200px 0px" }
49    )
50
51    images.forEach(img => observer.observe(img))
52  }
53
54  const addSearchHistory = keyword => {
55    if (!keyword) return
56    let history = []
57    try {
58      history = JSON.parse(localStorage.getItem(HISTORY_KEY)) || []
59    } catch (error) {
60      history = []
61    }
62    history = [keyword, ...history.filter(item => item !== keyword)].slice(0, 8)
63    localStorage.setItem(HISTORY_KEY, JSON.stringify(history))
64    if (win.$HistoryRecord && typeof win.$HistoryRecord.show === "function") {
65      win.$HistoryRecord.show(history)
66    }
67  }
68
69  const submitSearch = keyword => {
70    if (!keyword || keyword.length < 1) return
71    try {
72      addSearchHistory(keyword)
73      top.location.href = buildSearchUrl(keyword)
74    } catch (error) {
75      window.location.href = buildSearchUrl(keyword)
76    }
77  }
78  // 列表(搜索结果)
79  class SortList {
80    constructor(selector, url) {
81      const _this = this
82      this.$archive = () => $(selector)
83      this.keyword = keyword
84      this.url = url
85      this.sort = ""
86      this.page = 1
87
88      // 单选
89      $(document).on("change", '.xqbj-search-sort input[name="searchsort"][type="radio"]', function () {
90        _this.sort = $(this).val()
91        _this.page = 1
92        _this.load()
93      })
94    }
95
96    // 入口方法
97    load() {
98      this.showLoading()
99      this.fetchData()
100        .done(html => {
101          this.renderList(html)
102          this.bindEvents()
103        })
104        .fail(() => {
105          layer.msg("数据请求失败")
106        })
107        .always(() => {
108          this.goTop()
109          setTimeout(() => {
110            layer.closeAll("loading")
111          }, 500)
112        })
113    }
114
115    // 请求
116    fetchData() {
117      const data = {
118        q: this.keyword,
119        sort: this.sort,
120        page: this.page
121      }
122
123      return $.ajax({
124        url: this.url,
125        method: "GET",
126        data
127      })
128    }
129
130    // 渲染[后端处理]
131    renderList(html) {
132      this.$archive().fadeOut("fast", () => {
133        // [后端处理]
134        // this.$archive.replaceWith(this.listTemplate()).fadeIn(300);
135        this.$archive().replaceWith(html).fadeIn(300)
136      })
137    }
138
139    // 模板(列表 + 分页)[后端处理]
140    listTemplate = html => {
141      return `
142                <div id="archive" role="main">
143                    <article itemscope itemtype="http://schema.org/BlogPosting" class="">
144                        <div class="display-none" itemscope itemprop="author" itemtype="http://schema.org/Person">
145                            <meta itemprop="name" content="瓜瓜"/>
146                            <meta itemprop="url" content=""/>
147                        </div>
148                        <div class="display-none" itemscope itemprop="publisher" itemtype="http://schema.org/Organization">
149                            <meta itemprop="name" content="瓜瓜"/>
150                            <div itemscope itemprop="logo" itemtype="http://schema.org/ImageObject">
151                                <meta itemprop="url" content="/usr/themes/Mirages/images/51cg.png?s=50&amp;r=G&amp;d=">
152                            </div>
153                        </div>
154                        <meta itemprop="url mainEntityOfPage" content="https://51cg1.com/archives/207221/" />
155                        <meta itemprop="dateModified" content="2025-05-19T09:10:30+00:00">
156                        <a href="https://51cg1.com/archives/207221/" >
157                            <div class="post-card" id="post-card-207221" >
158                                <div class="blog-background"></div>
159                                <script type="text/javascript">
160                                    loadBannerDirect('https://pic.sqbcn.cn/upload_01/xiao/20250517/2025051717181423596.jpeg', '', document.querySelector('#post-card-207221'), '-1', document.querySelector('#post-card-207221').offsetWidth, document.querySelector('#post-card-207221').offsetHeight);
161                                </script>
162                                <div class="post-card-mask ">
163                                <div class="post-card-container">
164                                    <h2 class="post-card-title" itemprop="headline">日本AV女优路边撩素人 偶遇中国猛男上集 车内激战持久狂野 事后甩50万日元惊呆女优 形象瞬间高大!</h2>
165                                        <div class="post-card-info">
166                                            <span itemprop="author" itemscope itemtype="http://schema.org/Person">瓜瓜 • </span>                                                <span itemprop="datePublished" content="2025-05-17T16:18:00+00:00">2025 年 05 月 17 日 • </span>
167                                            <span>今日吃瓜, 看片娱乐</span>
168                                        </div>
169                                    </div>
170                                </div>
171                            </div>
172                        </a>
173                    </article>
174                    <article itemscope itemtype="http://schema.org/BlogPosting" class="">
175                        <div class="display-none" itemscope itemprop="author" itemtype="http://schema.org/Person">
176                            <meta itemprop="name" content="瓜表妹"/>
177                            <meta itemprop="url" content=""/>
178                        </div>
179                        <div class="display-none" itemscope itemprop="publisher" itemtype="http://schema.org/Organization">
180                            <meta itemprop="name" content="瓜表妹"/>
181                            <div itemscope itemprop="logo" itemtype="http://schema.org/ImageObject">
182                                <meta itemprop="url" content="/usr/themes/Mirages/images/51cg.png?s=50&amp;r=G&amp;d=">
183                            </div>
184                        </div>
185                        <meta itemprop="url mainEntityOfPage" content="https://51cg1.com/archives/206994/" />
186                        <meta itemprop="dateModified" content="2025-05-19T09:10:36+00:00">
187                        <a href="https://51cg1.com/archives/206994/" >
188                            <div class="post-card" id="post-card-206994" >
189                                <div class="blog-background"></div>
190                                <script type="text/javascript">
191                                loadBannerDirect('https://pic.sqbcn.cn/upload_01/xiao/20250516/2025051621385232406.jpeg', '', document.querySelector('#post-card-206994'), '-1', document.querySelector('#post-card-206994').offsetWidth, document.querySelector('#post-card-206994').offsetHeight);
192                                </script>
193                                <div class="post-card-mask ">
194                                    <div class="post-card-container">
195                                        <h2 class="post-card-title" itemprop="headline">台湾极品福利姬女神 波衣 道具自慰喷水私拍合集 近距离展示美乳嫩穴无限魅惑 娇喘勾魂诱人!</h2>
196                                        <div class="post-card-info">
197                                            <span itemprop="author" itemscope itemtype="http://schema.org/Person">瓜表妹 • </span>                                                <span itemprop="datePublished" content="2025-05-17T16:00:00+00:00">2025 年 05 月 17 日 • </span>
198                                            <span>今日吃瓜, 网红黑料</span>
199                                        </div>
200                                    </div>
201                                </div>
202                            </div>
203                        </a>
204                    </article>
205                    <article itemscope itemtype="http://schema.org/BlogPosting" class="">
206                        <div class="display-none" itemscope itemprop="author" itemtype="http://schema.org/Person">
207                            <meta itemprop="name" content="瓜表妹"/>
208                            <meta itemprop="url" content=""/>
209                        </div>
210                        <div class="display-none" itemscope itemprop="publisher" itemtype="http://schema.org/Organization">
211                            <meta itemprop="name" content="瓜表妹"/>
212                            <div itemscope itemprop="logo" itemtype="http://schema.org/ImageObject">
213                                <meta itemprop="url" content="/usr/themes/Mirages/images/51cg.png?s=50&amp;r=G&amp;d=">
214                            </div>
215                        </div>
216                        <meta itemprop="url mainEntityOfPage" content="https://51cg1.com/archives/206989/" />
217                        <meta itemprop="dateModified" content="2025-05-19T09:10:44+00:00">
218                        <a href="https://51cg1.com/archives/206989/" >
219                            <div class="post-card" id="post-card-206989" >
220                                <div class="blog-background"></div>
221                                <script type="text/javascript">
222                                    loadBannerDirect('https://pic.sqbcn.cn/upload_01/xiao/20250516/2025051620282659908.jpeg', '', document.querySelector('#post-card-206989'), '-1', document.querySelector('#post-card-206989').offsetWidth, document.querySelector('#post-card-206989').offsetHeight);
223                                </script>
224                                <div class="post-card-mask ">
225                                    <div class="post-card-container">
226                                        <h2 class="post-card-title" itemprop="headline">极品反差女神 私拍道具插穴特写 粉嫩蜜穴淫水泛滥 蜜桃臀高潮喷涌 画面撩到爆!</h2>
227                                        <div class="post-card-info">
228                                            <span itemprop="author" itemscope itemtype="http://schema.org/Person">瓜表妹 • </span>                                                <span itemprop="datePublished" content="2025-05-17T15:30:00+00:00">2025 年 05 月 17 日 • </span>
229                                            <span>今日吃瓜, 骚男骚女</span>
230                                        </div>
231                                    </div>
232                                </div>
233                            </div>
234                        </a>
235                    </article>
236                    <article itemscope itemtype="http://schema.org/BlogPosting" class="">
237                        <div class="display-none" itemscope itemprop="author" itemtype="http://schema.org/Person">
238                            <meta itemprop="name" content="瓜二哥"/>
239                            <meta itemprop="url" content=""/>
240                        </div>
241                        <div class="display-none" itemscope itemprop="publisher" itemtype="http://schema.org/Organization">
242                            <meta itemprop="name" content="瓜二哥"/>
243                            <div itemscope itemprop="logo" itemtype="http://schema.org/ImageObject">
244                                <meta itemprop="url" content="/usr/themes/Mirages/images/51cg.png?s=50&amp;r=G&amp;d=">
245                            </div>
246                        </div>
247                        <meta itemprop="url mainEntityOfPage" content="https://51cg1.com/archives/207136/" />
248                        <meta itemprop="dateModified" content="2025-05-19T09:09:56+00:00">
249                        <a href="https://51cg1.com/archives/207136/" >
250                            <div class="post-card" id="post-card-207136" >
251                                <div class="blog-background"></div>
252                                <script type="text/javascript">
253                                loadBannerDirect('https://pic.sqbcn.cn/upload_01/xiao/20250516/2025051621454710950.jpeg', '', document.querySelector('#post-card-207136'), '-1', document.querySelector('#post-card-207136').offsetWidth, document.querySelector('#post-card-207136').offsetHeight);
254                                </script>
255                                <div class="post-card-mask ">
256                                    <div class="post-card-container">
257                                        <h2 class="post-card-title" itemprop="headline">抖音推特双平台反差母狗 露脸自慰裸舞合集 抖奶露穴超级淫骚 性感身材令人血脉喷张!</h2>
258                                        <div class="post-card-info">
259                                            <span itemprop="author" itemscope itemtype="http://schema.org/Person">瓜二哥 • </span>                                                <span itemprop="datePublished" content="2025-05-17T15:21:00+00:00">2025 年 05 月 17 日 • </span>
260                                            <span>今日吃瓜, 网红黑料</span>
261                                        </div>
262                                    </div>
263                                </div>
264                            </div>
265                        </a>
266                    </article>
267
268                    <div class="page-nav page-nav-ajax">
269                        <div class="page-jump">
270                            <div id="pageForm" method="get">
271                                <span class="page-info"> 12/518 </span>
272                                <input type="number" id="pageNum">
273                                <button id="submitBtn">跳转</button>
274                            </div>
275                        </div>
276                        <ul class="page-navigator">
277                            <li class="prev"><a href="javascript:void(0);" data-page="11">上一页</a></li>
278                            <li><span></span></li>
279                            <li class="next"><a href="javascript:void(0);" data-page="13">下一页</a></li>
280                        </ul>
281                    </div>
282                </div>
283            `
284    }
285
286    // 事件
287    bindEvents() {
288      const _this = this
289      $(doc)
290        .off("click.pageNav")
291
292        // 上一页
293        .on("click.pageNav", ".page-nav-ajax .prev a", function (e) {
294          e.preventDefault()
295          _this.page = $(this)?.data("page") || 1
296          // console.log('prev clicked', $(this).data('page'));
297          _this.load()
298        })
299
300        // 下一页
301        .on("click.pageNav", ".page-nav-ajax .next a", function (e) {
302          e.preventDefault()
303          _this.page = $(this)?.data("page") || 1
304          _this.load()
305        })
306
307        // 跳转按钮
308        .on("click.pageNav", ".page-nav-ajax #submitBtn", function (e) {
309          e.preventDefault()
310          const input = $(this).closest(".page-nav-ajax").find("input").val()
311
312          _this.page = 1 * input || 1
313          _this.load()
314        })
315    }
316
317    // 显示加载动画
318    showLoading() {
319      layer.load(0)
320    }
321
322    // 显示加载动画
323    goTop() {
324      window.scrollTo({
325        top: 0,
326        behavior: "smooth"
327      })
328    }
329  }
330
331  // 导航(头部导航)
332  class NavSearch {
333    constructor(hoturl, url, throttleInterval, keyLength) {
334      const _this = this
335      this.hoturl = hoturl
336      this.url = url
337      this.throttleInterval = throttleInterval
338      this.keyLength = keyLength
339      this.domparser = new DOMParser()
340
341      // 模板定义(历史)
342      this.hotTemplate = (c = {}) => {
343        const source = Array.isArray(c) ? { hotArticles: c, hotTags: [] } : c || {}
344        const tagList = Array.isArray(source.hotTags) ? source.hotTags.slice(0, 10) : []
345        const searchList = Array.isArray(source.hotSearches)
346          ? source.hotSearches
347          : Array.isArray(source.hotArticles)
348            ? source.hotArticles
349            : []
350        const list = searchList.slice(0, 10)
351        const hasTags = tagList.length > 0
352        const hasData = list.length > 0
353        return `
354                    <div class="container-search-context">
355                    <div class="search-container">
356                        <div class="search-title">
357                        <span>历史记录</span>
358                        <div class="r-text on-history-clear">
359                            <i class="fa fa-trash-o icon"></i>
360                            删除记录
361                        </div>
362                        </div>
363                        <div class="container-search-tags">
364                        <div class="list history-record">
365                            <div class="no-data">暂无记录</div>
366                        </div>
367                        </div>
368
369                        <div class="search-title">
370                        <span>热门标签</span>
371                        </div>
372                        <div class="hot-tag-list">
373                        ${
374                          hasTags
375                            ? tagList
376                                .map(e => {
377                                  const name = escapeHTML(e.name || "")
378                                  const url = e.url || buildSearchUrl(e.name || "")
379                                  return `<a href="${url}" class="hot-tag-item">${name}</a>`
380                                })
381                                .join("")
382                            : `<div class="no-data">暂无数据</div>`
383                        }
384                        </div>
385
386                        <div class="search-title search-border">
387                        <span>热门搜索</span>
388                        </div>
389                        <div class="container-search-hots">
390                        ${
391                          hasData
392                            ? `
393                                <div class="rank-list">
394                                    ${list
395                                      .map(
396                                        (e, index) => `
397                                        <a href="${e.permalink}" class="rank-card">
398                                            ${index <= 2 ? `<div class="xqbj-icon-rank-${index + 1} rank-card-icon"></div>` : `<div class="rank-card-icon rank-card-num">${index + 1}</div>`}
399                                            <div class="rank-card-title text-line-ellipsis-1">${escapeHTML(e.title)}</div>
400                                            <div class="rank-card-meta">
401                                              <span class="view"><span class="view-num">${escapeHTML(e.hot_formatted)}</span><span class="view-suffix">热度</span></span>
402                                              <span class="hot-badge">热</span>
403                                            </div>
404                                        </a>
405                                    `
406                                      )
407                                      .join("")}
408                                </div>
409                            `
410                            : `<div class="no-data">暂无数据</div>`
411                        }
412                        </div>
413                    </div>
414                    </div>
415                `
416      }
417      this.renderSuggestList = (keyword, listSearchContainer, data) => {
418        const safeKeyword = keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
419        const regex = new RegExp(safeKeyword, "g")
420        const list = {
421          list: data.map(e => ({
422            title: e,
423            url: buildSearchUrl(e)
424          }))
425        }
426
427        list.list = list.list.map(item => ({
428          ...item,
429          title: item.title.replace(regex, `<span class="keyword">${keyword}</span>`)
430        }))
431
432        const tpl = _this.seaTemplate(list)
433        $(listSearchContainer).html(tpl)
434      }
435
436      this.requestSuggest = (keyword, listSearchContainer, hotSearchContainer) => {
437        if (!keyword) {
438          $(listSearchContainer).removeClass("show").html("")
439          if (hotSearchContainer) {
440            $(hotSearchContainer).addClass("show")
441          }
442          return
443        }
444
445        _this
446          .fetchSearchData(keyword)
447          .done(d => {
448            _this.renderSuggestList(keyword, listSearchContainer, d)
449          })
450          .fail(() => {})
451          .always(() => {
452            $(listSearchContainer).addClass("show")
453            if (hotSearchContainer) {
454              $(hotSearchContainer).removeClass("show")
455            }
456          })
457      }
458
459      this.seaTemplate = c => {
460        const list = Array.isArray(c?.list) ? c.list.slice(0, 20) : []
461        if (list.length === 0) return ""
462
463        return `
464                    <div class="container-search-context">
465                      <div class="search-container">
466                        <div class="container-search-hots container-search-lists">
467                          <div class="rank-list">
468                            ${list
469                              .map(
470                                e => `
471                              <a href="${e.url}" class="rank-card">
472                                <div class="xqbj-icon-search1"></div>
473                                <div class="rank-card-title text-line-ellipsis-1">${e.title ?? ""}</div>
474                              </a>
475                            `
476                              )
477                              .join("")}
478                          </div>
479                        </div>
480                      </div>
481                    </div>
482              `
483      }
484
485      // 初始(mobile)
486      $(doc).on("click", "form#search-form .search-form-input", function (e) {
487        top.location.href = "/search-page.html"
488      })
489
490      $(doc).on("click", "form#search-form #search_btn", function (e) {
491        e.preventDefault()
492        top.location.href = "/search-page.html"
493      })
494
495      // 输入(mobile)
496      $(doc).on(
497        "input",
498        "#input-mobile-control-key",
499        _this.debounce(function () {
500          const searchRoot = $(this).closest(".search-page-mobile-search, .nav-search-container")
501          const listSearchContainer = searchRoot.find(".container-list-search").get(0)
502          const hotSearchContainer = isSearchPage()
503            ? $(".search-page__panel .container-hot-search").get(0)
504            : searchRoot.find(".container-hot-search").get(0)
505          const keyword = parseKeyword($(this).val(), _this.domparser)
506
507          _this.requestSuggest(keyword, listSearchContainer, hotSearchContainer)
508        }, _this.throttleInterval)
509      )
510
511      // 搜索(mobile)
512      $(doc).on("click", ".input-mobile-search-btn", function () {
513        const keyword = parseKeyword(
514          $(this).closest(".search-page-mobile-header").find("#input-mobile-control-key").val(),
515          _this.domparser
516        )
517        submitSearch(keyword)
518      })
519
520      // xf0714 搜索-键盘(mobile) start
521      $("#input-mobile-control-key").on("keydown", function (event) {
522        if (event.key === "Enter") {
523          event.preventDefault()
524          submitSearch(parseKeyword($(this).val(), _this.domparser))
525        }
526      })
527      // xf0714 搜索-键盘(mobile) end
528
529      // 桌面端导航搜索 -> 跳转二级页面
530      $(doc).on("click", "#navbar .nav-search-container", function (e) {
531        e.preventDefault()
532        e.stopPropagation()
533        if (isSearchPage()) {
534          $("#input-page-control-key").trigger("focus")
535          return
536        }
537        top.location.href = "/search-page.html"
538      })
539
540      // 搜索页 PC 输入联想
541      $(doc).on(
542        "input",
543        "#input-page-control-key",
544        _this.debounce(function () {
545          const keyword = parseKeyword($(this).val(), _this.domparser)
546          const listSearchContainer = $(".search-page__suggest .container-list-search").get(0)
547          const hotSearchContainer = $(".search-page__panel .container-hot-search").get(0)
548          _this.requestSuggest(keyword, listSearchContainer, hotSearchContainer)
549        }, _this.throttleInterval)
550      )
551
552      $(doc).on("click", ".input-page-search-btn", function () {
553        submitSearch(parseKeyword($("#input-page-control-key").val(), _this.domparser))
554      })
555
556      $(doc).on("keydown", "#input-page-control-key", function (e) {
557        if (e.key === "Enter") {
558          e.preventDefault()
559          submitSearch(parseKeyword($(this).val(), _this.domparser))
560        }
561      })
562
563      // 返回
564      $(doc).on("click", ".backbtn", function () {
565        const currentUrl = window.location.href
566
567        if (currentUrl.includes("search-page")) {
568          top.location.href = "/"
569        } else if (
570          window.location.protocol === "file:" ||
571          (!document.referrer && document.referrer.startsWith("file://"))
572        ) {
573          top.location.href = `/`
574        } else if (!document.referrer) {
575          top.location.href = `/`
576        } else {
577          const fallbackUrl = "/"
578          const firstUrl = sessionStorage.getItem("firstNonSearchUrl")
579          if (firstUrl) {
580            top.location.href = firstUrl
581          } else {
582            top.location.href = fallbackUrl
583          }
584        }
585      })
586
587      // 搜索历史收集(mobile and desktop)
588      $(doc).on(
589        "click",
590        ".container-search-tags a, .hot-tag-list a, .container-search-lists a, .xqbj-search-tags-list a, .xqbj-search-none a",
591        function (event) {
592          const keywordhtml = _this.domparser.parseFromString(
593            $(event.target)
594              ?.text()
595              ?.replace(/(^\s*)|(\s*$)/g, ""),
596            "text/html"
597          )
598          const keyword = keywordhtml.body.textContent
599          try {
600            $HistoryRecord.add(keyword)
601          } catch (error) {
602            // console.log("历史信息收集失败", error);
603          }
604        }
605      )
606
607      //
608      // this.init()
609    }
610
611    // 初始化
612    init() {
613      const _this = this
614      const renderHot = data => {
615        const tpl = _this.hotTemplate(data)
616
617        $(".search-page__panel .container-hot-search").html(tpl).addClass("show")
618
619        const navHotSearchContainer = $("#navbar .nav-search-container .container-hot-search").get(0)
620        if (navHotSearchContainer && !isSearchPage()) {
621          $(navHotSearchContainer).html(tpl).addClass("show")
622        }
623
624        win?.$HistoryRecord && win?.$HistoryRecord.init()
625      }
626
627      const loadHot = () => {
628        _this
629          .fetchHotData()
630          .done(res => {
631            const data = res?.data || {}
632            const hotTags = Array.isArray(data.hotTags) ? data.hotTags : []
633            const hotArticles = Array.isArray(data.hotSearches)
634              ? data.hotSearches
635              : Array.isArray(data.hotArticles)
636                ? data.hotArticles
637                : []
638            // 构建者正在工作且暂无 stale 时,保留 SSR 热榜,不用空降级覆盖。
639            if (hotTags.length === 0 && hotArticles.length === 0) return
640            renderHot({
641              hotTags,
642              hotSearches: hotArticles,
643              hotArticles: hotArticles.length > 0 ? hotArticles : hotRankList
644            })
645          })
646          .fail(() => {
647            if (!isSearchPage()) {
648              renderHot(hotRankList)
649            }
650          })
651      }
652
653      // 热榜只在搜索页按需读取一次。全站每页请求/每 30s 轮询会放大缓存过期惊群。
654      if (isSearchPage()) {
655        loadHot()
656        $(".search-page__panel .container-hot-search").addClass("show")
657      }
658
659      win?.$HistoryRecord && win?.$HistoryRecord.init()
660
661      if (isSearchPage()) {
662        setTimeout(() => {
663          if (window.innerWidth < 768) {
664            $("#input-mobile-control-key").trigger("focus")
665          } else {
666            $("#input-page-control-key").trigger("focus")
667          }
668        }, 100)
669      }
670    }
671    // 搜索请求
672    fetchSearchData(keyword) {
673      const _this = this
674      if (keyword.length <= _this.keyLength) throw new Error("关键词长度必须大于2")
675
676      const data = {
677        q: encodeURIComponent(keyword)
678      }
679
680      return $.ajax({
681        url: `${this.url}`,
682        method: "GET",
683        data
684      })
685    }
686
687    // 热门请求
688    fetchHotData() {
689      const _this = this
690      return $.ajax({
691        url: _this.hoturl,
692        method: "GET"
693      })
694    }
695
696    // 节流
697    debounce(func, delay) {
698      let timer = null
699      return function (...args) {
700        if (timer) clearTimeout(timer)
701        timer = setTimeout(() => {
702          func.apply(this, args)
703          timer = null
704        }, delay)
705      }
706    }
707  }
708
709  // 历史(搜索历史)
710  class HistoryRecord {
711    constructor() {
712      this.key = HISTORY_KEY // localStorage 的 key
713      this.max = 8 // 最多保存 20 条记录
714      this.listcontainer = "div.history-record" // 列表容器元素
715      this.init() // 初始加载记录
716    }
717    getHistory() {
718      try {
719        const history = JSON.parse(localStorage.getItem(this.key)) || []
720        return Array.isArray(history) ? history : []
721      } catch (error) {
722        return []
723      }
724    }
725
726    // 加载
727    init() {
728      const _this = this
729      this.show(this.getHistory())
730
731      // 事件
732      _this.event()
733    }
734
735    // 事件
736    event() {
737      const _this = this
738      $(doc).on("click", ".on-history-clear", function () {
739        _this.clear()
740      })
741
742      $(doc).on("click", ".on-history-delete", function (e) {
743        e.preventDefault()
744        const keyword = $(this).closest("a").text()
745        _this.del(keyword)
746      })
747
748      // 点击每个历史项 删除自身 并更新本地存储的数据
749      $(doc).on("click", ".history-record-item .history-close", function (e) {
750        e.preventDefault()
751        const $item = $(this).closest(".history-record-item")
752        const keyword = $item.find("a span").text()
753        _this.del(keyword)
754      })
755    }
756
757    // 显示(操作)
758    show(historys) {
759      const $container = $(this.listcontainer)
760      $container &&
761        $container.each((index, c) => {
762          let tpl = '<div class="no-data">暂无记录</div>'
763          if (historys?.length > 0) {
764            tpl = historys
765              .map(
766                item => `<div class='history-record-item'>
767                  <a href="${buildSearchUrl(item)}"><span class="text-line-ellipsis-1">${item}</span></a>
768                  <img src='/usr/themes/Mirages/images/history-close.png' class='history-close' alt='close'/>
769                </div>`
770              )
771              .join("")
772          }
773          c.innerHTML = tpl
774        })
775    }
776
777    // 添加
778    add(keyword) {
779      if (!keyword) return
780
781      let history = this.getHistory()
782
783      // 去重 + 添加到开头 + 限制数量
784      history = [keyword, ...history.filter(item => item !== keyword)].slice(0, this.max)
785
786      localStorage.setItem(this.key, JSON.stringify(history))
787      this.show(history)
788    }
789
790    // 删除
791    del(keyword) {
792      if (!keyword) return
793
794      let history = this.getHistory()
795
796      // 删除
797      history = history.filter(k => k !== keyword)
798
799      localStorage.setItem(this.key, JSON.stringify(history))
800      this.show(history)
801    }
802
803    // 清空
804    clear() {
805      localStorage.removeItem(this.key)
806      this.show([])
807    }
808  }
809
810  // 初始化
811  document.addEventListener(
812    "DOMContentLoaded",
813    function () {
814      const landingKey = "firstNonSearchUrl"
815
816      if (!isSearchPage()) {
817        sessionStorage.setItem(landingKey, window.location.href)
818      }
819
820      doc.addEventListener(
821        "click",
822        function (event) {
823          const button = event.target.closest(".input-page-search-btn, .input-mobile-search-btn")
824          if (!button) return
825          event.preventDefault()
826          event.stopImmediatePropagation()
827          const inputId = button.classList.contains("input-mobile-search-btn")
828            ? "input-mobile-control-key"
829            : "input-page-control-key"
830          const input = doc.getElementById(inputId)
831          submitSearch(parseKeyword(input ? input.value : "", new DOMParser()))
832        },
833        true
834      )
835
836      doc.addEventListener(
837        "keydown",
838        function (event) {
839          if (event.key !== "Enter") return
840          if (
841            event.target &&
842            (event.target.id === "input-page-control-key" || event.target.id === "input-mobile-control-key")
843          ) {
844            event.preventDefault()
845            event.stopImmediatePropagation()
846            submitSearch(parseKeyword(event.target.value, new DOMParser()))
847          }
848        },
849        true
850      )
851
852      win["$NavSearch"] = new NavSearch(
853        "/search-page-data.php",
854        "/action/suggest",
855        500,
856        0 // 搜索接口
857      )
858      win["$SortList"] = new SortList("div#archive", "/action/search_by")
859      win["$HistoryRecord"] = new HistoryRecord()
860      win["$NavSearch"].init()
861      initSearchAdLazyLoad()
862    },
863    false
864  )
865})(document, window, window.layer || { load: function () {} }, window.hotRankList || [], window.keyword || "")

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.