spec-up-t 1.2.4 → 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/compiled/body.js +11 -8
- package/assets/compiled/head.css +7 -4
- package/assets/css/add-bootstrap-classes-to-images.css +34 -0
- package/assets/css/collapse-definitions.css +41 -0
- package/assets/css/create-pdf.css +339 -0
- package/assets/css/horizontal-scroll-hint.css +6 -0
- package/assets/css/image-full-size.css +40 -0
- package/assets/css/index.css +5 -0
- package/assets/css/search.css +8 -8
- package/assets/css/terms-and-definitions.css +3 -3
- package/assets/js/add-bootstrap-classes-to-images.js +95 -0
- package/assets/js/collapse-definitions.js +259 -34
- package/assets/js/collapse-meta-info.js +37 -10
- package/assets/js/collapsibleMenu.js +0 -24
- package/assets/js/create-alphabet-index.js +11 -2
- package/assets/js/create-term-filter.js +47 -17
- package/assets/js/hide-show-utility-container.js +16 -0
- package/assets/js/horizontal-scroll-hint.js +2 -2
- package/assets/js/image-full-size.js +74 -0
- package/assets/js/insert-trefs.js +135 -49
- package/assets/js/search.js +46 -20
- package/{src → config}/asset-map.json +6 -0
- package/{src/config → config}/paths.js +2 -2
- package/gulpfile.js +1 -1
- package/index.js +5 -5
- package/package.json +1 -1
- package/src/README.md +3 -3
- package/src/collect-external-references.js +2 -2
- package/src/collectExternalReferences/fetchTermsFromIndex.1.js +340 -0
- package/src/collectExternalReferences/fetchTermsFromIndex.js +1 -1
- package/src/collectExternalReferences/processXTrefsData.js +1 -1
- package/src/create-pdf.js +330 -21
- package/src/create-term-index.js +126 -22
- package/src/health-check/tref-term-checker.js +1 -1
- package/src/health-check.js +1 -1
- package/src/init.js +1 -1
- package/src/insert-term-index.js +5 -5
- package/src/install-from-boilerplate/add-scripts-keys.js +3 -1
- package/src/install-from-boilerplate/boilerplate/gitignore +1 -1
- package/src/markdown-it-extensions.js +2 -2
- package/src/utils/fetch.js +14 -14
- package/assets/css/pdf-styles.css +0 -170
|
@@ -1,52 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Manages collapsible definition lists with visual state indicators.
|
|
3
|
+
* @author Kor Dwarshuis
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
* @description This module provides functionality to toggle the visibility
|
|
6
|
+
* of definition descriptions in a document with a smooth user experience.
|
|
7
|
+
* It creates interactive buttons with three toggle states and prevents
|
|
8
|
+
* UI jumping during transitions using fixed positioning and requestAnimationFrame.
|
|
9
|
+
* @requires insert-trefs.js - For the initializeOnTrefsInserted helper function
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Sets up collapsible definition lists with toggle buttons.
|
|
14
|
+
* Handles the creation of buttons, event listeners, and visibility states.
|
|
15
|
+
* This is the main initialization function that's called when the DOM is ready
|
|
16
|
+
* and all transcluded references have been inserted.
|
|
17
|
+
* @function
|
|
18
|
+
* @see initializeOnTrefsInserted - Helper function that ensures this runs at the right time
|
|
19
|
+
*/
|
|
1
20
|
function collapseDefinitions() {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Queries and categorizes definition list elements in the DOM.
|
|
23
|
+
* @function
|
|
24
|
+
* @returns {Object} Object containing categorized DOM element collections
|
|
25
|
+
* @returns {NodeList} returns.dds - All definition descriptions
|
|
26
|
+
* @returns {NodeList} returns.dts - All definition terms
|
|
27
|
+
* @returns {Array<Element>} returns.regularDds - Standard definition descriptions
|
|
28
|
+
* @returns {Array<Element>} returns.specialDds - Special definition descriptions (e.g., "See also", "Source")
|
|
29
|
+
*/
|
|
30
|
+
function queryElements() {
|
|
31
|
+
const dds = document.querySelectorAll('#content dl.terms-and-definitions-list > dd');
|
|
32
|
+
const dts = document.querySelectorAll('#content dl.terms-and-definitions-list > dt');
|
|
33
|
+
const regularDds = Array.from(dds).filter(dd => !isSpecialDefinition(dd.textContent.trim()));
|
|
34
|
+
const specialDds = Array.from(dds).filter(dd => isSpecialDefinition(dd.textContent.trim()));
|
|
35
|
+
|
|
36
|
+
return { dds, dts, regularDds, specialDds };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let { dds, dts, regularDds, specialDds } = queryElements();
|
|
40
|
+
const buttonTitleText = 'Change how much info is shown';
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Determines if a definition is a special type (e.g., a "See also" or "Source" note)
|
|
44
|
+
* @param {string} content - The content of the definition to check
|
|
45
|
+
* @returns {boolean} True if the content starts with a special prefix
|
|
46
|
+
*/
|
|
47
|
+
function isSpecialDefinition(content) {
|
|
48
|
+
const definitionHidePrefixes = [
|
|
49
|
+
"Source",
|
|
50
|
+
"See also",
|
|
51
|
+
"More in",
|
|
52
|
+
"Also see",
|
|
53
|
+
"See:",
|
|
54
|
+
"See also",
|
|
55
|
+
"See more",
|
|
56
|
+
"See more in",
|
|
57
|
+
"See more about",
|
|
58
|
+
"See more on",
|
|
59
|
+
"See more at",
|
|
60
|
+
"More:"
|
|
61
|
+
];
|
|
62
|
+
return definitionHidePrefixes.some(prefix => content.startsWith(prefix));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
specialDds.forEach(dd => {
|
|
66
|
+
dd.classList.add('terms-def-extra-info');
|
|
67
|
+
});
|
|
5
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Toggles the visibility state of definitions across the document.
|
|
71
|
+
* Cycles through three visibility states:
|
|
72
|
+
* - State 0: All definitions hidden
|
|
73
|
+
* - State 1: Only regular definitions visible
|
|
74
|
+
* - State 2: All definitions visible
|
|
75
|
+
*
|
|
76
|
+
* Updates UI indicators to reflect the current state.
|
|
77
|
+
* @function
|
|
78
|
+
*/
|
|
6
79
|
function toggleVisibility() {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
80
|
+
const buttons = document.querySelectorAll('.collapse-all-defs-button');
|
|
81
|
+
const currentState = parseInt(buttons[0].dataset.state || 0);
|
|
82
|
+
// Cycle through 3 states: 0 (all hidden), 1 (only regular visible), 2 (all visible)
|
|
83
|
+
const newState = (currentState + 1) % 3;
|
|
84
|
+
|
|
85
|
+
// Update state based on newState
|
|
86
|
+
switch (newState) {
|
|
87
|
+
case 0: // All definitions hidden
|
|
88
|
+
dds.forEach(dd => {
|
|
89
|
+
dd.classList.add('hidden');
|
|
90
|
+
dd.classList.remove('visible');
|
|
91
|
+
});
|
|
92
|
+
buttons.forEach(button => {
|
|
93
|
+
button.dataset.state = 0;
|
|
94
|
+
button.title = 'Show basic definitions';
|
|
95
|
+
// Update which state indicator is active
|
|
96
|
+
button.querySelectorAll('.state-indicator').forEach(indicator => {
|
|
97
|
+
if (parseInt(indicator.dataset.state) === 0) {
|
|
98
|
+
indicator.classList.add('active');
|
|
99
|
+
} else {
|
|
100
|
+
indicator.classList.remove('active');
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
document.querySelector('html').classList.add('defs-hidden');
|
|
105
|
+
break;
|
|
106
|
+
|
|
107
|
+
case 1: // Only regular definitions visible
|
|
108
|
+
regularDds.forEach(dd => {
|
|
109
|
+
dd.classList.remove('hidden');
|
|
110
|
+
dd.classList.add('visible');
|
|
111
|
+
});
|
|
112
|
+
specialDds.forEach(dd => {
|
|
113
|
+
dd.classList.add('hidden');
|
|
114
|
+
dd.classList.remove('visible');
|
|
115
|
+
});
|
|
116
|
+
buttons.forEach(button => {
|
|
117
|
+
button.dataset.state = 1;
|
|
118
|
+
button.title = 'Show all definitions';
|
|
119
|
+
// Update which state indicator is active
|
|
120
|
+
button.querySelectorAll('.state-indicator').forEach(indicator => {
|
|
121
|
+
if (parseInt(indicator.dataset.state) === 1) {
|
|
122
|
+
indicator.classList.add('active');
|
|
123
|
+
} else {
|
|
124
|
+
indicator.classList.remove('active');
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
document.querySelector('html').classList.remove('defs-hidden');
|
|
129
|
+
break;
|
|
130
|
+
|
|
131
|
+
case 2: // All definitions visible
|
|
132
|
+
dds.forEach(dd => {
|
|
133
|
+
dd.classList.remove('hidden');
|
|
134
|
+
dd.classList.add('visible');
|
|
135
|
+
});
|
|
136
|
+
specialDds.forEach(dd => {
|
|
137
|
+
dd.classList.add('terms-def-extra-info');
|
|
138
|
+
});
|
|
139
|
+
buttons.forEach(button => {
|
|
140
|
+
button.dataset.state = 2;
|
|
141
|
+
button.title = 'Hide all definitions';
|
|
142
|
+
// Update which state indicator is active
|
|
143
|
+
button.querySelectorAll('.state-indicator').forEach(indicator => {
|
|
144
|
+
if (parseInt(indicator.dataset.state) === 2) {
|
|
145
|
+
indicator.classList.add('active');
|
|
146
|
+
} else {
|
|
147
|
+
indicator.classList.remove('active');
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
document.querySelector('html').classList.remove('defs-hidden');
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Creates and appends toggle buttons to all definition terms.
|
|
158
|
+
* Each button contains state indicators for the three visibility states,
|
|
159
|
+
* and is initialized to show all definitions (state 2).
|
|
160
|
+
* @function
|
|
161
|
+
*/
|
|
162
|
+
function addButtons() {
|
|
163
|
+
dts.forEach(dt => {
|
|
164
|
+
// Check if button already exists to avoid duplicates
|
|
165
|
+
if (dt.querySelector('.collapse-all-defs-button')) {
|
|
166
|
+
return; // Skip if button already exists
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const button = document.createElement('button');
|
|
170
|
+
button.classList.add('collapse-all-defs-button', 'btn-outline-secondary', 'd-print-none', 'btn', 'p-0', 'fs-5', 'd-flex', 'align-items-center', 'justify-content-center');
|
|
171
|
+
// Create a container for all three state indicators
|
|
172
|
+
button.innerHTML = `<span class="state-indicator" data-state="0">①</span><span class="state-indicator" data-state="1">②</span><span class="state-indicator" data-state="2">③</span>`;
|
|
173
|
+
button.setAttribute('id', 'toggleButton');
|
|
174
|
+
button.setAttribute('title', buttonTitleText);
|
|
175
|
+
button.setAttribute('data-state', '2'); // Start with all definitions visible
|
|
176
|
+
|
|
177
|
+
// Set initial active state
|
|
178
|
+
button.querySelector('.state-indicator[data-state="2"]').classList.add('active');
|
|
179
|
+
|
|
180
|
+
dt.appendChild(button);
|
|
15
181
|
});
|
|
16
|
-
document.querySelector('html').classList.toggle('defs-hidden');
|
|
17
182
|
}
|
|
18
183
|
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
const button = document.createElement('button');
|
|
22
|
-
button.classList.add('collapse-all-defs-button', 'd-print-none', 'btn', 'p-0', 'fs-5', 'd-flex', 'align-items-center','justify-content-center');
|
|
23
|
-
button.innerHTML = '▲';
|
|
24
|
-
button.setAttribute('id', 'toggleButton');
|
|
25
|
-
dt.appendChild(button);
|
|
26
|
-
});
|
|
184
|
+
// Initial button setup
|
|
185
|
+
addButtons();
|
|
27
186
|
|
|
28
|
-
|
|
187
|
+
/**
|
|
188
|
+
* Handles click events on definition toggle buttons and their state indicators.
|
|
189
|
+
* Uses advanced positioning techniques to prevent UI jumping during transitions:
|
|
190
|
+
* 1. Temporarily fixes the button's position using position:fixed during DOM updates
|
|
191
|
+
* 2. Uses requestAnimationFrame for optimal timing of position restoration
|
|
192
|
+
* 3. Precisely adjusts scroll position to maintain visual stability
|
|
193
|
+
*
|
|
194
|
+
* This prevents the visual disruption that would otherwise occur when expanding
|
|
195
|
+
* or collapsing definitions causes layout reflow.
|
|
196
|
+
*
|
|
197
|
+
* @param {Event} event - The DOM click event
|
|
198
|
+
*/
|
|
29
199
|
document.addEventListener('click', event => {
|
|
30
|
-
if
|
|
31
|
-
|
|
200
|
+
// Check if the click is on a state-indicator or the button itself
|
|
201
|
+
if (event.target.classList.contains('collapse-all-defs-button') ||
|
|
202
|
+
event.target.classList.contains('state-indicator')) {
|
|
203
|
+
// Get the button element (whether clicked directly or via child)
|
|
204
|
+
const button = event.target.classList.contains('collapse-all-defs-button') ?
|
|
205
|
+
event.target :
|
|
206
|
+
event.target.closest('.collapse-all-defs-button');
|
|
32
207
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
208
|
+
// Find the parent dt and dl elements
|
|
209
|
+
const dtElement = button.closest('dt');
|
|
210
|
+
|
|
211
|
+
// Get button's position in viewport and page
|
|
212
|
+
const buttonRect = button.getBoundingClientRect();
|
|
38
213
|
|
|
39
|
-
//
|
|
214
|
+
// Apply a class to prevent layout shifts during transition
|
|
215
|
+
document.documentElement.classList.add('definitions-transitioning');
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Button position anchoring technique:
|
|
219
|
+
* 1. Fix the button in its current viewport position to ensure
|
|
220
|
+
* it doesn't move during DOM reflow
|
|
221
|
+
* 2. Apply fixed positioning with the exact same coordinates
|
|
222
|
+
* 3. After DOM changes, restore normal positioning and adjust scroll
|
|
223
|
+
*/
|
|
224
|
+
button.style.position = 'fixed';
|
|
225
|
+
button.style.top = `${buttonRect.top}px`;
|
|
226
|
+
button.style.right = `${window.innerWidth - buttonRect.right}px`;
|
|
227
|
+
button.style.zIndex = '1000';
|
|
228
|
+
|
|
229
|
+
// Add highlight effect
|
|
230
|
+
dtElement.classList.add('highlight');
|
|
40
231
|
setTimeout(() => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
232
|
+
dtElement.classList.remove('highlight');
|
|
233
|
+
}, 0);
|
|
234
|
+
|
|
235
|
+
// Toggle visibility which might change layout
|
|
236
|
+
toggleVisibility();
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Visual stability restoration:
|
|
240
|
+
* Use requestAnimationFrame to restore normal positioning at the optimal time
|
|
241
|
+
* after DOM updates, when the browser is ready to paint the next frame.
|
|
242
|
+
* This provides better timing than setTimeout for visual operations.
|
|
243
|
+
*/
|
|
244
|
+
requestAnimationFrame(() => {
|
|
245
|
+
// Remove fixed positioning
|
|
246
|
+
button.style.position = '';
|
|
247
|
+
button.style.top = '';
|
|
248
|
+
button.style.right = '';
|
|
249
|
+
button.style.zIndex = '';
|
|
250
|
+
|
|
251
|
+
// Remove the transitioning class
|
|
252
|
+
document.documentElement.classList.remove('definitions-transitioning');
|
|
253
|
+
|
|
254
|
+
// Scroll to correct position so the button appears where it was fixed
|
|
255
|
+
const newButtonRect = button.getBoundingClientRect();
|
|
256
|
+
|
|
257
|
+
// Calculate and apply precise scroll adjustment to maintain visual position
|
|
258
|
+
window.scrollTo({
|
|
259
|
+
top: window.scrollY + (newButtonRect.top - buttonRect.top),
|
|
260
|
+
behavior: 'instant'
|
|
44
261
|
});
|
|
45
|
-
}
|
|
262
|
+
});
|
|
46
263
|
}
|
|
47
264
|
});
|
|
48
265
|
}
|
|
49
266
|
|
|
267
|
+
/**
|
|
268
|
+
* Initialize the collapsible definitions functionality when the DOM is fully loaded.
|
|
269
|
+
* We listen for a custom event from insert-trefs.js to know exactly when all
|
|
270
|
+
* external references have been inserted into the DOM.
|
|
271
|
+
* @listens DOMContentLoaded - Standard DOM event fired when initial HTML document is completely loaded
|
|
272
|
+
* @listens trefs-inserted - Custom event fired by insert-trefs.js when all term references are processed
|
|
273
|
+
* @see initializeOnTrefsInserted - Helper function that manages initialization timing
|
|
274
|
+
*/
|
|
50
275
|
document.addEventListener("DOMContentLoaded", function () {
|
|
51
|
-
collapseDefinitions
|
|
276
|
+
initializeOnTrefsInserted(collapseDefinitions);
|
|
52
277
|
});
|
|
@@ -5,25 +5,30 @@
|
|
|
5
5
|
* @since 2025-02-16
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Creates a toggle button for collapsible meta information sections.
|
|
10
|
+
* @function createToggleButton
|
|
11
|
+
* @param {HTMLElement} element - The DD element that contains the meta information
|
|
12
|
+
* @returns {void}
|
|
13
|
+
*/
|
|
9
14
|
function createToggleButton(element) {
|
|
10
15
|
const toggleButton = document.createElement('button');
|
|
11
16
|
toggleButton.classList.add('meta-info-toggle-button', 'btn');
|
|
12
17
|
toggleButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 16 16" style="shape-rendering: geometricPrecision;">' +
|
|
13
18
|
'<path fill-rule="evenodd" d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>' +
|
|
14
|
-
'<path d="M8.93 6.588l-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588z"/>' +
|
|
19
|
+
'<path d="M8.93 6.588l-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588z"/>' +
|
|
15
20
|
'<path d="M9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/>' +
|
|
16
|
-
|
|
21
|
+
'</svg>';
|
|
17
22
|
toggleButton.title = 'Meta info';
|
|
18
23
|
|
|
19
24
|
// Add event listener to the button
|
|
20
|
-
toggleButton.addEventListener('click', function(e) {
|
|
25
|
+
toggleButton.addEventListener('click', function (e) {
|
|
21
26
|
e.preventDefault();
|
|
22
27
|
e.stopPropagation();
|
|
23
|
-
|
|
28
|
+
|
|
24
29
|
// Get the wrapper containing the meta info
|
|
25
30
|
const isCollapsed = element.classList.contains('collapsed');
|
|
26
|
-
|
|
31
|
+
|
|
27
32
|
// Toggle the collapsed state
|
|
28
33
|
if (isCollapsed) {
|
|
29
34
|
// If collapsed, expand it
|
|
@@ -49,14 +54,20 @@ function createToggleButton(element) {
|
|
|
49
54
|
}
|
|
50
55
|
}
|
|
51
56
|
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Finds all description list items (dd) that contain tables and makes them collapsible.
|
|
60
|
+
* Adds necessary wrapper elements and toggle buttons to create the collapsible UI.
|
|
61
|
+
* @function collapseMetaInfo
|
|
62
|
+
* @returns {void}
|
|
63
|
+
*/
|
|
64
|
+
function collapseMetaInfo() {
|
|
54
65
|
const collapsibles = document.querySelectorAll('dl > dd:has(table)');
|
|
55
66
|
|
|
56
|
-
collapsibles.forEach(function(element) {
|
|
67
|
+
collapsibles.forEach(function (element) {
|
|
57
68
|
// Add meta-info-content-wrapper class
|
|
58
69
|
element.classList.add('meta-info-content-wrapper');
|
|
59
|
-
|
|
70
|
+
|
|
60
71
|
// Wrap content in a div for proper spacing
|
|
61
72
|
const wrapper = document.createElement('div');
|
|
62
73
|
wrapper.classList.add('meta-info-inner-wrapper');
|
|
@@ -75,4 +86,20 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
75
86
|
// Collapse by default on load
|
|
76
87
|
element.classList.add('collapsed');
|
|
77
88
|
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Initialize the collapse meta info functionality when the DOM is fully loaded.
|
|
94
|
+
* We use the initializeOnTrefsInserted helper from insert-trefs.js to ensure our
|
|
95
|
+
* functionality runs at the right time - either after all external references have
|
|
96
|
+
* been inserted, or after a timeout if the event isn't triggered.
|
|
97
|
+
*
|
|
98
|
+
* @listens DOMContentLoaded - Initial event when DOM is ready
|
|
99
|
+
* @listens trefs-inserted - Custom event from insert-trefs.js when all external references are inserted
|
|
100
|
+
* @see initializeOnTrefsInserted - Helper function that manages initialization timing
|
|
101
|
+
*/
|
|
102
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
103
|
+
initializeOnTrefsInserted(collapseMetaInfo);
|
|
78
104
|
});
|
|
105
|
+
|
|
@@ -98,35 +98,11 @@ function initCollapsibleMenu() {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
});
|
|
101
|
-
|
|
102
|
-
console.log('Collapsible menu initialized with accessibility improvements');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Log TOC structure to help debugging
|
|
106
|
-
function logTOCStructure() {
|
|
107
|
-
const tocContainer = document.getElementById('toc');
|
|
108
|
-
if (tocContainer) {
|
|
109
|
-
console.log('TOC container found:', tocContainer);
|
|
110
|
-
console.log('TOC container children:', tocContainer.children);
|
|
111
|
-
const firstUL = tocContainer.querySelector('ul');
|
|
112
|
-
if (firstUL) {
|
|
113
|
-
console.log('First UL found:', firstUL);
|
|
114
|
-
console.log('UL class list:', firstUL.classList);
|
|
115
|
-
const listItems = firstUL.querySelectorAll('li');
|
|
116
|
-
console.log('List items count:', listItems.length);
|
|
117
|
-
} else {
|
|
118
|
-
console.warn('No UL found in TOC container');
|
|
119
|
-
}
|
|
120
|
-
} else {
|
|
121
|
-
console.warn('TOC container not found');
|
|
122
|
-
}
|
|
123
101
|
}
|
|
124
102
|
|
|
125
103
|
// Run after DOM is fully loaded
|
|
126
104
|
document.addEventListener('DOMContentLoaded', () => {
|
|
127
105
|
initCollapsibleMenu();
|
|
128
|
-
// Log the TOC structure for debugging
|
|
129
|
-
logTOCStructure();
|
|
130
106
|
});
|
|
131
107
|
|
|
132
108
|
// Re-initialize when highlighting changes
|
|
@@ -5,9 +5,18 @@
|
|
|
5
5
|
* @since 2024-09-19
|
|
6
6
|
*/
|
|
7
7
|
function createAlphabetIndex() {
|
|
8
|
-
|
|
8
|
+
// Check if the terms and definitions list exists
|
|
9
|
+
// If it doesn't exist, exit the function
|
|
10
|
+
// This prevents errors when the script is run on pages without the terms and definitions list
|
|
11
|
+
// and ensures that the script only runs when necessary
|
|
9
12
|
const termsListElement = document.querySelector(".terms-and-definitions-list");
|
|
10
|
-
const dtElements = termsListElement.querySelectorAll("dt");
|
|
13
|
+
const dtElements = termsListElement ? termsListElement.querySelectorAll("dt") : [];
|
|
14
|
+
|
|
15
|
+
if (dtElements.length === 0) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const terminologySectionUtilityContainer = document.getElementById("terminology-section-utility-container");
|
|
11
20
|
const alphabetIndex = {};
|
|
12
21
|
|
|
13
22
|
dtElements.forEach(dt => {
|
|
@@ -5,6 +5,17 @@
|
|
|
5
5
|
* @since 2024-09-19
|
|
6
6
|
*/
|
|
7
7
|
function createTermFilter() {
|
|
8
|
+
// Check if the terms and definitions list exists
|
|
9
|
+
// If it doesn't exist, exit the function
|
|
10
|
+
// This prevents errors when the script is run on pages without the terms and definitions list
|
|
11
|
+
// and ensures that the script only runs when necessary
|
|
12
|
+
const termsListElement = document.querySelector(".terms-and-definitions-list");
|
|
13
|
+
const dtElements = termsListElement ? termsListElement.querySelectorAll("dt") : [];
|
|
14
|
+
|
|
15
|
+
if (dtElements.length === 0) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
8
19
|
const terminologySectionUtilityContainer = document.getElementById("terminology-section-utility-container");
|
|
9
20
|
|
|
10
21
|
// Create checkboxes container
|
|
@@ -31,27 +42,46 @@ function createTermFilter() {
|
|
|
31
42
|
</label>
|
|
32
43
|
`;
|
|
33
44
|
|
|
34
|
-
//
|
|
35
|
-
|
|
45
|
+
// Append checkboxes to container
|
|
46
|
+
checkboxesContainer.appendChild(localTermsCheckboxDiv);
|
|
47
|
+
checkboxesContainer.appendChild(externalTermsCheckboxDiv);
|
|
48
|
+
|
|
49
|
+
// Add event listeners to checkboxes (generic for any number of checkboxes)
|
|
50
|
+
function enforceAtLeastOneChecked(event) {
|
|
51
|
+
const checkboxes = checkboxesContainer.querySelectorAll('input[type="checkbox"]');
|
|
52
|
+
const checkedBoxes = Array.from(checkboxes).filter(cb => cb.checked);
|
|
53
|
+
// If the user is unchecking a box
|
|
36
54
|
if (!event.target.checked) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
55
|
+
// If all others are already unchecked (so this would make all unchecked except the one being unchecked)
|
|
56
|
+
if (checkedBoxes.length === 0) {
|
|
57
|
+
// Check all other checkboxes except the one being unchecked
|
|
58
|
+
checkboxes.forEach(cb => {
|
|
59
|
+
if (cb !== event.target) {
|
|
60
|
+
cb.checked = true;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
// The one being unchecked remains unchecked
|
|
64
|
+
}
|
|
40
65
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
66
|
+
// Toggle classes for each checkbox type
|
|
67
|
+
checkboxes.forEach(cb => {
|
|
68
|
+
const html = document.querySelector('html');
|
|
69
|
+
if (cb.id === 'showLocalTermsCheckbox') {
|
|
70
|
+
html.classList.toggle('hide-local-terms', !cb.checked);
|
|
71
|
+
} else if (cb.id === 'showExternalTermsCheckbox') {
|
|
72
|
+
html.classList.toggle('hide-external-terms', !cb.checked);
|
|
73
|
+
}
|
|
74
|
+
// Add more else ifs here for future checkboxes
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Attach the handler to all checkboxes in the container
|
|
79
|
+
checkboxesContainer.addEventListener('change', function(event) {
|
|
80
|
+
if (event.target.matches('input[type="checkbox"]')) {
|
|
81
|
+
enforceAtLeastOneChecked(event);
|
|
48
82
|
}
|
|
49
83
|
});
|
|
50
|
-
|
|
51
|
-
// Append checkboxes to container
|
|
52
|
-
checkboxesContainer.appendChild(localTermsCheckboxDiv);
|
|
53
|
-
checkboxesContainer.appendChild(externalTermsCheckboxDiv);
|
|
54
|
-
|
|
84
|
+
|
|
55
85
|
// Add checkboxes to the terminology section utility container
|
|
56
86
|
terminologySectionUtilityContainer.appendChild(checkboxesContainer);
|
|
57
87
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function hideShowUtilityContainer() {
|
|
2
|
+
// Check if the terms and definitions list exists
|
|
3
|
+
// If it doesn't exist, exit the function
|
|
4
|
+
// This prevents errors when the script is run on pages without the terms and definitions list
|
|
5
|
+
// and ensures that the script only runs when necessary
|
|
6
|
+
const termsListElement = document.querySelector(".terms-and-definitions-list");
|
|
7
|
+
const dtElements = termsListElement ? termsListElement.querySelectorAll("dt") : [];
|
|
8
|
+
|
|
9
|
+
if (dtElements.length === 0) {
|
|
10
|
+
document.getElementById("terminology-section-utility-container")?.remove();
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
15
|
+
hideShowUtilityContainer();
|
|
16
|
+
});
|
|
@@ -113,7 +113,7 @@ const horizontalScrollHint = (elements) => {
|
|
|
113
113
|
// Create scroll hint element
|
|
114
114
|
const scrollHint = document.createElement('p');
|
|
115
115
|
scrollHint.classList.add('scrollHint');
|
|
116
|
-
scrollHint.innerHTML = `<img style='width: 40px; vertical-align: middle;' src='${fingerHorizontalScrollingImage}' alt='
|
|
116
|
+
scrollHint.innerHTML = `<img class='scrollHintImage' style='width: 40px; vertical-align: middle; padding: 0;margin: 0 !important;' src='${fingerHorizontalScrollingImage}' alt='' /> Scroll to the right`;
|
|
117
117
|
scrollHint.style.animation = 'arrow-tweet-panel-pulse 0.82s ease-in-out infinite';
|
|
118
118
|
|
|
119
119
|
el.appendChild(scrollHint);
|
|
@@ -155,5 +155,5 @@ document.addEventListener("DOMContentLoaded", function () {
|
|
|
155
155
|
// Apply to multiple different elements
|
|
156
156
|
// horizontalScrollHint(['.table-container', '.code-block', document.querySelector('#special-element')]);
|
|
157
157
|
|
|
158
|
-
horizontalScrollHint(['.table-responsive']);
|
|
158
|
+
horizontalScrollHint(['.table-responsive-md']);
|
|
159
159
|
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file This file adds functionality to display images in full-size on a web page when clicked. The functionality is implemented via a class added to the image element.
|
|
3
|
+
* @author Kor Dwarshuis
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const imageFullSize = () => {
|
|
9
|
+
const imageFullSizeClass = 'image-full-page';
|
|
10
|
+
|
|
11
|
+
// All images get a click event listener via event delegation
|
|
12
|
+
const markdownElement = document.querySelector('#content');
|
|
13
|
+
|
|
14
|
+
function removeContainer() {
|
|
15
|
+
let container = document.querySelector('.image-container-full-page');
|
|
16
|
+
if (container) {
|
|
17
|
+
document.body.removeChild(container);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (markdownElement) {
|
|
22
|
+
markdownElement.addEventListener('click', (event) => {
|
|
23
|
+
if (event.target.tagName === 'IMG') {
|
|
24
|
+
|
|
25
|
+
// To be implemented: also account for SVG, path, circle, rect
|
|
26
|
+
// if ((event.target.tagName === 'svg' || event.target.tagName === 'path' || event.target.tagName === 'circle' || event.target.tagName === 'rect') && event.target.closest('.markdown')) {
|
|
27
|
+
|
|
28
|
+
let image = event.target;
|
|
29
|
+
|
|
30
|
+
if (document.querySelector('.image-container-full-page') === null) {
|
|
31
|
+
// Add container if it doesn't exist
|
|
32
|
+
|
|
33
|
+
// Clone the image element
|
|
34
|
+
const clonedImage = image.cloneNode(true);
|
|
35
|
+
|
|
36
|
+
// Create a new div element with the class .full-page-image-container
|
|
37
|
+
const container = document.createElement('div');
|
|
38
|
+
container.classList.add('image-container');
|
|
39
|
+
container.classList.add('image-container-full-page');
|
|
40
|
+
|
|
41
|
+
// Add the cloned image to the new container div
|
|
42
|
+
container.appendChild(clonedImage);
|
|
43
|
+
|
|
44
|
+
// Append the new container div to the body
|
|
45
|
+
document.body.appendChild(container);
|
|
46
|
+
|
|
47
|
+
// Add event listener to the new container
|
|
48
|
+
container.addEventListener('click', function containerClickEvent() {
|
|
49
|
+
container.removeEventListener('click', containerClickEvent); // remove this click listener
|
|
50
|
+
removeContainer();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Toggle the full size class on the original image
|
|
56
|
+
image.classList.toggle(imageFullSizeClass);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Add keydown event listener to handle the ESC key
|
|
61
|
+
document.addEventListener('keydown', (event) => {
|
|
62
|
+
if (event.key === "Escape") {
|
|
63
|
+
removeContainer();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
} else {
|
|
68
|
+
console.log("Element with class '.markdown' not found.");
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
73
|
+
imageFullSize();
|
|
74
|
+
});
|