PageSourceSearch

https://ses-media.jp/js/toc.js

js ses-media.jp collected 2026-10-04 19:28:44 UTC 3,306 bytes, 102 lines download raw bytes

1/**
2 * 記事目次自動生成スクリプト
3 */
4
5document.addEventListener('DOMContentLoaded', function() {
6    generateTableOfContents();
7});
8
9function generateTableOfContents() {
10    const articleContent = document.querySelector('.article-content');
11    if (!articleContent) return;
12
13    // H2, H3タグを取得
14    const headings = articleContent.querySelectorAll('h2, h3');
15    if (headings.length < 2) return; // 見出しが2つ未満なら目次を作らない
16
17    // 目次コンテナを作成
18    const tocContainer = document.createElement('div');
19    tocContainer.className = 'table-of-contents is-closed';
20
21    const tocTitle = document.createElement('div');
22    tocTitle.className = 'toc-title';
23    tocTitle.textContent = '目次';
24
25    tocTitle.addEventListener('click', () => {
26        tocContainer.classList.toggle('is-closed');
27    });
28
29    tocContainer.appendChild(tocTitle);
30
31    const tocList = document.createElement('ol');
32    tocList.className = 'toc-list';
33
34    let h2Index = 0;
35    let currentH2Item = null;
36
37    headings.forEach((heading, index) => {
38        const headingText = heading.textContent.trim();
39        const headingId = `heading-${index + 1}`;
40        heading.id = headingId;
41
42        const tocItem = document.createElement('li');
43        const tocLink = document.createElement('a');
44        tocLink.href = `#${headingId}`;
45
46        tocLink.addEventListener('click', function(e) {
47            e.preventDefault();
48            if (tocContainer.classList.contains('is-closed')) {
49                tocContainer.classList.remove('is-closed');
50            }
51            smoothScrollTo(heading);
52        });
53
54        if (heading.tagName === 'H2') {
55            h2Index++;
56            tocItem.className = 'toc-h2';
57
58            // H2のテキストを「1. 見出し」のように設定
59            tocLink.textContent = `${h2Index}. ${headingText}`;
60
61            tocItem.appendChild(tocLink);
62            tocList.appendChild(tocItem);
63            currentH2Item = tocItem;
64
65        } else if (heading.tagName === 'H3') {
66            tocItem.className = 'toc-h3';
67
68            // H3のテキストを「┗ 見出し」のように設定
69            tocLink.textContent = `${headingText}`;
70
71            tocItem.appendChild(tocLink);
72
73            if (currentH2Item) {
74                let h3List = currentH2Item.querySelector('ol');
75                if (!h3List) {
76                    h3List = document.createElement('ol');
77                    h3List.className = 'toc-h3-list';
78                    currentH2Item.appendChild(h3List);
79                }
80                h3List.appendChild(tocItem);
81            } else {
82                tocList.appendChild(tocItem);
83            }
84        }
85    });
86
87    tocContainer.appendChild(tocList);
88
89    // 最初の見出し(h2 or h3)の前に目次を挿入
90    const firstHeading = articleContent.querySelector('h2, h3');
91    if (firstHeading) {
92        firstHeading.parentNode.insertBefore(tocContainer, firstHeading);
93    }
94}
95
96function smoothScrollTo(element) {
97    const offsetTop = element.getBoundingClientRect().top + window.pageYOffset - 100;
98    window.scrollTo({
99        top: offsetTop,
100        behavior: 'smooth'
101    });
102}

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.