PageSourceSearch

https://55cine.com/js/page-pager.js

js 55cine.com collected 2026-10-02 19:14:22 UTC 4,948 bytes, 167 lines download raw bytes

1/**
2 * 공용 PC 페이지네이션 (now-playing-test 기준)
3 * 상단 .page-toolbar + .page-pager (이전 · 페이지 번호 · 다음)
4 */
5(function (global) {
6  "use strict";
7
8  var DESKTOP_MQ = window.matchMedia("(min-width: 900px)");
9
10  function isDesktop() {
11    return DESKTOP_MQ.matches;
12  }
13
14  function scrollToTop(scrollRootSelector) {
15    var scrollEl = scrollRootSelector
16      ? document.querySelector(scrollRootSelector)
17      : document.querySelector(".np-scroll, .mz-scroll, .se-right-inner");
18    if (scrollEl) {
19      scrollEl.scrollTo({ top: 0, behavior: "smooth" });
20    } else {
21      window.scrollTo({ top: 0, behavior: "smooth" });
22    }
23  }
24
25  var MAX_PAGE_BUTTONS = 10;
26
27  /**
28   * 페이지 번호 최대 10개 + 줄임표 (1·마지막 페이지는 유지)
29   * @returns {Array<{ type: 'page', page: number }|{ type: 'ellipsis' }>}
30   */
31  function buildPageItems(current, total, maxNumeric) {
32    maxNumeric = maxNumeric || MAX_PAGE_BUTTONS;
33    if (total <= maxNumeric) {
34      var all = [];
35      for (var i = 1; i <= total; i++) {
36        all.push({ type: "page", page: i });
37      }
38      return all;
39    }
40
41    var items = [{ type: "page", page: 1 }];
42    var innerMax = maxNumeric - 2;
43    var start = Math.max(2, current - Math.floor(innerMax / 2));
44    var end = start + innerMax - 1;
45
46    if (end >= total) {
47      end = total - 1;
48      start = Math.max(2, end - innerMax + 1);
49    }
50    if (start <= 2) {
51      start = 2;
52      end = Math.min(total - 1, start + innerMax - 1);
53    }
54
55    if (start > 2) items.push({ type: "ellipsis" });
56    for (var p = start; p <= end; p++) {
57      items.push({ type: "page", page: p });
58    }
59    if (end < total - 1) items.push({ type: "ellipsis" });
60    items.push({ type: "page", page: total });
61    return items;
62  }
63
64  /**
65   * @param {HTMLElement|null} navEl
66   * @param {{ page: number, totalPages: number, onChange: function(number), scrollOnChange?: boolean, scrollRootSelector?: string, maxPageButtons?: number }} options
67   */
68  function render(navEl, options) {
69    if (!navEl) return;
70
71    var page = Math.max(1, options.page || 1);
72    var totalPages = Math.max(1, options.totalPages || 1);
73    var onChange = options.onChange || function () {};
74    var scrollOnChange = options.scrollOnChange !== false;
75    var alwaysVisible = !!options.alwaysVisible;
76
77    navEl.innerHTML = "";
78
79    if (!isDesktop() || (!alwaysVisible && totalPages <= 1)) {
80      navEl.classList.remove("is-visible");
81      return;
82    }
83
84    navEl.classList.add("is-visible");
85
86    function go(targetPage) {
87      if (targetPage < 1 || targetPage > totalPages || targetPage === page) return;
88      onChange(targetPage);
89      if (scrollOnChange) scrollToTop(options.scrollRootSelector);
90    }
91
92    var prev = document.createElement("button");
93    prev.type = "button";
94    prev.textContent = "이전";
95    prev.disabled = page <= 1;
96    prev.addEventListener("click", function () {
97      go(page - 1);
98    });
99    navEl.appendChild(prev);
100
101    var maxButtons = options.maxPageButtons || MAX_PAGE_BUTTONS;
102    var pageItems = buildPageItems(page, totalPages, maxButtons);
103
104    pageItems.forEach(function (item) {
105      if (item.type === "ellipsis") {
106        var gap = document.createElement("span");
107        gap.className = "page-pager__ellipsis";
108        gap.setAttribute("aria-hidden", "true");
109        gap.textContent = "…";
110        navEl.appendChild(gap);
111        return;
112      }
113
114      (function (num) {
115        var btn = document.createElement("button");
116        btn.type = "button";
117        btn.textContent = String(num);
118        if (num === page) btn.setAttribute("aria-current", "page");
119        btn.addEventListener("click", function () {
120          go(num);
121        });
122        navEl.appendChild(btn);
123      })(item.page);
124    });
125
126    var next = document.createElement("button");
127    next.type = "button";
128    next.textContent = "다음";
129    next.disabled = page >= totalPages;
130    next.addEventListener("click", function () {
131      go(page + 1);
132    });
133    navEl.appendChild(next);
134  }
135
136  function updateVisibility(navEl, totalPages) {
137    if (!navEl) return;
138    if (!isDesktop() || totalPages <= 1) {
139      navEl.classList.remove("is-visible");
140      navEl.innerHTML = "";
141    }
142  }
143
144  function formatCount(total, page, totalPages, unit) {
145    unit = unit || "ê±´";
146    if (isDesktop() && totalPages > 1) {
147      return "총 " + total + unit + " · " + page + " / " + totalPages + " 페이지";
148    }
149    return "총 " + total + unit;
150  }
151
152  function formatMovies(total, page, totalPages) {
153    return formatCount(total, page, totalPages, "편");
154  }
155
156  global.TiPagePager = {
157    mq: DESKTOP_MQ,
158    isDesktop: isDesktop,
159    render: render,
160    buildPageItems: buildPageItems,
161    updateVisibility: updateVisibility,
162    scrollToTop: scrollToTop,
163    formatCount: formatCount,
164    formatMovies: formatMovies,
165    MAX_PAGE_BUTTONS: MAX_PAGE_BUTTONS
166  };
167})(window);

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.