Changes for page Alder Support Center scripts
Last modified by wiki admin on 2026/08/26 01:04
From version 6.1
edited by wiki admin
on 2026/08/24 22:13
on 2026/08/24 22:13
Change comment:
There is no comment for this version
To version 8.1
edited by wiki admin
on 2026/08/24 22:49
on 2026/08/24 22:49
Change comment:
There is no comment for this version
Summary
-
Objects (1 modified, 0 added, 0 removed)
Details
- XWiki.JavaScriptExtension[0]
-
- Code
-
... ... @@ -56,49 +56,116 @@ 56 56 var content = document.getElementById('xwikicontent'); 57 57 if (!content) { return; } 58 58 59 - // Only top-level headings. An h2 nested inside a table or a macro box is 60 - // part of that structure and must not be torn out of it. 61 - var headings = []; 62 - for (var i = 0; i < content.children.length; i++) { 63 - if (content.children[i].tagName === 'H2') { headings.push(content.children[i]); } 59 + // XWiki renders each section as its own <div class="f-accordion-panel">, 60 + // with the section heading as the first child and everything else after it: 61 + // 62 + // <div class="f-accordion-panel" data-controller="accordion"> 63 + // <h2>Arm/Disarm</h2> <- section heading 64 + // <h1>Arm</h1><p>...</p> <- content, including Helpjuice's inverted 65 + // </div> h1 "subsections" 66 + // 67 + // So the section container already exists and we only need to make it 68 + // collapsible. Two earlier versions of this script tried to rebuild sections 69 + // by grouping sibling headings -- first from content.children (headings are 70 + // nested, so it found none), then by grouping headings that share a parent 71 + // (each heading has its OWN panel, so every group had one item and the 72 + // script bailed silently). Both looked fine on a hand-written preview page. 73 + var made = []; 74 + var panels = content.querySelectorAll('.f-accordion-panel'); 75 + 76 + var eligible = []; 77 + for (var p = 0; p < panels.length; p++) { 78 + var first = panels[p].firstElementChild; 79 + if (first && /^H[1-4]$/.test(first.tagName)) { 80 + eligible.push({ panel: panels[p], heading: first }); 81 + } 64 64 } 65 - if (headings.length < MIN_SECTIONS) { return; } 66 66 67 - var made = []; 68 - headings.forEach(function (h2, index) { 69 - var details = document.createElement('details'); 70 - details.className = 'alder-sec'; 71 - if (index === 0) { details.open = true; } 84 + if (eligible.length >= MIN_SECTIONS) { 85 + eligible.forEach(function (item, index) { 86 + var panel = item.panel; 87 + var heading = item.heading; 72 72 73 - var summary = document.createElement('summary'); 74 - var title = document.createElement('span'); 75 - title.className = 'alder-sec-title'; 76 - title.textContent = (h2.textContent || '').trim(); 77 - summary.appendChild(title); 78 - summary.appendChild(chevron()); 79 - details.appendChild(summary); 89 + var details = document.createElement('details'); 90 + details.className = 'alder-sec'; 91 + if (index === 0) { details.open = true; } 92 + if (heading.id) { details.id = heading.id; heading.removeAttribute('id'); } 80 80 81 - var wrap = document.createElement('div'); 82 - wrap.className = 'alder-sec-body'; 83 - details.appendChild(wrap); 94 + var summary = document.createElement('summary'); 95 + var title = document.createElement('span'); 96 + title.className = 'alder-sec-title'; 97 + title.textContent = (heading.textContent || '').trim(); 98 + summary.appendChild(title); 99 + summary.appendChild(chevron()); 100 + details.appendChild(summary); 84 84 85 - // Keep the heading's id on the details element so existing anchors and 86 - // the table-of-contents macro still resolve to something. 87 - if (h2.id) { details.id = h2.id; h2.removeAttribute('id'); } 102 + // The heading is now the summary, so it must not also appear inside. 103 + panel.removeChild(heading); 88 88 89 - content.insertBefore(details, h2); 105 + var wrap = document.createElement('div'); 106 + wrap.className = 'alder-sec-body'; 107 + while (panel.firstChild) { wrap.appendChild(panel.firstChild); } 108 + details.appendChild(wrap); 90 90 91 - // Move the heading and everything up to the next h2 into the body. 92 - var node = h2; 93 - while (node && !(node !== h2 && node.tagName === 'H2')) { 94 - var next = node.nextSibling; 95 - wrap.appendChild(node); 96 - node = next; 97 - if (node && node.nodeType === 1 && node.tagName === 'H2') { break; } 110 + // Keep the panel as the outer element: it carries XWiki's own 111 + // data-controller, and removing it could break behaviour we did not 112 + // write and cannot see. 113 + panel.appendChild(details); 114 + made.push(details); 115 + }); 116 + } else { 117 + // Fallback for content without those panels -- hand-written wiki markup, 118 + // and any XWiki version that renders sections differently. 119 + var found = content.querySelectorAll('h2'); 120 + if (found.length < MIN_SECTIONS) { return; } 121 + 122 + var byParent = []; 123 + for (var f = 0; f < found.length; f++) { 124 + var parent = found[f].parentNode; 125 + var slot = null; 126 + for (var b = 0; b < byParent.length; b++) { 127 + if (byParent[b].parent === parent) { slot = byParent[b]; break; } 128 + } 129 + if (!slot) { slot = { parent: parent, items: [] }; byParent.push(slot); } 130 + slot.items.push(found[f]); 98 98 } 99 - made.push(details); 100 - }); 132 + byParent.sort(function (a, b) { return b.items.length - a.items.length; }); 101 101 134 + var container = byParent[0].parent; 135 + var headings = byParent[0].items; 136 + if (headings.length < MIN_SECTIONS) { return; } 137 + 138 + headings.forEach(function (h2, index) { 139 + var details = document.createElement('details'); 140 + details.className = 'alder-sec'; 141 + if (index === 0) { details.open = true; } 142 + 143 + var summary = document.createElement('summary'); 144 + var title = document.createElement('span'); 145 + title.className = 'alder-sec-title'; 146 + title.textContent = (h2.textContent || '').trim(); 147 + summary.appendChild(title); 148 + summary.appendChild(chevron()); 149 + details.appendChild(summary); 150 + 151 + var wrap = document.createElement('div'); 152 + wrap.className = 'alder-sec-body'; 153 + details.appendChild(wrap); 154 + 155 + if (h2.id) { details.id = h2.id; h2.removeAttribute('id'); } 156 + container.insertBefore(details, h2); 157 + 158 + var node = h2; 159 + while (node && !(node !== h2 && node.tagName === 'H2')) { 160 + var next = node.nextSibling; 161 + wrap.appendChild(node); 162 + node = next; 163 + if (node && node.nodeType === 1 && node.tagName === 'H2') { break; } 164 + } 165 + made.push(details); 166 + }); 167 + } 168 + 102 102 if (!made.length) { return; } 103 103 104 104 var tools = document.createElement('div'); ... ... @@ -105,7 +105,7 @@ 105 105 tools.className = 'alder-tools'; 106 106 tools.appendChild(button('Expand all', true, made)); 107 107 tools.appendChild(button('Collapse all', false, made)); 108 - content.insertBefore(tools, made[0]);175 + made[0].parentNode.insertBefore(tools, made[0]); 109 109 110 110 openFromHash(); 111 111 window.addEventListener('hashchange', openFromHash);