|
| 1 | +(() => { |
| 2 | + const root = document.querySelector('article.content'); |
| 3 | + if (!root) return; |
| 4 | + |
| 5 | + const isHeading = el => el && el.nodeType === 1 && /^H[1-6]$/.test(el.tagName); |
| 6 | + |
| 7 | + // Récupère tous les titres h2..h6 dans l'ordre du document (live snapshot figé) |
| 8 | + const headings = Array.from(root.querySelectorAll('h2, h3, h4, h5, h6')); |
| 9 | + |
| 10 | + for (const h of headings) { |
| 11 | + // Idempotence : si ce titre est déjà le 1er enfant d'un .section-wrapper, on ne fait rien |
| 12 | + if (h.parentElement?.classList.contains('section-wrapper') && |
| 13 | + h.parentElement.firstElementChild === h) { |
| 14 | + continue; |
| 15 | + } |
| 16 | + |
| 17 | + const wrapper = document.createElement('div'); |
| 18 | + wrapper.className = 'section-wrapper'; |
| 19 | + // (optionnel) pour debug : |
| 20 | + wrapper.dataset.heading = h.tagName.toLowerCase(); |
| 21 | + if (h.id) wrapper.dataset.anchor = h.id; |
| 22 | + |
| 23 | + // Insérer le wrapper juste avant le titre |
| 24 | + h.parentNode.insertBefore(wrapper, h); |
| 25 | + |
| 26 | + // Déplacer le titre dans le wrapper |
| 27 | + wrapper.appendChild(h); |
| 28 | + |
| 29 | + // Puis déplacer tout ce qui suit IMMÉDIATEMENT jusqu'au prochain heading (quel que soit le niveau) |
| 30 | + // -> ainsi on n'englobe jamais les sous-titres |
| 31 | + let node = wrapper.nextSibling; // ancien "nextSibling" du h2, devenu celui du wrapper |
| 32 | + while (node) { |
| 33 | + const next = node.nextSibling; // mémoriser avant déplacement/arrêt |
| 34 | + |
| 35 | + // Si on tombe sur un titre (h1..h6), on s'arrête (le prochain wrapper le prendra en charge) |
| 36 | + if (node.nodeType === 1 && isHeading(node)) break; |
| 37 | + |
| 38 | + // Sinon, c'est du contenu d'intro : on le rapatrie dans ce wrapper |
| 39 | + wrapper.appendChild(node); |
| 40 | + |
| 41 | + node = next; |
| 42 | + } |
| 43 | + } |
| 44 | +})(); |
| 45 | + |
1 | 46 | (() => { |
2 | 47 | let contentHeaders= document.querySelectorAll("main h2[id]"); |
3 | 48 | if (!document.querySelector('html').classList.contains('homepage') && contentHeaders) { |
|
71 | 116 | const menuLinks = document.querySelectorAll('#onthispage a'); |
72 | 117 | const observer = new IntersectionObserver(entries => { |
73 | 118 | entries.forEach(entry => { |
74 | | - const id = entry.target.getAttribute("id"); |
| 119 | + const id = entry.target.getAttribute("data-anchor"); |
75 | 120 | const link = document.querySelector(`#onthispage a[href="#${id}"]`); |
76 | 121 |
|
77 | 122 | if (entry.isIntersecting) { |
|
80 | 125 | } |
81 | 126 | }); |
82 | 127 | }, { |
83 | | - rootMargin: "-50% 0px -50% 0px", // trigger when the section is centered in viewport |
| 128 | + root: null, |
| 129 | + rootMargin: "0px 0px -100% 0px", |
84 | 130 | threshold: 0 |
85 | 131 | }); |
86 | 132 |
|
87 | | - sections.forEach(section => observer.observe(section)); |
| 133 | + sections.forEach(section => observer.observe(section.parentElement)); |
88 | 134 | } |
89 | 135 |
|
90 | 136 | // generate code snippet copy/paste |
|
111 | 157 | notification.classList.remove('bg-black'); |
112 | 158 | }, 500); |
113 | 159 | } catch (err) { |
114 | | - console.error('Failed to copy: ', err); |
115 | 160 | notification.innerHTML = 'Copy failed!'; |
116 | 161 | notification.classList.add('bg-red-800'); |
117 | 162 | notification.classList.remove('hidden'); |
|
0 commit comments