PageSourceSearch

https://www.retailcrm.ru/t/v10532/images/toc.js

js retailcrm.ru collected 2026-10-03 19:44:45 UTC 3,184 bytes, 75 lines download raw bytes

1//=== Генерация оглавления (TOC) без списка, с якорями, смещением 80px и классом articles-link ===
2
3const tocContainer = document.querySelector(".toc-table");
4const articleBlocks = document.querySelectorAll(".article-content");
5let globalHeadingIndex = 0;
6
7function slugify(str) {
8  return String(str).toLowerCase().trim()
9    .replace(/[^\w\s-]/g, '')      // убрать запрещённые символы
10    .replace(/\s+/g, '-')          // пробелы -> тире
11    .replace(/-+/g, '-');          // повторяющиеся тире -> одно
12}
13
14function toSlugRU(str) {
15  const map = {
16    'а':'a','б':'b','в':'v','г':'g','д':'d','е':'e','ё':'yo','ж':'zh','з':'z',
17    'и':'i','й':'j','к':'k','л':'l','м':'m','н':'n','о':'o','п':'p','р':'r',
18    'с':'s','т':'t','у':'u','ф':'f','х':'h','ц':'ts','ч':'ch','ш':'sh','щ':'sch',
19    'ъ':'','ы':'y','ь':'','э':'e','ю':'yu','я':'ya'
20  };
21  // 1) приводим к строке и к нижнему регистру
22  let s = String(str).trim().toLowerCase();
23  // 2) транслитерация: заменяем каждую букву из map, остальное оставляем (латиница и цифры пройдут)
24  s = s.split('').map(ch => map[ch] !== undefined ? map[ch] : ch).join('');
25  // 3) заменяем любые небуквенно-цифровые символы (кроме дефиса) на дефис
26  s = s.replace(/[^a-z0-9-]+/g, '-');
27  // 4) убираем повторяющиеся дефисы и обрезаем крайние дефисы
28  s = s.replace(/-+/g, '-').replace(/^-|-$/g, '');
29  return s;
30}
31
32function createTOC() {
33  if (!tocContainer) return;
34
35  articleBlocks.forEach((block, blockIndex) => {
36    const headings = block.querySelectorAll("h2");
37
38    headings.forEach((heading) => {
39      const title = heading.textContent.trim();
40      const titleSlug = toSlugRU(title);
41      
42      const anchorId = `toc-${blockIndex}-${globalHeadingIndex}-${titleSlug}`;
43      
44
45      // устанавливаем id у заголовка
46      heading.setAttribute("id", anchorId);
47
48      // создаём ссылку
49      const a = document.createElement("a");
50      a.setAttribute("href", `#${anchorId}`);
51      a.textContent = title;
52      a.classList.add("articles-link"); // ✅ только один нужный класс
53
54      // плавная прокрутка со смещением 80px
55      a.addEventListener("click", (e) => {
56        e.preventDefault();
57        const target = document.getElementById(anchorId);
58        if (target) {
59          const yOffset = -120; // смещение вверх
60          const y = target.getBoundingClientRect().top + window.scrollY + yOffset;
61          window.scrollTo({ top: y, behavior: "smooth" });
62          history.replaceState(null, "", `#${anchorId}`);
63        }
64      });
65
66      tocContainer.appendChild(a);
67      globalHeadingIndex++;
68    });
69  });
70}
71
72// Запуск
73if (tocContainer && articleBlocks.length > 0) {
74  createTOC();
75}

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.