@hyperbook/markdown 0.21.0 → 0.22.1

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.
@@ -1,33 +1,61 @@
1
1
  var hyperbook = (function () {
2
- const collapsibles = document.getElementsByClassName("collapsible");
2
+ /**
3
+ * Initialize elements within the given root element.
4
+ * @param {HTMLElement} root - The root element to initialize.
5
+ */
6
+ const init = (root) => {
7
+ const collapsibles = root.getElementsByClassName("collapsible");
8
+ for (let collapsible of collapsibles) {
9
+ collapsible.addEventListener("click", () => {
10
+ const id = collapsible.parentElement.getAttribute("data-id");
11
+ collapsible.classList.toggle("expanded");
12
+ const expanded = collapsible.classList.contains("expanded");
13
+ if (id) {
14
+ [...collapsibles]
15
+ .filter((c) => c.parentElement.getAttribute("data-id") === id)
16
+ .forEach((c) => {
17
+ if (expanded) {
18
+ c.classList.add("expanded");
19
+ } else {
20
+ c.classList.remove("expanded");
21
+ }
22
+ });
23
+ }
24
+ });
25
+ }
3
26
 
4
- for (let collapsible of collapsibles) {
5
- collapsible.addEventListener("click", () => {
6
- collapsible.classList.toggle("expanded");
7
- });
8
- }
27
+ const searchInputEl = root.querySelector("#search-input");
28
+ if (searchInputEl) {
29
+ searchInputEl.addEventListener("keypress", (event) => {
30
+ if (event.key === "Enter") {
31
+ event.preventDefault();
32
+ search();
33
+ }
34
+ });
35
+ }
9
36
 
37
+ initBookmarks(root);
38
+ };
39
+
40
+ /**
41
+ * Toggle the table of contents drawer.
42
+ */
10
43
  function tocToggle() {
11
44
  const tocDrawerEl = document.getElementById("toc-drawer");
12
45
  tocDrawerEl.open = !tocDrawerEl.open;
13
46
  }
14
- // search
15
-
16
- const searchInputEl = document.getElementById("search-input");
17
- if (searchInputEl) {
18
- searchInputEl.addEventListener("keypress", (event) => {
19
- if (event.key === "Enter") {
20
- event.preventDefault();
21
- search();
22
- }
23
- });
24
- }
25
47
 
48
+ /**
49
+ * Toggle the search drawer.
50
+ */
26
51
  function searchToggle() {
27
52
  const searchDrawerEl = document.getElementById("search-drawer");
28
53
  searchDrawerEl.open = !searchDrawerEl.open;
29
54
  }
30
55
 
56
+ /**
57
+ * Perform a search and display the results.
58
+ */
31
59
  function search() {
32
60
  const resultsEl = document.getElementById("search-results");
33
61
  resultsEl.innerHTML = "";
@@ -83,6 +111,9 @@ var hyperbook = (function () {
83
111
  }
84
112
  }
85
113
 
114
+ /**
115
+ * Open the QR code dialog.
116
+ */
86
117
  function qrcodeOpen() {
87
118
  const qrCodeDialog = document.getElementById("qrcode-dialog");
88
119
  const qrcodeEls = qrCodeDialog.getElementsByClassName("make-qrcode");
@@ -106,19 +137,26 @@ var hyperbook = (function () {
106
137
  qrCodeDialog.showModal();
107
138
  }
108
139
 
140
+ /**
141
+ * Close the QR code dialog.
142
+ */
109
143
  function qrcodeClose() {
110
144
  const qrCodeDialog = document.getElementById("qrcode-dialog");
111
145
  qrCodeDialog.close();
112
146
  }
113
147
 
148
+ /**
149
+ * Toggle the navigation drawer.
150
+ */
114
151
  function navToggle() {
115
152
  const navDrawerEl = document.getElementById("nav-drawer");
116
153
  navDrawerEl.open = !navDrawerEl.open;
117
154
  }
118
155
 
119
156
  /**
120
- * @param {string} key
121
- * @param {string} label
157
+ * Toggle a bookmark.
158
+ * @param {string} key - The key of the bookmark.
159
+ * @param {string} label - The label of the bookmark.
122
160
  */
123
161
  function toggleBookmark(key, label) {
124
162
  const bookmarks = JSON.parse(localStorage.getItem("bookmarks") || "{}");
@@ -137,8 +175,12 @@ var hyperbook = (function () {
137
175
  }
138
176
  }
139
177
 
140
- function initBookmarks() {
141
- const bookmarkEls = document.getElementsByClassName("bookmark");
178
+ /**
179
+ * Initialize bookmarks within the given root element.
180
+ * @param {HTMLElement} [root=document] - The root element to initialize.
181
+ */
182
+ function initBookmarks(root = document) {
183
+ const bookmarkEls = root.getElementsByClassName("bookmark");
142
184
  const bookmarks = JSON.parse(localStorage.getItem("bookmarks") || "{}");
143
185
  for (let bookmarkEl of bookmarkEls) {
144
186
  const key = bookmarkEl.getAttribute("data-key");
@@ -147,15 +189,35 @@ var hyperbook = (function () {
147
189
  }
148
190
  }
149
191
  }
150
- initBookmarks();
151
192
 
152
193
  /**
153
- * @param {HTMLElement} el
194
+ * Toggle the lightbox view of an element.
195
+ * @param {HTMLElement} el - The element to toggle.
154
196
  */
155
197
  function toggleLightbox(el) {
156
198
  el.parentElement.classList.toggle("lightbox");
157
199
  el.parentElement.classList.toggle("normal");
158
200
  }
201
+
202
+ // Initialize existing elements on document load
203
+ document.addEventListener("DOMContentLoaded", () => {
204
+ init(document);
205
+ });
206
+
207
+ // Observe for new elements added to the DOM
208
+ const observer = new MutationObserver((mutations) => {
209
+ mutations.forEach((mutation) => {
210
+ mutation.addedNodes.forEach((node) => {
211
+ if (node.nodeType === 1) {
212
+ // Element node
213
+ init(node);
214
+ }
215
+ });
216
+ });
217
+ });
218
+
219
+ observer.observe(document.body, { childList: true, subtree: true });
220
+
159
221
  return {
160
222
  toggleLightbox,
161
223
  toggleBookmark,
@@ -165,5 +227,6 @@ var hyperbook = (function () {
165
227
  search,
166
228
  qrcodeOpen,
167
229
  qrcodeClose,
230
+ init,
168
231
  };
169
232
  })();
@@ -182,4 +182,21 @@ code[data-line-numbers-max-digits="4"]>[data-line]::before {
182
182
 
183
183
  code-input:not(.code-input_registered)::before {
184
184
  content: "..."!important;
185
+ }
186
+
187
+ /**
188
+ * Allows code-input elements to be used with the Prism.js line-numbers plugin, as long as the code-input element
189
+ * or a parent element of it has the CSS class `line-numbers`.
190
+ * https://prismjs.com/plugins/line-numbers/
191
+ * Files: prism-line-numbers.css
192
+ */
193
+ /* Update padding to match line-numbers plugin */
194
+ code-input.line-numbers textarea, code-input.line-numbers.code-input_pre-element-styled pre,
195
+ .line-numbers code-input textarea, .line-numbers code-input.code-input_pre-element-styled pre {
196
+ padding-left: max(3.8em, var(--padding, 16px))!important;
197
+ }
198
+
199
+ /* Ensure pre code/textarea just wide enough to give 100% width with line numbers */
200
+ code-input.line-numbers, .line-numbers code-input {
201
+ grid-template-columns: calc(100% - max(0em, calc(3.8em - var(--padding, 16px))));
185
202
  }
@@ -1,5 +1,4 @@
1
1
  hyperbook.abc = (function () {
2
- const els = document.querySelectorAll(".directive-abc-music");
3
2
  window.codeInput?.registerTemplate(
4
3
  "abc-highlighted",
5
4
  codeInput.templates.prism(window.Prism, [
@@ -7,7 +6,7 @@ hyperbook.abc = (function () {
7
6
  ])
8
7
  );
9
8
 
10
- for (let el of els) {
9
+ const initABC = (el) => {
11
10
  const tuneEl = el.getElementsByClassName("tune")[0];
12
11
  const playerEl = el.getElementsByClassName("player")[0];
13
12
 
@@ -60,5 +59,32 @@ hyperbook.abc = (function () {
60
59
  "<div class='audio-error'>Audio is not supported in this browser.</div>";
61
60
  }
62
61
  }
63
- }
64
- })();
62
+ };
63
+
64
+ const init = (root) => {
65
+ const els = root.querySelectorAll(".directive-abc-music");
66
+ els.forEach(initABC);
67
+ };
68
+
69
+ // Initialize existing elements on document load
70
+ document.addEventListener("DOMContentLoaded", () => {
71
+ init(document);
72
+ });
73
+
74
+ // Observe for new elements added to the DOM
75
+ const observer = new MutationObserver((mutations) => {
76
+ mutations.forEach((mutation) => {
77
+ mutation.addedNodes.forEach((node) => {
78
+ if (node.nodeType === 1 && node.classList.contains("directive-abc-music")) {
79
+ initABC(node);
80
+ }
81
+ });
82
+ });
83
+ });
84
+
85
+ observer.observe(document.body, { childList: true, subtree: true });
86
+
87
+ return {
88
+ init,
89
+ };
90
+ })();
@@ -1,23 +1,40 @@
1
1
  hyperbook.download = (function () {
2
+ function initElement(el) {
3
+ const labelEl = el.getElementsByClassName("label")[0];
4
+ const src = el.href;
5
+
6
+ fetch(src).then((r) => {
7
+ const isOnline = r.ok;
8
+ if (isOnline) {
9
+ labelEl.classList.remove("offline");
10
+ labelEl.innerHTML = labelEl.innerHTML.replace("(Offline)", "");
11
+ } else {
12
+ labelEl.classList.add("offline");
13
+ labelEl.innerHTML += " (Offline)";
14
+ }
15
+ });
16
+ }
17
+
2
18
  function init() {
3
19
  const els = document.getElementsByClassName("directive-archive");
4
20
  for (let el of els) {
5
- const labelEl = el.getElementsByClassName("label")[0];
6
-
7
- const src = el.href;
21
+ initElement(el);
22
+ }
23
+ }
8
24
 
9
- fetch(src).then((r) => {
10
- const isOnline = r.ok;
11
- if (isOnline) {
12
- labelEl.classList.remove("offline");
13
- labelEl.innerHTML.replace("(Offline)", "");
14
- } else {
15
- labelEl.classList.add("offline");
16
- labelEl.innerHTML += " (Offline)";
25
+ const observer = new MutationObserver((mutations) => {
26
+ for (let mutation of mutations) {
27
+ if (mutation.type === "childList") {
28
+ for (let node of mutation.addedNodes) {
29
+ if (node.classList && node.classList.contains("directive-archive")) {
30
+ initElement(node);
31
+ }
17
32
  }
18
- });
33
+ }
19
34
  }
20
- }
35
+ });
36
+
37
+ observer.observe(document.body, { childList: true, subtree: true });
21
38
 
22
39
  init();
23
40
  })();
@@ -1,13 +1,13 @@
1
1
  hyperbook.bookmarks = (function () {
2
- function update() {
2
+ function update(root = document) {
3
3
  const bookmarks = JSON.parse(localStorage.getItem("bookmarks") || "{}");
4
4
 
5
- const containerEls = document.getElementsByClassName("directive-bookmarks");
5
+ const containerEls = root.getElementsByClassName("directive-bookmarks");
6
6
  for (let containerEl of containerEls) {
7
7
  const elements = [];
8
8
  Object.entries(bookmarks).forEach(([key, label]) => {
9
- const bookmarkEl = document.createElement("li");
10
- const link = document.createElement("a");
9
+ const bookmarkEl = root.createElement("li");
10
+ const link = root.createElement("a");
11
11
  link.href = key;
12
12
  link.innerHTML = label;
13
13
  bookmarkEl.append(link);
@@ -16,7 +16,24 @@ hyperbook.bookmarks = (function () {
16
16
  containerEl.replaceChildren(...elements);
17
17
  }
18
18
  }
19
- update();
19
+
20
+ // Initialize existing elements on document load
21
+ document.addEventListener("DOMContentLoaded", () => {
22
+ update(document);
23
+ });
24
+
25
+ // Observe for new elements added to the DOM
26
+ const observer = new MutationObserver((mutations) => {
27
+ mutations.forEach((mutation) => {
28
+ mutation.addedNodes.forEach((node) => {
29
+ if (node.nodeType === 1 && node.classList.contains("directive-bookmarks")) { // Element node
30
+ update(node);
31
+ }
32
+ });
33
+ });
34
+ });
35
+
36
+ observer.observe(document.body, { childList: true, subtree: true });
20
37
 
21
38
  return {
22
39
  update,
@@ -1,6 +1,6 @@
1
1
  hyperbook.download = (function () {
2
- function init() {
3
- const els = document.getElementsByClassName("directive-download");
2
+ const init = (root) => {
3
+ const els = root.getElementsByClassName("directive-download");
4
4
  for (let el of els) {
5
5
  const labelEl = el.getElementsByClassName("label")[0];
6
6
 
@@ -17,7 +17,27 @@ hyperbook.download = (function () {
17
17
  }
18
18
  });
19
19
  }
20
- }
20
+ };
21
21
 
22
- init();
22
+ // Initialize existing elements on document load
23
+ document.addEventListener("DOMContentLoaded", () => {
24
+ init(document);
25
+ });
26
+
27
+ // Observe for new elements added to the DOM
28
+ const observer = new MutationObserver((mutations) => {
29
+ mutations.forEach((mutation) => {
30
+ mutation.addedNodes.forEach((node) => {
31
+ if (node.nodeType === 1) { // Element node
32
+ init(node);
33
+ }
34
+ });
35
+ });
36
+ });
37
+
38
+ observer.observe(document.body, { childList: true, subtree: true });
39
+
40
+ return {
41
+ init,
42
+ };
23
43
  })();
@@ -1,9 +1,11 @@
1
1
  hyperbook.mermaid = (function () {
2
2
  const elementCode = ".directive-mermaid";
3
+
3
4
  const loadMermaid = function (theme) {
4
5
  window.mermaid.initialize({ theme });
5
6
  window.mermaid.init({ theme }, document.querySelectorAll(elementCode));
6
7
  };
8
+
7
9
  const resetProcessed = function () {
8
10
  return new Promise((resolve, reject) => {
9
11
  try {
@@ -35,19 +37,54 @@ hyperbook.mermaid = (function () {
35
37
  const init = () => {
36
38
  const toggle = document.querySelector("dark-mode-toggle");
37
39
  if (toggle?.mode == "dark") {
38
- resetProcessed().then(loadMermaid("dark")).catch(console.error);
40
+ resetProcessed()
41
+ .then(() => loadMermaid("dark"))
42
+ .catch(console.error);
39
43
  } else {
40
- resetProcessed().then(loadMermaid("default")).catch(console.error);
44
+ resetProcessed()
45
+ .then(() => loadMermaid("default"))
46
+ .catch(console.error);
41
47
  }
42
48
 
43
49
  document.addEventListener("colorschemechange", (e) => {
44
50
  if (e.detail.colorScheme === "dark") {
45
- resetProcessed().then(loadMermaid("dark")).catch(console.error);
51
+ resetProcessed()
52
+ .then(() => loadMermaid("dark"))
53
+ .catch(console.error);
46
54
  } else {
47
- resetProcessed().then(loadMermaid("default")).catch(console.error);
55
+ resetProcessed()
56
+ .then(() => loadMermaid("default"))
57
+ .catch(console.error);
48
58
  }
49
59
  });
50
60
  };
51
61
 
52
62
  init();
63
+
64
+ // Observe for new elements added to the DOM
65
+ const observer = new MutationObserver((mutations) => {
66
+ mutations.forEach((mutation) => {
67
+ mutation.addedNodes.forEach((node) => {
68
+ if (node.nodeType === 1 && node.hasAttribute("data-mermaid")) {
69
+ // Element node
70
+ const toggle = document.querySelector("dark-mode-toggle");
71
+ if (toggle?.mode == "dark") {
72
+ resetProcessed()
73
+ .then(() => loadMermaid("dark"))
74
+ .catch(console.error);
75
+ } else {
76
+ resetProcessed()
77
+ .then(() => loadMermaid("default"))
78
+ .catch(console.error);
79
+ }
80
+ }
81
+ });
82
+ });
83
+ });
84
+
85
+ observer.observe(document.body, { childList: true, subtree: true });
86
+
87
+ return {
88
+ init,
89
+ };
53
90
  })();
@@ -56,8 +56,12 @@ hyperbook.protect = (function () {
56
56
  localStorage.setItem("protect", JSON.stringify(protect));
57
57
  }
58
58
 
59
- function init() {
60
- const els = document.getElementsByClassName("directive-protect");
59
+ /**
60
+ * Initialize elements within the given root element.
61
+ * @param {HTMLElement} root - The root element to initialize.
62
+ */
63
+ function init(root) {
64
+ const els = root.getElementsByClassName("directive-protect");
61
65
  for (let el of els) {
62
66
  const inputEl = el.getElementsByTagName("input")[0];
63
67
 
@@ -75,5 +79,25 @@ hyperbook.protect = (function () {
75
79
  }
76
80
  }
77
81
 
78
- init();
82
+ // Initialize existing elements on document load
83
+ document.addEventListener("DOMContentLoaded", () => {
84
+ init(document);
85
+ });
86
+
87
+ // Observe for new elements added to the DOM
88
+ const observer = new MutationObserver((mutations) => {
89
+ mutations.forEach((mutation) => {
90
+ mutation.addedNodes.forEach((node) => {
91
+ if (node.nodeType === 1) { // Element node
92
+ init(node);
93
+ }
94
+ });
95
+ });
96
+ });
97
+
98
+ observer.observe(document.body, { childList: true, subtree: true });
99
+
100
+ return {
101
+ init,
102
+ };
79
103
  })();