create-asciidoc-multi-book-workspace 0.1.6 → 0.1.7
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/CHANGELOG.md +11 -0
- package/dist/runtime/adoc-books.mjs +100 -11
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.7 - 2026-06-13
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Add a `复制本书为纯文本` control to each generated book page so readers can copy the expanded single-file book text for saving, note-taking, or model analysis.
|
|
8
|
+
- Add a browser fallback that opens the expanded book text as a UTF-8 plain-text page when clipboard access is unavailable.
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Keep the generated book page controls self-contained by embedding the already-reduced book text in the HTML instead of adding another published source file.
|
|
13
|
+
|
|
3
14
|
## 0.1.6 - 2026-06-09
|
|
4
15
|
|
|
5
16
|
### Added
|
|
@@ -11,6 +11,7 @@ const ANCHOR_PATTERN = /^\[#([A-Za-z0-9_-]+)(?:[.,][^\]]*)?\]$/gm;
|
|
|
11
11
|
const LOCAL_TARGET_PATTERN = /\b(?:href|src)="([^"]+)"/g;
|
|
12
12
|
const SCHEME_PATTERN = /^[a-zA-Z][a-zA-Z0-9+.-]*:/;
|
|
13
13
|
const HOME_MARKER = "data-multi-book-home";
|
|
14
|
+
const CONTROLS_MARKER = "data-multi-book-controls";
|
|
14
15
|
const FETCH_DIAGRAMS_ENV = "ADOC_BOOKS_FETCH_DIAGRAMS";
|
|
15
16
|
const CONFIG_FILE = "adoc-books.config.mjs";
|
|
16
17
|
const DEFAULT_CONFIG = {
|
|
@@ -208,29 +209,35 @@ function escapeHtmlAttribute(value) {
|
|
|
208
209
|
.replaceAll("<", "<")
|
|
209
210
|
.replaceAll(">", ">");
|
|
210
211
|
}
|
|
211
|
-
function
|
|
212
|
-
|
|
212
|
+
function escapeJsonScript(value) {
|
|
213
|
+
return JSON.stringify(value)
|
|
214
|
+
.replaceAll("<", "\\u003c")
|
|
215
|
+
.replaceAll("\u2028", "\\u2028")
|
|
216
|
+
.replaceAll("\u2029", "\\u2029");
|
|
217
|
+
}
|
|
218
|
+
function addBookControlsToBookHtml(html, href, homeLink, bookSource) {
|
|
219
|
+
if (html.includes(CONTROLS_MARKER))
|
|
213
220
|
return html;
|
|
214
221
|
const marker = '<div id="toc" class="toc2">';
|
|
215
222
|
const index = html.indexOf(marker);
|
|
216
223
|
if (index === -1)
|
|
217
224
|
throw new Error("book HTML is missing the left TOC container");
|
|
218
225
|
const insertAt = index + marker.length;
|
|
219
|
-
const
|
|
226
|
+
const controlsBlock = `
|
|
220
227
|
<style>
|
|
221
|
-
.multi-book-
|
|
228
|
+
.multi-book-controls {
|
|
222
229
|
margin: 0 0 1rem;
|
|
223
230
|
padding-bottom: .75rem;
|
|
224
231
|
border-bottom: 1px solid #e5e7eb;
|
|
225
232
|
}
|
|
226
|
-
.multi-book-home
|
|
233
|
+
.multi-book-home {
|
|
227
234
|
color: #1f2937;
|
|
228
235
|
display: block;
|
|
229
236
|
font-weight: 600;
|
|
230
237
|
line-height: 1.35;
|
|
231
238
|
text-decoration: none;
|
|
232
239
|
}
|
|
233
|
-
.multi-book-home
|
|
240
|
+
.multi-book-home:hover {
|
|
234
241
|
color: #0f766e;
|
|
235
242
|
text-decoration: underline;
|
|
236
243
|
}
|
|
@@ -241,11 +248,92 @@ function addHomeLinkToBookHtml(html, href, homeLink) {
|
|
|
241
248
|
font-weight: 400;
|
|
242
249
|
margin-top: .15rem;
|
|
243
250
|
}
|
|
251
|
+
.multi-book-copy-source {
|
|
252
|
+
appearance: none;
|
|
253
|
+
background: #ffffff;
|
|
254
|
+
border: 1px solid #cbd5e1;
|
|
255
|
+
border-radius: 4px;
|
|
256
|
+
color: #1f2937;
|
|
257
|
+
cursor: pointer;
|
|
258
|
+
display: block;
|
|
259
|
+
font-size: .82rem;
|
|
260
|
+
font-weight: 600;
|
|
261
|
+
line-height: 1.2;
|
|
262
|
+
margin-top: .75rem;
|
|
263
|
+
padding: .42rem .5rem;
|
|
264
|
+
text-align: center;
|
|
265
|
+
width: 100%;
|
|
266
|
+
}
|
|
267
|
+
.multi-book-copy-source:hover,
|
|
268
|
+
.multi-book-copy-source:focus {
|
|
269
|
+
border-color: #0f766e;
|
|
270
|
+
color: #0f766e;
|
|
271
|
+
}
|
|
272
|
+
.multi-book-copy-status {
|
|
273
|
+
color: #64748b;
|
|
274
|
+
display: block;
|
|
275
|
+
font-size: .75rem;
|
|
276
|
+
line-height: 1.35;
|
|
277
|
+
margin-top: .4rem;
|
|
278
|
+
min-height: 1em;
|
|
279
|
+
}
|
|
244
280
|
</style>
|
|
245
|
-
<div class="multi-book-
|
|
246
|
-
<a href="${escapeHtmlAttribute(href)}">${escapeHtmlAttribute(homeLink.label)}<span>${escapeHtmlAttribute(homeLink.subtitle)}</span></a>
|
|
247
|
-
|
|
248
|
-
|
|
281
|
+
<div class="multi-book-controls" ${CONTROLS_MARKER}>
|
|
282
|
+
<a class="multi-book-home" ${HOME_MARKER} href="${escapeHtmlAttribute(href)}">${escapeHtmlAttribute(homeLink.label)}<span>${escapeHtmlAttribute(homeLink.subtitle)}</span></a>
|
|
283
|
+
<button type="button" class="multi-book-copy-source" data-multi-book-source-copy>复制本书为纯文本</button>
|
|
284
|
+
<span class="multi-book-copy-status" data-multi-book-source-status aria-live="polite"></span>
|
|
285
|
+
</div>
|
|
286
|
+
<script type="application/json" id="multi-book-source-data">${escapeJsonScript(bookSource)}</script>
|
|
287
|
+
<script>
|
|
288
|
+
(function () {
|
|
289
|
+
var sourceElement = document.getElementById("multi-book-source-data");
|
|
290
|
+
var button = document.querySelector("[data-multi-book-source-copy]");
|
|
291
|
+
var status = document.querySelector("[data-multi-book-source-status]");
|
|
292
|
+
if (!sourceElement || !button) return;
|
|
293
|
+
|
|
294
|
+
var source = "";
|
|
295
|
+
var fallbackMode = false;
|
|
296
|
+
try {
|
|
297
|
+
source = JSON.parse(sourceElement.textContent || '""');
|
|
298
|
+
} catch (error) {
|
|
299
|
+
if (status) status.textContent = "纯文本数据读取失败";
|
|
300
|
+
button.disabled = true;
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function setStatus(message) {
|
|
305
|
+
if (status) status.textContent = message;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function openSourcePage() {
|
|
309
|
+
var blob = new Blob([source], { type: "text/plain;charset=utf-8" });
|
|
310
|
+
var url = URL.createObjectURL(blob);
|
|
311
|
+
window.open(url, "_blank", "noopener");
|
|
312
|
+
setTimeout(function () { URL.revokeObjectURL(url); }, 60000);
|
|
313
|
+
setStatus("已尝试打开纯文本页;如果没有出现,请允许弹出窗口后再试");
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
button.addEventListener("click", async function () {
|
|
317
|
+
if (fallbackMode) {
|
|
318
|
+
openSourcePage();
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
try {
|
|
323
|
+
if (!navigator.clipboard || !navigator.clipboard.writeText) throw new Error("clipboard unavailable");
|
|
324
|
+
await navigator.clipboard.writeText(source);
|
|
325
|
+
button.textContent = "已复制";
|
|
326
|
+
setStatus("");
|
|
327
|
+
setTimeout(function () { button.textContent = "复制本书为纯文本"; }, 1800);
|
|
328
|
+
} catch (error) {
|
|
329
|
+
fallbackMode = true;
|
|
330
|
+
button.textContent = "打开纯文本页";
|
|
331
|
+
openSourcePage();
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
}());
|
|
335
|
+
</script>`;
|
|
336
|
+
return `${html.slice(0, insertAt)}${controlsBlock}${html.slice(insertAt)}`;
|
|
249
337
|
}
|
|
250
338
|
async function addHomeLinks(rootDir, books, homeLink) {
|
|
251
339
|
const catalog = path.join(rootDir, "build", "html", "catalog.html");
|
|
@@ -253,7 +341,8 @@ async function addHomeLinks(rootDir, books, homeLink) {
|
|
|
253
341
|
const htmlFile = path.join(book.htmlOutputDir, "book.html");
|
|
254
342
|
const html = await readFile(htmlFile, "utf8");
|
|
255
343
|
const href = path.relative(path.dirname(htmlFile), catalog);
|
|
256
|
-
await
|
|
344
|
+
const source = await readFile(path.join(rootDir, "build", "adoc", "books", `${book.bookId}.adoc`), "utf8");
|
|
345
|
+
await writeFile(htmlFile, addBookControlsToBookHtml(html, href, homeLink, source), "utf8");
|
|
257
346
|
}
|
|
258
347
|
}
|
|
259
348
|
async function writeRootIndex(rootDir, rootIndex) {
|