Last modified by wiki admin on 2026/08/26 01:04

From version 5.1
edited by wiki admin
on 2026/08/24 22:13
Change comment: There is no comment for this version
To version 1.1
edited by wiki admin
on 2026/08/24 21:04
Change comment: There is no comment for this version

Summary

Details

Page properties
Content
... ... @@ -1,1 +1,1 @@
1 -Article accordion. Edit the object, not this text.
1 +Article accordion for the customer-facing design. Edit the object, not this text.
XWiki.JavaScriptExtension[0]
Code
... ... @@ -1,135 +1,0 @@
1 -/* ===========================================================================
2 - Alder Support Center - article accordion
3 - Goes in an XWiki.JavaScriptExtension object on AlderTheme.Scripts (alder wiki).
4 -
5 - Turns each top-level H2 inside #xwikicontent into a collapsible section, so a
6 - long omnibus article becomes a short list of section titles. No article needs
7 - editing: the sections come from headings the content already has.
8 -
9 - Deliberate behaviours, all reversible by disabling this object:
10 - * Sections open independently. Opening one does not close another.
11 - * The first section starts open, so the page never looks empty.
12 - * Fewer than two H2s: nothing happens, the article renders normally.
13 - * Edit/preview modes are skipped, or authors would be editing generated
14 - markup.
15 - * A link to a heading inside a collapsed section opens that section and
16 - scrolls to it, including on first load and on later hash changes.
17 - =========================================================================== */
18 -(function () {
19 - 'use strict';
20 -
21 - var MIN_SECTIONS = 2;
22 -
23 - function ready(fn) {
24 - if (document.readyState === 'loading') {
25 - document.addEventListener('DOMContentLoaded', fn);
26 - } else {
27 - fn();
28 - }
29 - }
30 -
31 - function chevron() {
32 - var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
33 - svg.setAttribute('class', 'alder-chev');
34 - svg.setAttribute('viewBox', '0 0 24 24');
35 - var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
36 - path.setAttribute('d', 'M6 9l6 6 6-6');
37 - svg.appendChild(path);
38 - return svg;
39 - }
40 -
41 - function build() {
42 - var body = document.body;
43 - if (!body || body.className.indexOf('viewbody') === -1) {
44 - return; // edit, preview, or anything that is not a rendered page
45 - }
46 - var content = document.getElementById('xwikicontent');
47 - if (!content) { return; }
48 -
49 - // Only top-level headings. An h2 nested inside a table or a macro box is
50 - // part of that structure and must not be torn out of it.
51 - var headings = [];
52 - for (var i = 0; i < content.children.length; i++) {
53 - if (content.children[i].tagName === 'H2') { headings.push(content.children[i]); }
54 - }
55 - if (headings.length < MIN_SECTIONS) { return; }
56 -
57 - var made = [];
58 - headings.forEach(function (h2, index) {
59 - var details = document.createElement('details');
60 - details.className = 'alder-sec';
61 - if (index === 0) { details.open = true; }
62 -
63 - var summary = document.createElement('summary');
64 - var title = document.createElement('span');
65 - title.className = 'alder-sec-title';
66 - title.textContent = (h2.textContent || '').trim();
67 - summary.appendChild(title);
68 - summary.appendChild(chevron());
69 - details.appendChild(summary);
70 -
71 - var wrap = document.createElement('div');
72 - wrap.className = 'alder-sec-body';
73 - details.appendChild(wrap);
74 -
75 - // Keep the heading's id on the details element so existing anchors and
76 - // the table-of-contents macro still resolve to something.
77 - if (h2.id) { details.id = h2.id; h2.removeAttribute('id'); }
78 -
79 - content.insertBefore(details, h2);
80 -
81 - // Move the heading and everything up to the next h2 into the body.
82 - var node = h2;
83 - while (node && !(node !== h2 && node.tagName === 'H2')) {
84 - var next = node.nextSibling;
85 - wrap.appendChild(node);
86 - node = next;
87 - if (node && node.nodeType === 1 && node.tagName === 'H2') { break; }
88 - }
89 - made.push(details);
90 - });
91 -
92 - if (!made.length) { return; }
93 -
94 - var tools = document.createElement('div');
95 - tools.className = 'alder-tools';
96 - tools.appendChild(button('Expand all', true, made));
97 - tools.appendChild(button('Collapse all', false, made));
98 - content.insertBefore(tools, made[0]);
99 -
100 - openFromHash();
101 - window.addEventListener('hashchange', openFromHash);
102 - }
103 -
104 - function button(label, open, sections) {
105 - var b = document.createElement('button');
106 - b.type = 'button';
107 - b.textContent = label;
108 - b.addEventListener('click', function () {
109 - sections.forEach(function (d) { d.open = open; });
110 - });
111 - return b;
112 - }
113 -
114 - function openFromHash() {
115 - var hash = window.location.hash;
116 - if (!hash || hash.length < 2) { return; }
117 - var id = hash.slice(1);
118 - var target = null;
119 - try {
120 - target = document.getElementById(id);
121 - } catch (e) {
122 - return;
123 - }
124 - if (!target) { return; }
125 - // Open the target itself if it is a section, plus any collapsed ancestor.
126 - var node = target;
127 - while (node && node !== document.body) {
128 - if (node.tagName === 'DETAILS') { node.open = true; }
129 - node = node.parentNode;
130 - }
131 - if (target.scrollIntoView) { target.scrollIntoView(); }
132 - }
133 -
134 - ready(build);
135 -})();
Name
... ... @@ -1,1 +1,0 @@
1 -Article accordion
Parse content
... ... @@ -1,1 +1,0 @@
1 -No
Use this extension
... ... @@ -1,1 +1,0 @@
1 -always