spec-up-t 1.3.1 → 1.4.0

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 (130) hide show
  1. package/.github/copilot-instructions.md +13 -0
  2. package/assets/compiled/body.js +17 -11
  3. package/assets/compiled/head.css +6 -4
  4. package/assets/css/collapse-definitions.css +0 -1
  5. package/assets/css/create-pdf.css +4 -2
  6. package/assets/css/create-term-filter.css +4 -4
  7. package/assets/css/definition-buttons-container.css +60 -0
  8. package/assets/css/insert-trefs.css +7 -0
  9. package/assets/css/sidebar-toc.css +2 -1
  10. package/assets/css/terms-and-definitions.css +73 -22
  11. package/assets/js/add-href-to-snapshot-link.js +16 -9
  12. package/assets/js/addAnchorsToTerms.js +1 -1
  13. package/assets/js/charts.js +10 -0
  14. package/assets/js/collapse-definitions.js +13 -2
  15. package/assets/js/collapse-meta-info.js +11 -9
  16. package/assets/js/definition-button-container-utils.js +82 -0
  17. package/assets/js/edit-term-buttons.js +77 -20
  18. package/assets/js/github-issues.js +35 -0
  19. package/assets/js/github-repo-info.js +144 -0
  20. package/assets/js/highlight-heading-plus-sibling-nodes.test.js +18 -0
  21. package/assets/js/insert-trefs.js +62 -13
  22. package/assets/js/mermaid-diagrams.js +11 -0
  23. package/assets/js/terminology-section-utility-container/README.md +107 -0
  24. package/assets/js/terminology-section-utility-container/create-alphabet-index.js +17 -0
  25. package/assets/js/{create-term-filter.js → terminology-section-utility-container/create-term-filter.js} +11 -44
  26. package/assets/js/terminology-section-utility-container/hide-show-utility-container.js +21 -0
  27. package/assets/js/terminology-section-utility-container/search.js +203 -0
  28. package/assets/js/terminology-section-utility-container.js +203 -0
  29. package/assets/js/tooltips.js +283 -0
  30. package/config/asset-map.json +24 -16
  31. package/index.js +57 -390
  32. package/package.json +5 -2
  33. package/src/add-remove-xref-source.js +20 -21
  34. package/src/collect-external-references.js +8 -337
  35. package/src/collect-external-references.test.js +440 -33
  36. package/src/configure.js +8 -109
  37. package/src/create-docx.js +7 -6
  38. package/src/create-pdf.js +15 -14
  39. package/src/freeze-spec-data.js +46 -0
  40. package/src/git-info.test.js +76 -0
  41. package/src/health-check/destination-gitignore-checker.js +5 -3
  42. package/src/health-check/external-specs-checker.js +5 -4
  43. package/src/health-check/specs-configuration-checker.js +2 -1
  44. package/src/health-check/term-references-checker.js +5 -3
  45. package/src/health-check/terms-intro-checker.js +2 -1
  46. package/src/health-check/tref-term-checker.js +8 -7
  47. package/src/health-check.js +8 -7
  48. package/src/init.js +3 -2
  49. package/src/install-from-boilerplate/add-gitignore-entries.js +3 -2
  50. package/src/install-from-boilerplate/add-scripts-keys.js +5 -4
  51. package/src/install-from-boilerplate/boilerplate/README.md +1 -1
  52. package/src/install-from-boilerplate/boilerplate/spec/example-markup-in-markdown.md +1 -1
  53. package/src/install-from-boilerplate/boilerplate/spec/spec-head.md +1 -1
  54. package/src/install-from-boilerplate/boilerplate/specs.json +2 -1
  55. package/src/install-from-boilerplate/config-scripts-keys.js +3 -3
  56. package/src/install-from-boilerplate/copy-boilerplate.js +2 -1
  57. package/src/install-from-boilerplate/copy-system-files.js +4 -3
  58. package/src/install-from-boilerplate/custom-update.js +12 -1
  59. package/src/install-from-boilerplate/help.txt +1 -1
  60. package/src/install-from-boilerplate/menu.sh +6 -6
  61. package/src/json-key-validator.js +17 -11
  62. package/src/markdown-it/README.md +207 -0
  63. package/src/markdown-it/definition-lists.js +397 -0
  64. package/src/markdown-it/index.js +83 -0
  65. package/src/markdown-it/link-enhancement.js +98 -0
  66. package/src/markdown-it/plugins.js +118 -0
  67. package/src/markdown-it/table-enhancement.js +97 -0
  68. package/src/markdown-it/template-tag-syntax.js +152 -0
  69. package/src/parsers/index.js +16 -0
  70. package/src/parsers/spec-parser.js +152 -0
  71. package/src/parsers/spec-parser.test.js +109 -0
  72. package/src/parsers/template-tag-parser.js +277 -0
  73. package/src/parsers/template-tag-parser.test.js +107 -0
  74. package/src/pipeline/configuration/configure-starterpack.js +200 -0
  75. package/src/{create-external-specs-list.js → pipeline/configuration/create-external-specs-list.js} +13 -12
  76. package/src/{create-term-index.js → pipeline/configuration/create-term-index.js} +19 -18
  77. package/src/{create-versions-index.js → pipeline/configuration/create-versions-index.js} +4 -3
  78. package/src/{insert-term-index.js → pipeline/configuration/insert-term-index.js} +2 -2
  79. package/src/pipeline/configuration/prepare-spec-configuration.js +70 -0
  80. package/src/pipeline/parsing/apply-markdown-it-extensions.js +35 -0
  81. package/src/pipeline/parsing/create-markdown-parser.js +94 -0
  82. package/src/pipeline/parsing/create-markdown-parser.test.js +49 -0
  83. package/src/{html-dom-processor.js → pipeline/postprocessing/definition-list-postprocessor.js} +69 -10
  84. package/src/{escape-handler.js → pipeline/preprocessing/escape-processor.js} +3 -1
  85. package/src/{fix-markdown-files.js → pipeline/preprocessing/normalize-terminology-markdown.js} +41 -31
  86. package/src/pipeline/references/collect-external-references.js +307 -0
  87. package/src/pipeline/references/external-references-service.js +231 -0
  88. package/src/pipeline/references/fetch-terms-from-index.js +198 -0
  89. package/src/pipeline/references/match-term.js +34 -0
  90. package/src/{collectExternalReferences/matchTerm.test.js → pipeline/references/match-term.test.js} +8 -2
  91. package/src/pipeline/references/process-xtrefs-data.js +94 -0
  92. package/src/pipeline/references/xtref-utils.js +166 -0
  93. package/src/pipeline/rendering/render-spec-document.js +146 -0
  94. package/src/pipeline/rendering/render-utils.js +154 -0
  95. package/src/utils/LOGGER.md +81 -0
  96. package/src/utils/{doesUrlExist.js → does-url-exist.js} +4 -3
  97. package/src/utils/fetch.js +5 -4
  98. package/src/utils/file-opener.js +3 -2
  99. package/src/utils/git-info.js +77 -0
  100. package/src/utils/logger.js +74 -0
  101. package/src/utils/regex-patterns.js +471 -0
  102. package/src/utils/regex-patterns.test.js +281 -0
  103. package/templates/template.html +56 -21
  104. package/assets/js/create-alphabet-index.js +0 -60
  105. package/assets/js/hide-show-utility-container.js +0 -16
  106. package/assets/js/index.js +0 -87
  107. package/assets/js/search.js +0 -365
  108. package/src/collectExternalReferences/fetchTermsFromIndex.js +0 -284
  109. package/src/collectExternalReferences/matchTerm.js +0 -32
  110. package/src/collectExternalReferences/processXTrefsData.js +0 -108
  111. package/src/freeze.js +0 -90
  112. package/src/markdown-it-extensions.js +0 -395
  113. package/src/references.js +0 -114
  114. /package/assets/css/{bootstrap.min.css → embedded-libraries/bootstrap.min.css} +0 -0
  115. /package/assets/css/{prism.css → embedded-libraries/prism.css} +0 -0
  116. /package/assets/css/{prism.dark.css → embedded-libraries/prism.dark.css} +0 -0
  117. /package/assets/css/{prism.default.css → embedded-libraries/prism.default.css} +0 -0
  118. /package/assets/js/{bootstrap.bundle.min.js → embedded-libraries/bootstrap.bundle.min.js} +0 -0
  119. /package/assets/js/{chart.js → embedded-libraries/chart.js} +0 -0
  120. /package/assets/js/{diff.min.js → embedded-libraries/diff.min.js} +0 -0
  121. /package/assets/js/{font-awesome.js → embedded-libraries/font-awesome.js} +0 -0
  122. /package/assets/js/{mermaid.js → embedded-libraries/mermaid.js} +0 -0
  123. /package/assets/js/{notyf.js → embedded-libraries/notyf.js} +0 -0
  124. /package/assets/js/{popper.js → embedded-libraries/popper.js} +0 -0
  125. /package/assets/js/{prism.dark.js → embedded-libraries/prism.dark.js} +0 -0
  126. /package/assets/js/{prism.default.js → embedded-libraries/prism.default.js} +0 -0
  127. /package/assets/js/{prism.js → embedded-libraries/prism.js} +0 -0
  128. /package/assets/js/{tippy.js → embedded-libraries/tippy.js} +0 -0
  129. /package/src/{escape-mechanism.js → pipeline/preprocessing/escape-placeholder-utils.js} +0 -0
  130. /package/src/utils/{isLineWithDefinition.js → is-line-with-definition.js} +0 -0
@@ -14,11 +14,7 @@ h6 {
14
14
 
15
15
  /* ====== TERMINOLOGY SECTION CONTAINER ====== */
16
16
  #terminology-section-utility-container {
17
- display: flex;
18
- flex-wrap: wrap;
19
- justify-content: center;
20
17
  margin: 1em auto;
21
- padding: 0;
22
18
  width: 100%;
23
19
  }
24
20
 
@@ -69,14 +65,52 @@ dl.terms-and-definitions-list>dt {
69
65
  /* Improve line spacing */
70
66
  font-size: 1.05em;
71
67
  /* Slightly larger font for better hierarchy */
68
+ /* Use flexbox for proper layout of term text and button container */
69
+ display: flex;
70
+ flex-wrap: wrap;
72
71
  align-items: center;
73
- /* Vertically center the content */
72
+ gap: 0.5rem;
73
+ /* Space between term text and buttons */
74
+ min-height: 2.5rem;
75
+ /* Ensure minimum height for buttons */
74
76
  }
75
77
 
76
- /* This adds spacing between the term text and the buttons */
78
+ /* ====== ELLIPSIS TRUNCATION WITH HOVER EXPANSION ====== */
79
+ /* Term text styling with ellipsis truncation and hover expansion */
77
80
  dl.terms-and-definitions-list>dt>span {
78
- margin-right: 1.5em;
79
- /* Add spacing to the right of the term text */
81
+ /* Flex item that grows to fill available space */
82
+ flex: 1 1 auto;
83
+ min-width: 0;
84
+ /* Allow flex item to shrink below content size */
85
+ white-space: nowrap;
86
+ overflow: hidden;
87
+ text-overflow: ellipsis;
88
+ transition: all 0.2s ease-in-out;
89
+ }
90
+
91
+ /* On hover or focus (including parent dt), expand to show full content */
92
+ /* The term will expand naturally and wrap if needed, buttons will only wrap if necessary */
93
+ dl.terms-and-definitions-list>dt>span:hover,
94
+ dl.terms-and-definitions-list>dt>span:focus,
95
+ dl.terms-and-definitions-list>dt:hover>span,
96
+ dl.terms-and-definitions-list>dt:focus>span {
97
+ white-space: normal;
98
+ overflow: visible;
99
+ text-overflow: initial;
100
+ word-wrap: break-word;
101
+ line-height: 1.4;
102
+ /* Don't force full width - let it expand naturally */
103
+ /* Buttons will only wrap if the expanded text actually needs more space */
104
+ }
105
+
106
+ /* Touch device support - also trigger on tap/touch */
107
+ dl.terms-and-definitions-list>dt>span:active,
108
+ dl.terms-and-definitions-list>dt:active>span {
109
+ white-space: normal;
110
+ overflow: visible;
111
+ text-overflow: initial;
112
+ word-wrap: break-word;
113
+ line-height: 1.4;
80
114
  }
81
115
 
82
116
 
@@ -205,10 +239,11 @@ dl.terms-and-definitions-list dd.last-dd {
205
239
  /* Apply original, more condensed styling when the html element has class "dense-info" */
206
240
  html.dense-info dl.terms-and-definitions-list>dt {
207
241
  padding: 0.1rem 1.25rem;
208
- display: block;
209
- /* Revert from flexbox to block */
242
+ /* Keep flexbox for consistent layout, just reduce padding */
210
243
  line-height: inherit;
211
244
  font-size: inherit;
245
+ min-height: auto;
246
+ /* Remove minimum height in dense mode */
212
247
  }
213
248
 
214
249
  html.dense-info dl.terms-and-definitions-list dd+dt {
@@ -221,21 +256,41 @@ html.dense-info dl.terms-and-definitions-list>dt::before {
221
256
  }
222
257
 
223
258
  html.dense-info dl.terms-and-definitions-list>dt>span {
224
- margin-right: 0;
225
- /* Remove spacing for term text */
259
+ /* Keep flex properties for consistent behavior */
260
+ flex: 1 1 auto;
261
+ min-width: 0;
226
262
  }
227
263
 
228
264
  /* ====== TRANSCLUSIONS STYLING ====== */
229
265
  /* Base transclusion styles */
230
- .transcluded-xref-term {
266
+ .term-external {
231
267
  position: relative;
232
268
  }
233
269
 
234
- dl.terms-and-definitions-list>dt.transcluded-xref-term,
235
- dl.terms-and-definitions-list>dd.transcluded-xref-term {
270
+ dl.terms-and-definitions-list>dt.term-external,
271
+ dl.terms-and-definitions-list>dd.term-external {
236
272
  background: #a9dde03b;
237
273
  }
238
274
 
275
+ /* Local term styling */
276
+ .term-local {
277
+ position: relative;
278
+ }
279
+
280
+ dl.terms-and-definitions-list>dt.term-local,
281
+ dl.terms-and-definitions-list>dd.term-local {
282
+ background: #f0f8ff;
283
+ }
284
+
285
+ /* Local term original term and parenthetical styling */
286
+ dl.terms-and-definitions-list .term-local-original-term {
287
+ font-style: italic;
288
+ }
289
+
290
+ dl.terms-and-definitions-list .term-local-parenthetical-terms {
291
+ font-weight: normal;
292
+ }
293
+
239
294
  /* Fix for all buttons */
240
295
  .btn {
241
296
  font-variant: small-caps;
@@ -245,10 +300,6 @@ dl.terms-and-definitions-list>dd.transcluded-xref-term {
245
300
  /* Higher z-index for all buttons */
246
301
  }
247
302
 
248
- .collapse-all-defs-button {
249
- float: right;
250
- }
251
-
252
303
  .transclusion-heading {
253
304
  font-size: 1.3em;
254
305
  font-weight: bold;
@@ -256,7 +307,7 @@ dl.terms-and-definitions-list>dd.transcluded-xref-term {
256
307
  }
257
308
 
258
309
  /* Embedded transclusions in definition lists */
259
- dl.terms-and-definitions-list>dd.transcluded-xref-term-embedded {
310
+ dl.terms-and-definitions-list>dd.term-external-embedded {
260
311
  position: relative;
261
312
  padding-left: 2.5rem;
262
313
  padding-top: 0.3rem;
@@ -264,7 +315,7 @@ dl.terms-and-definitions-list>dd.transcluded-xref-term-embedded {
264
315
  }
265
316
 
266
317
  /* Arrow styling for transclusions */
267
- dl.terms-and-definitions-list span.transcluded-xref-term::after {
318
+ dl.terms-and-definitions-list span.term-external::after {
268
319
  content: "";
269
320
  position: absolute;
270
321
  top: 50%;
@@ -279,7 +330,7 @@ dl.terms-and-definitions-list span.transcluded-xref-term::after {
279
330
  }
280
331
 
281
332
  /* Inline span styling for transclusions */
282
- dl.terms-and-definitions-list span.transcluded-xref-term {
333
+ dl.terms-and-definitions-list span.term-external {
283
334
  padding-left: 1.5rem;
284
335
  display: inline-block;
285
336
  }
@@ -7,25 +7,32 @@
7
7
  */
8
8
 
9
9
  function addHrefToSnapshotLink() {
10
- const snapshotLink = document.querySelector('#snapshotLink');
10
+ const snapshotLink = document.querySelector('#snapshot-link-in-content');
11
11
 
12
12
  // Get the current URL of the page
13
13
  const currentUrl = window.location.href;
14
14
 
15
+ // Remove query parameters and hash for URL processing
16
+ const urlWithoutParams = currentUrl.split('?')[0].split('#')[0];
17
+
15
18
  // Regex to match up to and including the 'versions/' directory (if it exists)
16
- const versionsRegex = new RegExp('^(https?://[^/]+(?:/[^/]+)*)/versions/(?:[^/]+/)?');
17
- const versionsMatch = versionsRegex.exec(currentUrl);
19
+ // Updated to handle file:// URLs and various protocols
20
+ const versionsRegex = new RegExp('^([^?#]+)/versions/(?:[^/?#]+/?)*');
21
+ const versionsMatch = versionsRegex.exec(urlWithoutParams);
18
22
 
19
- // If we are already in the 'versions' directory or deeper, strip down to 'versions/'
20
- // Otherwise, append '/versions/' to the current directory
21
23
  let snapshotLinkHref;
22
24
  if (versionsMatch) {
23
- snapshotLinkHref = `${versionsMatch[1]}/versions/`;
25
+ // If we are already in the 'versions' directory or deeper, strip down to 'versions/'
26
+ snapshotLinkHref = `${versionsMatch[1]}/versions/index.html`;
24
27
  } else {
28
+ // Clean up the URL: remove index.html, remove trailing slashes, remove any existing /versions/ suffixes
29
+ let cleanUrl = urlWithoutParams
30
+ .replace(/\/index\.html$/, '')
31
+ .replace(/\/$/, '')
32
+ .replace(/\/versions+$/, ''); // Remove any trailing /versions (including multiple)
33
+
25
34
  // Append '/versions/' to the current directory
26
- const urlWithoutAnchor = currentUrl.split('#')[0];
27
- const urlWithoutIndex = urlWithoutAnchor.replace(/\/index\.html$/, '');
28
- snapshotLinkHref = urlWithoutIndex.replace(/\/$/, '') + '/versions/';
35
+ snapshotLinkHref = cleanUrl + '/versions/index.html';
29
36
  }
30
37
 
31
38
  // Set the 'href' attribute of the snapshot link element to the constructed URL
@@ -3,7 +3,7 @@ function addAnchorsToTerms() {
3
3
  // For external references (tref), we need to use the main term ID, not alias ID
4
4
  function findMainTermSpan(element) {
5
5
  // First, check if this is a transcluded external reference
6
- const transcludedSpan = element.querySelector('span.transcluded-xref-term[id^="term:"]');
6
+ const transcludedSpan = element.querySelector('span.term-external[id^="term:"]');
7
7
  if (transcludedSpan) {
8
8
  // For transcluded external references, always use the main term ID (outermost span)
9
9
  // This ensures that anchor links work correctly with external content insertion
@@ -0,0 +1,10 @@
1
+ (function () {
2
+ 'use strict';
3
+
4
+ /* Charts */
5
+
6
+ document.querySelectorAll('.chartjs').forEach(chart => {
7
+ new Chart(chart, JSON.parse(chart.textContent));
8
+ });
9
+
10
+ })();
@@ -1,12 +1,14 @@
1
1
  /**
2
2
  * @fileoverview Manages collapsible definition lists with visual state indicators.
3
3
  * @author Kor Dwarshuis
4
- * @version 1.0.0
4
+ * @version 1.0.1
5
+ * @updated 2025-10-02 - Refactored to use centralized button container utilities
5
6
  * @description This module provides functionality to toggle the visibility
6
7
  * of definition descriptions in a document with a smooth user experience.
7
8
  * It creates interactive buttons with three toggle states and prevents
8
9
  * UI jumping during transitions using fixed positioning and requestAnimationFrame.
9
10
  * @requires insert-trefs.js - For the initializeOnTrefsInserted helper function
11
+ * @requires definition-button-container-utils.js - For the addButtonToContainer utility function
10
12
  */
11
13
 
12
14
  /**
@@ -58,6 +60,12 @@ function collapseDefinitions() {
58
60
  "See more on",
59
61
  "See more at",
60
62
  "More:",
63
+ "Note:",
64
+ "Paraphrased by",
65
+ "Beware:",
66
+ "eSSIF-Lab: ",
67
+ "W3C VC:",
68
+ "NIST:",
61
69
  "Supporting definitions:"
62
70
  ];
63
71
  return definitionHidePrefixes.some(prefix => content.startsWith(prefix));
@@ -156,6 +164,7 @@ function collapseDefinitions() {
156
164
 
157
165
  /**
158
166
  * Creates and appends toggle buttons to all definition terms.
167
+ * Creates or reuses a button container and adds the collapse button to it.
159
168
  * Each button contains state indicators for the three visibility states,
160
169
  * and is initialized to show all definitions (state 2).
161
170
  * @function
@@ -178,7 +187,9 @@ function collapseDefinitions() {
178
187
  // Set initial active state
179
188
  button.querySelector('.state-indicator[data-state="2"]').classList.add('active');
180
189
 
181
- dt.appendChild(button);
190
+ // Use the centralized utility to add the button to the container
191
+ // Prepend=false (default) ensures collapse button appears after meta-info button
192
+ addButtonToContainer(dt, button);
182
193
  });
183
194
  }
184
195
 
@@ -1,24 +1,23 @@
1
1
  /**
2
2
  * @file This file creates a collapsible meta info section for each term definition on the page. It is used to hide meta information about a term definition by default and show it when the user clicks the button.
3
3
  * @author Kor Dwarshuis
4
- * @version 0.0.2
4
+ * @version 0.0.3
5
5
  * @since 2025-02-16
6
+ * @updated 2025-10-02 - Refactored to use centralized button container utilities
7
+ * @requires definition-button-container-utils.js - For the addButtonToContainer utility function
6
8
  */
7
9
 
8
10
  /**
9
11
  * Creates a toggle button for collapsible meta information sections.
12
+ * Creates or reuses a button container and adds the meta-info button to it.
10
13
  * @function createToggleButton
11
14
  * @param {HTMLElement} element - The DD element that contains the meta information
12
15
  * @returns {void}
13
16
  */
14
17
  function createToggleButton(element) {
15
18
  const toggleButton = document.createElement('button');
16
- toggleButton.classList.add('meta-info-toggle-button', 'btn');
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;">' +
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"/>' +
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"/>' +
20
- '<path d="M9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/>' +
21
- '</svg>';
19
+ toggleButton.classList.add('meta-info-toggle-button', 'btn', 'fs-1', 'd-flex', 'align-items-center','justify-content-center');
20
+ toggleButton.innerHTML = '<i class="bi bi-info-circle" style="margin-top: -0.5em;"></i>';
22
21
  toggleButton.title = 'Meta info';
23
22
 
24
23
  // Add event listener to the button
@@ -41,13 +40,16 @@ function createToggleButton(element) {
41
40
  }
42
41
  });
43
42
 
44
- // Find the closest <dt> sibling and insert the button inside it
43
+ // Find the closest <dt> sibling
45
44
  let dtElement = element.previousElementSibling;
46
45
  while (dtElement && dtElement.tagName !== 'DT') {
47
46
  dtElement = dtElement.previousElementSibling;
48
47
  }
48
+
49
49
  if (dtElement) {
50
- dtElement.appendChild(toggleButton);
50
+ // Use the centralized utility to add the button to the container
51
+ // Prepend=true ensures meta-info button appears first
52
+ addButtonToContainer(dtElement, toggleButton, true);
51
53
  } else {
52
54
  // Fallback to inserting at the top right of the element if no <dt> is found
53
55
  element.insertBefore(toggleButton, element.firstChild);
@@ -0,0 +1,82 @@
1
+ /**
2
+ * @fileoverview Utility functions for managing the definition buttons container.
3
+ * @author Kor Dwarshuis
4
+ * @version 1.0.0
5
+ * @since 2025-10-02
6
+ * @description This module provides centralized utilities for creating and managing
7
+ * the container that holds control buttons in definition list terms (dt elements).
8
+ * This approach eliminates code duplication and provides a single source of truth
9
+ * for button container logic.
10
+ */
11
+
12
+ /**
13
+ * Gets or creates a button container within a definition term (dt) element.
14
+ * If a container already exists, it returns that container to prevent duplicates.
15
+ * If no container exists, it creates one and appends it to the dt element.
16
+ *
17
+ * This function serves as the single point of control for button container creation,
18
+ * ensuring consistency across all definition-related button functionality.
19
+ *
20
+ * @function getOrCreateButtonContainer
21
+ * @param {HTMLElement} dtElement - The dt (definition term) element that should contain the button container
22
+ * @returns {HTMLElement} The button container div element (either existing or newly created)
23
+ *
24
+ * @example
25
+ * // Get or create a container for a definition term
26
+ * const dt = document.querySelector('dt');
27
+ * const container = getOrCreateButtonContainer(dt);
28
+ *
29
+ * // Add buttons to the container
30
+ * const myButton = document.createElement('button');
31
+ * container.appendChild(myButton);
32
+ */
33
+ function getOrCreateButtonContainer(dtElement) {
34
+ // First, check if a container already exists to avoid duplicates
35
+ let buttonContainer = dtElement.querySelector('.definition-buttons-container');
36
+
37
+ // If no container exists, create one
38
+ if (!buttonContainer) {
39
+ buttonContainer = document.createElement('div');
40
+ buttonContainer.classList.add('definition-buttons-container');
41
+ dtElement.appendChild(buttonContainer);
42
+ }
43
+
44
+ return buttonContainer;
45
+ }
46
+
47
+ /**
48
+ * Adds a button to a definition term's button container.
49
+ * This is a convenience function that combines getting/creating the container
50
+ * and adding a button to it in a single operation.
51
+ *
52
+ * @function addButtonToContainer
53
+ * @param {HTMLElement} dtElement - The dt (definition term) element
54
+ * @param {HTMLElement} button - The button element to add to the container
55
+ * @param {boolean} [prepend=false] - If true, adds the button at the beginning; if false, appends at the end
56
+ * @returns {HTMLElement} The button container element
57
+ *
58
+ * @example
59
+ * // Add a button to the end of the container
60
+ * const dt = document.querySelector('dt');
61
+ * const myButton = document.createElement('button');
62
+ * addButtonToContainer(dt, myButton);
63
+ *
64
+ * @example
65
+ * // Add a button to the beginning of the container
66
+ * const dt = document.querySelector('dt');
67
+ * const firstButton = document.createElement('button');
68
+ * addButtonToContainer(dt, firstButton, true);
69
+ */
70
+ function addButtonToContainer(dtElement, button, prepend = false) {
71
+ const container = getOrCreateButtonContainer(dtElement);
72
+
73
+ if (prepend) {
74
+ // Add button as the first child
75
+ container.insertBefore(button, container.firstChild);
76
+ } else {
77
+ // Add button as the last child
78
+ container.appendChild(button);
79
+ }
80
+
81
+ return container;
82
+ }
@@ -18,45 +18,41 @@ function editTermButtons() {
18
18
  return currentElement;
19
19
  }
20
20
 
21
- // Remove "./" or "/" from the beginning of a string and "/" at the end of the string
22
- function cleanPath(path) {
23
- // Remove "./" or "/" from the beginning of the string
24
- if (path.startsWith("./")) {
25
- path = path.substring(2);
26
- } else if (path.startsWith("/")) {
27
- path = path.substring(1);
28
- }
29
21
 
30
- // Remove "/" at the end of the string if it exists
31
- if (path.endsWith("/")) {
32
- path = path.slice(0, -1);
33
- }
34
22
 
35
- return path;
23
+ // Simple path join utility for client-side JS (normalizes separators, handles leading/trailing /)
24
+ function pathJoin(...segments) {
25
+ // Filter out empty segments and join with '/'
26
+ return segments.filter(segment => segment).join('/').replace(/\/+/g, '/');
36
27
  }
37
28
 
38
- const cleanedSpecDir = cleanPath(specConfig.spec_directory);
39
-
40
- // Find all definition terms that have spans with the id of "term:...". These are the definitions we are looking for.
41
- document.querySelectorAll('dt:has(> span[id^="term:"])').forEach(item => {
29
+
30
+
31
+
32
+
33
+ document.querySelectorAll('dt.term-local').forEach(item => {
42
34
  const term = findDeepestSpan(item);
43
35
  const url = term.getAttribute('id');
44
36
 
37
+ const localFileName = url.split(":")[1];
38
+ const pathLocalTerms = pathJoin(specConfig.spec_directory, specConfig.spec_terms_directory, localFileName + '.md');
39
+
45
40
  // cut "url" on the ":" and keep the second part
46
- const fileName = url.split(":")[1];
41
+
47
42
  const branch = specConfig.source.branch || "main";
48
43
 
44
+
49
45
  // add edit and history buttons to term
50
46
  term.innerHTML += `<span class="edit-term-buttons">
51
47
  <a title="Link to the term file in the Github repo in a new tab" target="_blank" rel="noopener"
52
- href="https://github.com/${specConfig.source.account}/${specConfig.source.repo}/blob/${branch}/${cleanedSpecDir}/${specConfig.spec_terms_directory}/${fileName}.md"
48
+ href="https://github.com/${specConfig.source.account}/${specConfig.source.repo}/blob/${branch}/${pathLocalTerms}"
53
49
  class="p-1 edit-term-button btn">
54
50
  <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 16 16" style="shape-rendering: geometricPrecision;">
55
51
  <path fill-rule="evenodd" d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/>
56
52
  </svg>
57
53
  </a>
58
54
  <a title="Link to a GitHub page that shows a history of the edits in a new tab" target="_blank" rel="noopener"
59
- href="https://github.com/${specConfig.source.account}/${specConfig.source.repo}/commits/${branch}/${cleanedSpecDir}/${specConfig.spec_terms_directory}/${fileName}.md"
55
+ href="https://github.com/${specConfig.source.account}/${specConfig.source.repo}/commits/${branch}/${pathLocalTerms}"
60
56
  class="p-1 history-term-button btn">
61
57
  <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 16 16" style="shape-rendering: geometricPrecision;">
62
58
  <path fill-rule="evenodd" d="M8 1a7 7 0 1 0 4.95 11.95l.707.707A8.001 8.001 0 1 1 8 0v1z"/>
@@ -66,6 +62,67 @@ function editTermButtons() {
66
62
  </a>
67
63
  </span>`;
68
64
  });
65
+
66
+ // document.querySelectorAll('dt.term-external').forEach(item => {
67
+ // const term = findDeepestSpan(item);
68
+ // console.log("🚀 ~ editTermButtons ~ term:", term)
69
+ // const url = term.getAttribute('id');
70
+
71
+ // // Find the term in data-original-term attribute somewhere in a child of dt.term-external
72
+ // const originalTerm = term.dataset.originalTerm || url.split(":")[1];
73
+ // console.log("🚀 ~ editTermButtons ~ originalTerm:", originalTerm)
74
+
75
+ // // Lookup this term in the embedded allXTrefs object
76
+ // const matchingXtrefs = (allXTrefs?.xtrefs || []).filter(xref => xref.term === originalTerm);
77
+ // console.log("🚀 ~ editTermButtons ~ matchingXtrefs:", matchingXtrefs)
78
+
79
+ // if (matchingXtrefs.length > 0) {
80
+ // // Create edit and history buttons for each matching xtref
81
+ // const buttonsHtml = matchingXtrefs.map(xtref => {
82
+ // // Find sourceFiles with type "tref" - these are the files that define the term
83
+ // const trefFiles = xtref.sourceFiles?.filter(sf => sf.type === 'tref') || [];
84
+ // console.log("🚀 ~ editTermButtons ~ trefFiles:", trefFiles)
85
+
86
+ // if (trefFiles.length === 0) return '';
87
+
88
+ // // Find the corresponding repoUrl, terms_dir, branch from the xref
89
+ // const repoUrl = xtref.repoUrl;
90
+ // const termsDir = xtref.terms_dir;
91
+ // const branch = xtref.branch || "main";
92
+
93
+ // // Construct the edit pencil from that info
94
+ // return trefFiles.map(sf => {
95
+ // const filePath = pathJoin(termsDir, sf.file);
96
+ // console.log("🚀 ~ editTermButtons ~ filePath:", filePath)
97
+ // const editUrl = `${repoUrl}/blob/${branch}/${filePath}`;
98
+ // const historyUrl = `${repoUrl}/commits/${branch}/${filePath}`;
99
+
100
+ // return `
101
+ // <a title="Link to the term file '${sf.file}' in the Github repo in a new tab" target="_blank" rel="noopener"
102
+ // href="${editUrl}"
103
+ // class="p-1 edit-term-button btn">
104
+ // <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 16 16" style="shape-rendering: geometricPrecision;">
105
+ // <path fill-rule="evenodd" d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/>
106
+ // </svg>
107
+ // </a>
108
+ // <a title="Link to a GitHub page that shows a history of the edits in '${sf.file}' in a new tab" target="_blank" rel="noopener"
109
+ // href="${historyUrl}"
110
+ // class="p-1 history-term-button btn">
111
+ // <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 16 16" style="shape-rendering: geometricPrecision;">
112
+ // <path fill-rule="evenodd" d="M8 1a7 7 0 1 0 4.95 11.95l.707.707A8.001 8.001 0 1 1 8 0v1z"/>
113
+ // <path fill-rule="evenodd" d="M7.5 3a.5.5 0 0 1 .5.5v5.21l3.248 1.856a.5.5 0 0 1-.496.868l-3.5-2A.5.5 0 0 1 7 9V3.5a.5.5 0 0 1 .5-.5z"/>
114
+ // <circle cx="8" cy="8" r="0.3"/>
115
+ // </svg>
116
+ // </a>
117
+ // `;
118
+ // }).join('');
119
+ // }).join('');
120
+
121
+ // if (buttonsHtml) {
122
+ // term.innerHTML += `<span class="edit-term-buttons">${buttonsHtml}</span>`;
123
+ // }
124
+ // }
125
+ // });
69
126
  }
70
127
 
71
128
  document.addEventListener("DOMContentLoaded", function () {
@@ -0,0 +1,35 @@
1
+ (function () {
2
+ 'use strict';
3
+
4
+ /* GitHub Issues */
5
+
6
+ let source = specConfig.source;
7
+ if (source) {
8
+ if (source.host === 'github') {
9
+ fetch(`https://api.github.com/repos/${source.account + '/' + source.repo}/issues`)
10
+ .then(response => response.json())
11
+ .then(issues => {
12
+ let count = issues.length;
13
+ document.querySelectorAll('[issue-count]').forEach(node => {
14
+ node.setAttribute('issue-count', count)
15
+ });
16
+ repo_issue_list.innerHTML = issues.map(issue => {
17
+ return `<li class="repo-issue">
18
+ <detail-box>
19
+ <section>${md.render(issue.body || '')}</section>
20
+ <header class="repo-issue-title">
21
+ <span class="repo-issue-number">${issue.number}</span>
22
+ <span class="repo-issue-link">
23
+ <a href="${issue.html_url}" target="_blank">${issue.title}</a>
24
+ </span>
25
+ <span detail-box-toggle></span>
26
+ </header>
27
+ </detail-box>
28
+ </li>`
29
+ }).join('');
30
+ Prism.highlightAllUnder(repo_issue_list);
31
+ })
32
+ }
33
+ }
34
+
35
+ })();