PageSourceSearch

https://www.htyxzle.cc/usr/themes/Mirages/js/override-2026.js?v=e4c5d12051bc452d

js htyxzle.cc collected 2026-09-26 05:36:11 UTC 23,662 bytes, 578 lines download raw bytes

1/* ============================================================
2 * 91爆料 2026 视觉优化覆写脚本
3 * 职责:
4 *   1. 给"热搜"帖子注入右上角火焰角标
5 *   2. 给广告帖子(外链)注入右上角"广告"小角标
6 *   3. 给分类页 body 增加 is-category-page 类,便于 CSS 控制
7 *   4. H5 卡片式导航的开关/遮罩关闭交互
8 * 依赖:jQuery 2.2.4(已全局可用)
9 * ============================================================ */
10(function ($) {
11  'use strict';
12
13  // 当前路径是否为分类页(排除 tag / search)
14  function isCategoryPage() {
15    var p = window.location.pathname || '';
16    return /^\/category\//.test(p);
17  }
18
19  function isSearchPage() {
20    var p = window.location.pathname || '';
21    var q = window.location.search || '';
22    return /^\/search\//.test(p) || /(?:\?|&)s=/.test(q);
23  }
24
25  // 只有真正跨域的 HTTP(S) 链接才可作为广告兜底;站内文章/页面、锚点和
26  // javascript/mailto/tel 等非网页协议都不能仅凭 href 被误标为广告。
27  function isExternalHttpLink(href) {
28    if (!href) return false;
29    try {
30      var url = new URL(href, window.location.href);
31      return (url.protocol === 'http:' || url.protocol === 'https:') &&
32        url.origin !== window.location.origin;
33    } catch (e) {
34      return false;
35    }
36  }
37
38  function badgeMarkup(type) {
39    if (type === 'hot') {
40      return '<span class="corner-badge corner-badge--hot" aria-label="热搜"></span>';
41    }
42    return '<span class="corner-badge corner-badge--ad" aria-label="广告"><span class="corner-badge__text">广告</span></span>';
43  }
44
45  // 注入角标到 .post-card 内
46  function injectCornerBadges() {
47    $('#index article .post-card, #archive article .post-card').each(function () {
48      var $card = $(this);
49      if ($card.data('badged')) return;
50
51      // 广告角标:显式广告卡,或真正跨域的 HTTP(S) 外链卡。
52      var $a = $card.closest('a');
53      var href = $a.attr('href') || '';
54      var isAd =
55        !isSearchPage() &&
56        ($card.hasClass('post-card-ads') ||
57          $card.find('.post-card-ads').length > 0 ||
58          $card.closest('article').hasClass('post-card-ads-article') ||
59          isExternalHttpLink(href));
60      if (isAd) {
61        // 广告披露优先于热门状态;同一角落只保留一个角标,避免视觉重叠。
62        $card.children('.corner-badge').remove();
63        $card.append(badgeMarkup('ad'));
64      } else if (!$card.children('.corner-badge').length) {
65        // 热门角标:识别原斜飘带文案。
66        var $hotWrap = $card.find('.post-card-title .wrap');
67        if ($hotWrap.length && /热搜|HOT/i.test($hotWrap.text())) {
68          $card.append(badgeMarkup('hot'));
69        }
70      }
71
72      $card.data('badged', true);
73    });
74  }
75
76  function normalizePath(path) {
77    try {
78      path = new URL(path || '/', window.location.href).pathname || '/';
79    } catch (e) {
80      path = path || '/';
81      path = path.split('#')[0].split('?')[0] || '/';
82    }
83    if (path.length > 1 && path.charAt(path.length - 1) !== '/') {
84      path += '/';
85    }
86    return path;
87  }
88
89  function escapeHtml(value) {
90    return String(value == null ? '' : value).replace(/[&<>"']/g, function (character) {
91      return {
92        '&': '&amp;',
93        '<': '&lt;',
94        '>': '&gt;',
95        '"': '&quot;',
96        "'": '&#39;'
97      }[character];
98    });
99  }
100
101  // 分类与抽屉链接均来自站内导航数据。客户端兜底重建时再次限制为同源
102  // HTTP(S),避免后台异常配置进入 href/style 上下文。
103  function safeLocalUrl(value, fallback) {
104    try {
105      var url = new URL(value || '', window.location.href);
106      if ((url.protocol === 'http:' || url.protocol === 'https:') && url.origin === window.location.origin) {
107        return url.pathname + url.search + url.hash;
108      }
109    } catch (e) {
110      // 使用下方安全兜底。
111    }
112    return typeof fallback === 'string' ? fallback : '/';
113  }
114
115  function markH5NavTabActive() {
116    var currentPath = normalizePath(window.location.pathname);
117    var $tabs = $('.h5-category-tabs .list > li');
118    if (!$tabs.length) return;
119
120    $tabs.removeClass('active').find('a').removeAttr('aria-current');
121    var $active = null;
122    $tabs.each(function () {
123      var href = normalizePath($(this).find('a').attr('href'));
124      if (href === '/' && currentPath === '/') {
125        $active = $(this);
126        return false;
127      }
128      if (href !== '/' && (currentPath === href || currentPath.indexOf(href) === 0)) {
129        $active = $(this);
130        return false;
131      }
132    });
133    if ($active && $active.length) {
134      $active.addClass('active');
135      $active.find('a').attr('aria-current', 'page');
136      var list = $active.closest('.list').get(0);
137      if (list && typeof list.scrollTo === 'function') {
138        var tab = $active.get(0);
139        var offset = tab.offsetLeft - (list.clientWidth - tab.clientWidth) / 2;
140        list.scrollTo({ left: Math.max(0, offset), behavior: 'smooth' });
141      }
142    }
143  }
144
145  function isH5Viewport() {
146    if (window.matchMedia) {
147      return window.matchMedia('(max-width: 767px)').matches;
148    }
149    return window.innerWidth <= 767;
150  }
151
152  // 分类描述在 H5 默认单行省略;完整文本始终保留在 DOM 中。
153  function setupCategoryDescription() {
154    $('[data-category-description]').each(function () {
155      var $root = $(this);
156      var $text = $root.find('.category-description__text').first();
157      var $toggle = $root.find('.category-description__toggle').first();
158      var $titleToggle = $root.closest('.container').find('.category-description__title-toggle').first();
159      var textNode = $text.get(0);
160      if (!textNode || !$toggle.length) return;
161
162      var wasExpanded = $root.hasClass('is-expanded');
163      $root.removeClass('has-overflow is-expanded').addClass('is-measuring');
164      $toggle.prop('hidden', false).attr('aria-expanded', 'false');
165      $toggle.find('.category-description__toggle-label').text('展开全文');
166      $toggle.find('.category-description__toggle-icon').text('⌄');
167      $titleToggle.prop('hidden', true).attr('aria-expanded', 'false')
168        .off('click.categoryDescription');
169
170      var hasOverflow = isH5Viewport() && textNode.scrollWidth > textNode.clientWidth + 1;
171      $root.removeClass('is-measuring').toggleClass('has-overflow', hasOverflow);
172
173      function setExpanded(expanded) {
174        var useTitleToggle = expanded && $titleToggle.length > 0;
175        $root.toggleClass('is-expanded', expanded);
176        $toggle.prop('hidden', !hasOverflow || useTitleToggle).attr('aria-expanded', expanded ? 'true' : 'false');
177        $toggle.find('.category-description__toggle-label').text(expanded ? '收起' : '展开全文');
178        $toggle.find('.category-description__toggle-icon').text(expanded ? '⌃' : '⌄');
179        $titleToggle.prop('hidden', !hasOverflow || !expanded).attr('aria-expanded', expanded ? 'true' : 'false');
180      }
181
182      setExpanded(wasExpanded && hasOverflow);
183
184      $toggle.off('click.categoryDescription').on('click.categoryDescription', function () {
185        setExpanded(!$root.hasClass('is-expanded'));
186      });
187      $titleToggle.off('click.categoryDescription').on('click.categoryDescription', function () {
188        setExpanded(false);
189      });
190    });
191  }
192
193  var categoryDescriptionResizeTimer = null;
194  $(window).off('resize.categoryDescription').on('resize.categoryDescription', function () {
195    clearTimeout(categoryDescriptionResizeTimer);
196    categoryDescriptionResizeTimer = setTimeout(setupCategoryDescription, 120);
197  });
198
199  function readSiteNavPayload() {
200    var el = document.getElementById('site-nav-data');
201    if (!el) return null;
202    try {
203      return JSON.parse(el.textContent || '');
204    } catch (e) {
205      return null;
206    }
207  }
208
209  function getNavCardCategories() {
210    var payload = readSiteNavPayload();
211    if (!payload) return [];
212    var list = [];
213    if (payload.home) list.push(payload.home);
214    if (payload.categories && payload.categories.length) {
215      list = list.concat(payload.categories);
216    }
217    return list.map(function (item) {
218      return {
219        name: item.label || '',
220        href: item.href || '/',
221        img: item.img || ''
222      };
223    });
224  }
225
226  function getNavCardOtherLinks() {
227    var payload = readSiteNavPayload();
228    if (!payload || !payload.other) return [];
229    return payload.other.map(function (item) {
230      return {
231        name: item.label || '',
232        href: item.href || '/',
233        // primary 是 SiteNav::getOtherLinks() 新增的键,对应原型里置顶高亮的三项。
234        primary: !!item.primary
235      };
236    });
237  }
238
239  // 关闭侧边栏(与 mirages.main 的 display-nav 逻辑一致)
240  function closeSidebar() {
241    // 抽屉 DOM 一直在,开合只是加减 #wrap.display-nav,过滤状态写在 DOM 上。
242    // 关闭时退回默认页签并清掉搜索词,下次打开才是和首屏一致的干净状态。
243    selectNavCardsTab($('#site-navigation.nav-cards'), 'category');
244    $('#wrap').removeClass('display-nav scale-up hide-menu-tree');
245    $('body').removeClass('display-nav');
246    $('#footer').removeClass('display-nav');
247    $('#wrap').find('#body').off('click.navcards');
248  }
249
250  // 服务端已输出 nav-cards 时,按当前 URL 高亮对应分类
251  function markNavCardActive() {
252    var currentPath = normalizePath(window.location.pathname);
253    var $items = $('#site-navigation.nav-cards .nav-cards-grid--category > li');
254    if (!$items.length) return;
255
256    $items.removeClass('is-active').find('a').removeAttr('aria-current');
257    $items.each(function () {
258      var href = normalizePath($(this).find('a').attr('href'));
259      if (href === currentPath || (href !== '/' && currentPath.indexOf(href) === 0)) {
260        $(this).addClass('is-active').find('a').attr('aria-current', 'page');
261        return false;
262      }
263    });
264  }
265
266  // 抽屉两个页签各自的搜索框提示语(与 component/nav_cards.php 一致)
267  var NAV_CARDS_PLACEHOLDER = {
268    category: '搜索内容分类...',
269    other: '搜索联系入口...'
270  };
271
272  function activeNavCardsTab($sidebar) {
273    var $tab = $sidebar.find('.nav-cards-tab[aria-selected="true"]').first();
274    var name = $tab.length ? String($tab.attr('data-nav-cards-tab') || '') : '';
275    return name === 'other' ? 'other' : 'category';
276  }
277
278  // 实时过滤:只作用于当前页签的列表,匹配可见文案的子串,不区分大小写;
279  // 关键词为空时恒真即全部显示,一条都不剩时显示该面板的空态文案。
280  function filterNavCards($sidebar) {
281    var $panel = $sidebar.find('.nav-cards-panel[data-nav-cards-panel="' + activeNavCardsTab($sidebar) + '"]');
282    if (!$panel.length) return;
283
284    var term = $.trim(String($sidebar.find('[data-nav-cards-search]').val() || '')).toLowerCase();
285    var visible = 0;
286    $panel.find('.nav-cards-grid > li').each(function () {
287      var name = String($(this).attr('data-nav-cards-name') || '').toLowerCase();
288      var match = name.indexOf(term) !== -1;
289      $(this).prop('hidden', !match);
290      if (match) visible += 1;
291    });
292    $panel.find('[data-nav-cards-empty]').toggleClass('is-visible', visible === 0);
293  }
294
295  // 切页签时清空搜索并恢复全部条目,两个面板都要复位
296  function resetNavCardsFilter($sidebar) {
297    $sidebar.find('[data-nav-cards-search]').val('');
298    $sidebar.find('.nav-cards-grid > li').prop('hidden', false);
299    $sidebar.find('[data-nav-cards-empty]').removeClass('is-visible');
300  }
301
302  function selectNavCardsTab($sidebar, name) {
303    var target = name === 'other' ? 'other' : 'category';
304
305    $sidebar.find('.nav-cards-tab').each(function () {
306      var selected = String($(this).attr('data-nav-cards-tab') || '') === target;
307      $(this).attr('aria-selected', selected ? 'true' : 'false').toggleClass('is-active', selected);
308    });
309
310    $sidebar.find('.nav-cards-panel').each(function () {
311      var current = String($(this).attr('data-nav-cards-panel') || '') === target;
312      $(this).prop('hidden', !current);
313      if (current) this.scrollTop = 0;
314    });
315
316    resetNavCardsFilter($sidebar);
317    $sidebar.find('[data-nav-cards-search]').attr('placeholder', NAV_CARDS_PLACEHOLDER[target]);
318  }
319
320  // 绑定关闭按钮、遮罩关闭、Esc 关闭,以及页签切换与实时过滤
321  // (服务端/客户端渲染均需执行)
322  function bindNavCardsEvents($sidebar) {
323    if (!$sidebar.length) return;
324
325    $sidebar.off('click.navcardsClose', '.nav-cards-close');
326    $sidebar.on('click.navcardsClose', '.nav-cards-close', function (e) {
327      e.preventDefault();
328      e.stopPropagation();
329      closeSidebar();
330    });
331
332    // 遮罩是 #body 的伪元素,点击落在 #body 上,沿用这条委托。
333    $(document).off('click.navcardsBackdrop', '#wrap.display-nav #body');
334    $(document).on('click.navcardsBackdrop', '#wrap.display-nav #body', function () {
335      closeSidebar();
336    });
337
338    $(document).off('keydown.navcardsEsc');
339    $(document).on('keydown.navcardsEsc', function (e) {
340      if (e.key !== 'Escape' && e.key !== 'Esc' && e.keyCode !== 27) return;
341      if ($('#wrap').hasClass('display-nav')) closeSidebar();
342    });
343
344    $sidebar.off('click.navcardsTab', '.nav-cards-tab');
345    $sidebar.on('click.navcardsTab', '.nav-cards-tab', function (e) {
346      e.preventDefault();
347      selectNavCardsTab($sidebar, String($(this).attr('data-nav-cards-tab') || ''));
348    });
349
350    $sidebar.off('input.navcardsFilter', '[data-nav-cards-search]');
351    $sidebar.on('input.navcardsFilter', '[data-nav-cards-search]', function () {
352      filterNavCards($sidebar);
353    });
354
355    // 回车或点搜索图标仍然提交到站内搜索结果页(form action="/" + name="s");
356    // 关键词为空时不跳转,留在抽屉里,避免把用户甩到首页。
357    $sidebar.off('submit.navcardsSearch', '.nav-cards-search form');
358    $sidebar.on('submit.navcardsSearch', '.nav-cards-search form', function (e) {
359      var keyword = $.trim(String($(this).find('[data-nav-cards-search]').val() || ''));
360      if (keyword === '') {
361        e.preventDefault();
362        return;
363      }
364      closeSidebar();
365    });
366  }
367
368  // 渲染卡片导航 HTML(替换旧的 #menu-menu-1 内容)
369  function renderCardNav() {
370    var $sidebar = $('#site-navigation.sidebar');
371    if (!$sidebar.length) return;
372
373    // 已在 PHP 输出 nav-cards 时:只补交互与高亮,不覆盖 DOM
374    if ($sidebar.hasClass('nav-cards') && $sidebar.find('.nav-cards-close').length) {
375      markNavCardActive();
376      // PJAX 换页后抽屉 DOM 不重传,上一页留下的搜索词会把列表继续过滤掉,这里复位。
377      resetNavCardsFilter($sidebar);
378      bindNavCardsEvents($sidebar);
379      return;
380    }
381
382    if ($sidebar.hasClass('nav-cards')) return;
383
384    var currentPath = normalizePath(window.location.pathname);
385    var categoryCards = getNavCardCategories();
386    var otherCards = getNavCardOtherLinks();
387    var brandLogoUrl = String($sidebar.attr('data-brand-logo-url') || '/usr/themes/Mirages/images/logo.png');
388    if (!categoryCards.length) return;
389
390    var catHtml = categoryCards.map(function (c) {
391      var href = safeLocalUrl(c.href, '/');
392      var imageUrl = safeLocalUrl(c.img, '');
393      var active = normalizePath(href) === currentPath ? ' class="is-active"' : '';
394      var ariaCurrent = active ? ' aria-current="page"' : '';
395      var bg = imageUrl ? ' style="background-image:url(&quot;' + escapeHtml(imageUrl) + '&quot;)"' : '';
396      return (
397        '<li' + active + ' data-nav-cards-name="' + escapeHtml(c.name) + '">' +
398        '<a href="' + escapeHtml(href) + '"' + ariaCurrent + bg + '><span>' + escapeHtml(c.name) + '</span></a>' +
399        '</li>'
400      );
401    }).join('');
402
403    var otherHtml = otherCards.map(function (c) {
404      var href = safeLocalUrl(c.href, '/');
405      var primary = c.primary ? ' class="is-primary"' : '';
406      return (
407        '<li' + primary + ' data-nav-cards-name="' + escapeHtml(c.name) + '">' +
408        '<a href="' + escapeHtml(href) + '"><span>' + escapeHtml(c.name) + '</span></a>' +
409        '</li>'
410      );
411    }).join('');
412
413    var $nav = $sidebar.find('#nav');
414    // 结构必须与 component/nav_cards.php 保持同构:这段只服务于服务端还没输出
415    // nav-cards 的旧缓存页,两边背离会让旧页渲染出上一版抽屉。
416    var html =
417      '<div class="nav-cards-header">' +
418      '  <a href="/"><img src="' + escapeHtml(brandLogoUrl) + '" alt="91爆料" /></a>' +
419      '  <button type="button" class="nav-cards-close" aria-label="关闭">✕</button>' +
420      '</div>' +
421      '<div class="nav-cards-search">' +
422      '  <form action="/" role="search">' +
423      '    <input type="text" name="s" placeholder="' + NAV_CARDS_PLACEHOLDER.category + '" autocomplete="off" aria-label="搜索" data-nav-cards-search />' +
424      '    <button type="submit" class="nav-cards-search-icon" aria-label="提交搜索"><i class="fa fa-search" aria-hidden="true"></i></button>' +
425      '  </form>' +
426      '</div>' +
427      '<div class="nav-cards-tablist" role="tablist" aria-label="导航分组">' +
428      '  <button type="button" class="nav-cards-tab is-active" role="tab" id="nav-cards-tab-category" aria-selected="true" aria-controls="nav-cards-panel-category" data-nav-cards-tab="category">内容分类</button>' +
429      '  <button type="button" class="nav-cards-tab" role="tab" id="nav-cards-tab-other" aria-selected="false" aria-controls="nav-cards-panel-other" data-nav-cards-tab="other">联系我们</button>' +
430      '</div>' +
431      '<div class="nav-cards-panels">' +
432      '  <section class="nav-cards-panel" id="nav-cards-panel-category" role="tabpanel" aria-labelledby="nav-cards-tab-category" data-nav-cards-panel="category">' +
433      '    <ul class="nav-cards-grid nav-cards-grid--category">' + catHtml + '</ul>' +
434      '    <p class="nav-cards-empty" data-nav-cards-empty>未找到匹配的内容分类</p>' +
435      '  </section>' +
436      '  <section class="nav-cards-panel" id="nav-cards-panel-other" role="tabpanel" aria-labelledby="nav-cards-tab-other" data-nav-cards-panel="other" hidden>' +
437      '    <ul class="nav-cards-grid nav-cards-grid--other">' + otherHtml + '</ul>' +
438      '    <p class="nav-cards-empty" data-nav-cards-empty>未找到匹配的联系入口</p>' +
439      '  </section>' +
440      '</div>';
441
442    $nav.html(html);
443    $sidebar.addClass('nav-cards');
444    bindNavCardsEvents($sidebar);
445  }
446
447  // 列表封面图禁用 Mirages zoom(去掉放大镜光标与点击放大/背景虚化)
448  function disablePostCardZoom() {
449    $('#index article .post-card img, #archive article .post-card img').each(function () {
450      $(this).attr('no-zoom', true).removeAttr('data-action');
451    });
452  }
453
454  var navbarMoreMenuBound = false;
455
456  // 旧主题的桌面导航在不同页面会出现 dropdown 插件缺失或监听冲突。
457  // 在捕获阶段接管“更多”按钮,直接维护 show/aria-expanded 状态。
458  function setupNavbarMoreMenu() {
459    if (navbarMoreMenuBound) return;
460    navbarMoreMenuBound = true;
461
462    function setOpen($dropdown, open) {
463      $dropdown.toggleClass('show', open);
464      $dropdown.children('.dropdown-menu').toggleClass('show', open);
465      $dropdown.children('[data-toggle="dropdown"]').attr('aria-expanded', open ? 'true' : 'false');
466    }
467
468    document.addEventListener('click', function (event) {
469      var $target = $(event.target);
470      var $toggle = $target.closest('.navbar-more-nav [data-toggle="dropdown"]');
471      if ($toggle.length) {
472        var $dropdown = $toggle.closest('.dropdown');
473        if (!$dropdown.children('.dropdown-menu').length) return;
474        event.preventDefault();
475        event.stopPropagation();
476        event.stopImmediatePropagation();
477        var shouldOpen = !$dropdown.hasClass('show');
478        $('#navbar .navbar-more-nav.dropdown').not($dropdown).each(function () {
479          setOpen($(this), false);
480        });
481        setOpen($dropdown, shouldOpen);
482        return;
483      }
484
485      if ($target.closest('#navbar .navbar-more-nav').length) return;
486      $('#navbar .navbar-more-nav.dropdown').each(function () {
487        setOpen($(this), false);
488      });
489    }, true);
490
491    document.addEventListener('keydown', function (event) {
492      if (event.key !== 'Escape') return;
493      $('#navbar .navbar-more-nav.dropdown.show').each(function () {
494        var $dropdown = $(this);
495        setOpen($dropdown, false);
496        $dropdown.children('[data-toggle="dropdown"]').trigger('focus');
497      });
498    }, true);
499  }
500
501  // iPad/中等屏幕顶部分类必须保持单行。只有发生真实溢出时才显示边缘
502  // 渐变,并随滚动位置切换左右遮罩;同时把导航实际高度交给 Banner。
503  function setupResponsiveNavbarOverflow() {
504    var $scroll = $('#navbar .navbar-primary-scroll').first();
505    var $navbar = $('#navbar').first();
506    var scroll = $scroll.get(0);
507    if (!scroll || !$navbar.length) return;
508
509    function syncOverflowState() {
510      var isTablet = window.matchMedia
511        ? window.matchMedia('(min-width: 768px) and (max-width: 1199.98px)').matches
512        : window.innerWidth >= 768 && window.innerWidth < 1200;
513      var isDesktopNavbar = window.matchMedia
514        ? window.matchMedia('(min-width: 768px)').matches
515        : window.innerWidth >= 768;
516      var hasOverflow = isTablet && scroll.scrollWidth > scroll.clientWidth + 1;
517      var maxScroll = Math.max(0, scroll.scrollWidth - scroll.clientWidth);
518      $scroll
519        .toggleClass('has-overflow', hasOverflow)
520        .toggleClass('is-at-start', hasOverflow && scroll.scrollLeft <= 1)
521        .toggleClass('is-at-end', hasOverflow && scroll.scrollLeft >= maxScroll - 1);
522
523      if (isDesktopNavbar) {
524        document.documentElement.style.setProperty(
525          '--visual-tablet-navbar-height',
526          Math.ceil($navbar.outerHeight()) + 'px'
527        );
528      } else {
529        document.documentElement.style.removeProperty('--visual-tablet-navbar-height');
530      }
531    }
532
533    $scroll.off('scroll.visualNavbarOverflow').on('scroll.visualNavbarOverflow', syncOverflowState);
534    $(window).off('resize.visualNavbarOverflow').on('resize.visualNavbarOverflow', syncOverflowState);
535    syncOverflowState();
536    (window.requestAnimationFrame || window.setTimeout)(syncOverflowState);
537  }
538
539  function refreshVisualPolish() {
540    disablePostCardZoom();
541    injectCornerBadges();
542    renderCardNav();
543    markH5NavTabActive();
544    setupCategoryDescription();
545    setupNavbarMoreMenu();
546    setupResponsiveNavbarOverflow();
547  }
548
549  function patchMiragesSetupPage() {
550    if (!window.Mirages) return;
551    if (typeof Mirages.setupPage === 'function' && !Mirages.setupPage.__noCardZoom) {
552      var origSetupPage = Mirages.setupPage;
553      Mirages.setupPage = function () {
554        origSetupPage.apply(this, arguments);
555        refreshVisualPolish();
556      };
557      Mirages.setupPage.__noCardZoom = true;
558    }
559    if (typeof Mirages.doPJAXCompleteAction === 'function' && !Mirages.doPJAXCompleteAction.__noCardZoom) {
560      var origPjaxComplete = Mirages.doPJAXCompleteAction;
561      Mirages.doPJAXCompleteAction = function () {
562        origPjaxComplete.apply(this, arguments);
563        refreshVisualPolish();
564      };
565      Mirages.doPJAXCompleteAction.__noCardZoom = true;
566    }
567  }
568
569  patchMiragesSetupPage();
570
571  $(function () {
572    if (isCategoryPage()) {
573      $('body').addClass('is-category-page');
574    }
575    refreshVisualPolish();
576    $('body').on('ajax-image:done', disablePostCardZoom);
577  });
578})(jQuery);

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.