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.
Files changed (42) hide show
  1. package/assets/compiled/body.js +11 -8
  2. package/assets/compiled/head.css +7 -4
  3. package/assets/css/add-bootstrap-classes-to-images.css +34 -0
  4. package/assets/css/collapse-definitions.css +41 -0
  5. package/assets/css/create-pdf.css +339 -0
  6. package/assets/css/horizontal-scroll-hint.css +6 -0
  7. package/assets/css/image-full-size.css +40 -0
  8. package/assets/css/index.css +5 -0
  9. package/assets/css/search.css +8 -8
  10. package/assets/css/terms-and-definitions.css +3 -3
  11. package/assets/js/add-bootstrap-classes-to-images.js +95 -0
  12. package/assets/js/collapse-definitions.js +259 -34
  13. package/assets/js/collapse-meta-info.js +37 -10
  14. package/assets/js/collapsibleMenu.js +0 -24
  15. package/assets/js/create-alphabet-index.js +11 -2
  16. package/assets/js/create-term-filter.js +47 -17
  17. package/assets/js/hide-show-utility-container.js +16 -0
  18. package/assets/js/horizontal-scroll-hint.js +2 -2
  19. package/assets/js/image-full-size.js +74 -0
  20. package/assets/js/insert-trefs.js +135 -49
  21. package/assets/js/search.js +46 -20
  22. package/{src → config}/asset-map.json +6 -0
  23. package/{src/config → config}/paths.js +2 -2
  24. package/gulpfile.js +1 -1
  25. package/index.js +5 -5
  26. package/package.json +1 -1
  27. package/src/README.md +3 -3
  28. package/src/collect-external-references.js +2 -2
  29. package/src/collectExternalReferences/fetchTermsFromIndex.1.js +340 -0
  30. package/src/collectExternalReferences/fetchTermsFromIndex.js +1 -1
  31. package/src/collectExternalReferences/processXTrefsData.js +1 -1
  32. package/src/create-pdf.js +330 -21
  33. package/src/create-term-index.js +126 -22
  34. package/src/health-check/tref-term-checker.js +1 -1
  35. package/src/health-check.js +1 -1
  36. package/src/init.js +1 -1
  37. package/src/insert-term-index.js +5 -5
  38. package/src/install-from-boilerplate/add-scripts-keys.js +3 -1
  39. package/src/install-from-boilerplate/boilerplate/gitignore +1 -1
  40. package/src/markdown-it-extensions.js +2 -2
  41. package/src/utils/fetch.js +14 -14
  42. 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
- const dds = document.querySelectorAll('#content dl.terms-and-definitions-list > dd');
3
- const dts = document.querySelectorAll('#content dl.terms-and-definitions-list > dt');
4
- const buttons = document.querySelectorAll('.collapse-all-defs-button');
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 isHidden = dds[0].classList.contains('hidden');
8
- dds.forEach(dd => {
9
- dd.classList.toggle('hidden', !isHidden);
10
- dd.classList.toggle('visible', isHidden);
11
- });
12
- buttons.forEach(button => {
13
- button.innerHTML = isHidden ? '▲' : '▼';
14
- button.title = isHidden ? 'Collapse all definitions' : 'Expand all definitions';
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
- // Add button as last child of every <dl>
20
- dts.forEach(dt => {
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
- // Via event delegation add event listener to every .collapse-all-defs-button element
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 (event.target.classList.contains('collapse-all-defs-button')) {
31
- toggleVisibility();
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
- event.target.scrollIntoView({
34
- behavior: 'smooth',
35
- block: 'start',
36
- inline: 'nearest'
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
- // Adjust the scroll position by 100px smoothly
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
- window.scrollBy({
42
- top: -100,
43
- behavior: 'smooth'
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
- }, 500); // Delay to ensure the initial scrollIntoView completes
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
- // Function to create the toggle button
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
- '</svg>';
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
- // Find all elements with class 'collapsible' and make them collapsible
53
- document.addEventListener('DOMContentLoaded', function() {
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
- const terminologySectionUtilityContainer = document.getElementById("terminology-section-utility-container");
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
- // Add event listeners to checkboxes
35
- localTermsCheckboxDiv.querySelector('#showLocalTermsCheckbox').addEventListener('change', function(event) {
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
- document.querySelector('html').classList.add('hide-local-terms');
38
- } else {
39
- document.querySelector('html').classList.remove('hide-local-terms');
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
- externalTermsCheckboxDiv.querySelector('#showExternalTermsCheckbox').addEventListener('change', function(event) {
44
- if (!event.target.checked) {
45
- document.querySelector('html').classList.add('hide-external-terms');
46
- } else {
47
- document.querySelector('html').classList.remove('hide-external-terms');
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='finger scrolling horizontally' /> Scroll to the right`;
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
+ });