PageSourceSearch

https://umnitsa.ru/mg-plugins//p128-magnit-delivery/js/list.js?rev=1777512122

js umnitsa.ru collected 2026-09-26 05:40:35 UTC 4,192 bytes, 134 lines download raw bytes

1/**
2 * list.js — рендер и фильтрация списка ПВЗ
3 *
4 * Экспортирует: PvzList
5 */
6
7const PvzList = (() => {
8  const DAY_MAP = { MON:'Пн', TUE:'Вт', WED:'Ср', THU:'Чт', FRI:'Пт', SAT:'Сб', SUN:'Вс' };
9  const DAYS_ORDER = ['MON','TUE','WED','THU','FRI','SAT','SUN'];
10
11  let _listEl   = null;
12  let _emptyEl  = null;
13  let _onSelect = null;
14  let _activeKey = null;
15
16  /**
17   * Привязать модуль к DOM-элементам.
18   * @param {HTMLElement} listEl   <ul> для элементов
19   * @param {HTMLElement} emptyEl  заглушка «ничего не найдено»
20   * @param {Function}    onSelect callback(key)
21   */
22  function init(listEl, emptyEl, onSelect) {
23    _listEl   = listEl;
24    _emptyEl  = emptyEl;
25    _onSelect = onSelect;
26    console.log('INIT listEl:', listEl);
27  }
28
29  /**
30   * Отрисовать список точек.
31   * @param {Array}  points    массив ПВЗ
32   * @param {string} activeKey выбранный ключ (или null)
33   */
34  function render(points, activeKey) {
35    if (!_listEl) {
36      console.error('PvzList not initialized');
37      return;
38    }
39    _activeKey = activeKey;
40    _listEl.innerHTML = '';
41
42    if (!points.length) {
43      _emptyEl.hidden = false;
44      return;
45    }
46    _emptyEl.hidden = true;
47
48    points.forEach(p => {
49      const li = document.createElement('li');
50      li.className = 'pvz-item' + (p.key === activeKey ? ' is-active' : '');
51      li.dataset.key = p.key;
52      li.innerHTML = _itemHTML(p);
53      li.addEventListener('click', () => _onSelect(p.key));
54      _listEl.appendChild(li);
55    });
56  }
57
58  /**
59   * Пометить элемент активным без полного перерендера.
60   * @param {string} key
61   */
62  function setActive(key) {
63    _activeKey = key;
64    _listEl.querySelectorAll('.pvz-item').forEach(el => {
65      el.classList.toggle('is-active', el.dataset.key === key);
66    });
67
68    // скроллим к элементу
69    const active = _listEl.querySelector('.pvz-item.is-active');
70    if (active) active.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
71  }
72
73  /**
74   * Фильтровать массив по строке поиска.
75   * @param {Array}  points
76   * @param {string} query
77   * @returns {Array}
78   */
79  function filter(points, query) {
80    const q = query.trim().toLowerCase();
81    if (!q) return points;
82    return points.filter(p =>
83      p.name.toLowerCase().includes(q) ||
84      p.address.toLowerCase().includes(q) ||
85      (p.city && p.city.toLowerCase().includes(q))
86    );
87  }
88
89  // --- приватные ---
90
91  function _itemHTML(p) {
92    return `
93      <div class="pvz-item__name">${_esc(p.name)}</div>
94      <div class="pvz-item__address">${_esc(p.address)}</div>
95      <div class="pvz-item__hours ${_isOpenNow(p.workHours) ? 'pvz-item__hours--open' : ''}">
96        ${_todayHours(p.workHours)}
97      </div>
98    `;
99  }
100
101  function _todayHours(workHours) {
102    if (!workHours || !workHours.length) return '';
103    const todayKey = DAYS_ORDER[new Date().getDay() === 0 ? 6 : new Date().getDay() - 1];
104    const today = workHours.find(h => h.day === todayKey);
105    if (!today) return 'Сегодня закрыто';
106    return `Сегодня: ${today.from}–${today.till || '...'}`;
107  }
108
109  function _isOpenNow(workHours) {
110    if (!workHours || !workHours.length) return false;
111    const now  = new Date();
112    const todayKey = DAYS_ORDER[now.getDay() === 0 ? 6 : now.getDay() - 1];
113    const today = workHours.find(h => h.day === todayKey);
114    if (!today || !today.till) return false;
115    const [fh, fm] = today.from.split(':').map(Number);
116    const [th, tm] = today.till.split(':').map(Number);
117    const cur = now.getHours() * 60 + now.getMinutes();
118    return cur >= fh * 60 + fm && cur < th * 60 + tm;
119  }
120
121  function _decode(str) {
122    try { return decodeURIComponent(String(str)); } catch { return String(str); }
123  }
124
125  function _esc(str) {
126    return String(str)
127      .replace(/&/g, '&amp;')
128      .replace(/</g, '&lt;')
129      .replace(/>/g, '&gt;')
130      .replace(/"/g, '&quot;');
131  }
132
133  return { init, render, setActive, filter };
134})();

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.