@fiduswriter/books-document 0.1.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.
Files changed (125) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +24 -0
  3. package/dist/exporter/bits/index.d.ts +42 -0
  4. package/dist/exporter/bits/index.d.ts.map +1 -0
  5. package/dist/exporter/bits/index.js +98 -0
  6. package/dist/exporter/bits/index.js.map +1 -0
  7. package/dist/exporter/bits/templates.d.ts +7 -0
  8. package/dist/exporter/bits/templates.d.ts.map +1 -0
  9. package/dist/exporter/bits/templates.js +78 -0
  10. package/dist/exporter/bits/templates.js.map +1 -0
  11. package/dist/exporter/docx/index.d.ts +27 -0
  12. package/dist/exporter/docx/index.d.ts.map +1 -0
  13. package/dist/exporter/docx/index.js +129 -0
  14. package/dist/exporter/docx/index.js.map +1 -0
  15. package/dist/exporter/docx/render.d.ts +14 -0
  16. package/dist/exporter/docx/render.d.ts.map +1 -0
  17. package/dist/exporter/docx/render.js +116 -0
  18. package/dist/exporter/docx/render.js.map +1 -0
  19. package/dist/exporter/epub/index.d.ts +65 -0
  20. package/dist/exporter/epub/index.d.ts.map +1 -0
  21. package/dist/exporter/epub/index.js +268 -0
  22. package/dist/exporter/epub/index.js.map +1 -0
  23. package/dist/exporter/epub/templates.d.ts +65 -0
  24. package/dist/exporter/epub/templates.d.ts.map +1 -0
  25. package/dist/exporter/epub/templates.js +223 -0
  26. package/dist/exporter/epub/templates.js.map +1 -0
  27. package/dist/exporter/epub/tools.d.ts +5 -0
  28. package/dist/exporter/epub/tools.d.ts.map +1 -0
  29. package/dist/exporter/epub/tools.js +59 -0
  30. package/dist/exporter/epub/tools.js.map +1 -0
  31. package/dist/exporter/html/index.d.ts +67 -0
  32. package/dist/exporter/html/index.d.ts.map +1 -0
  33. package/dist/exporter/html/index.js +300 -0
  34. package/dist/exporter/html/index.js.map +1 -0
  35. package/dist/exporter/html/templates.d.ts +40 -0
  36. package/dist/exporter/html/templates.d.ts.map +1 -0
  37. package/dist/exporter/html/templates.js +226 -0
  38. package/dist/exporter/html/templates.js.map +1 -0
  39. package/dist/exporter/html/tools.d.ts +2 -0
  40. package/dist/exporter/html/tools.d.ts.map +1 -0
  41. package/dist/exporter/html/tools.js +23 -0
  42. package/dist/exporter/html/tools.js.map +1 -0
  43. package/dist/exporter/latex/index.d.ts +32 -0
  44. package/dist/exporter/latex/index.d.ts.map +1 -0
  45. package/dist/exporter/latex/index.js +102 -0
  46. package/dist/exporter/latex/index.js.map +1 -0
  47. package/dist/exporter/latex/templates.d.ts +4 -0
  48. package/dist/exporter/latex/templates.d.ts.map +1 -0
  49. package/dist/exporter/latex/templates.js +26 -0
  50. package/dist/exporter/latex/templates.js.map +1 -0
  51. package/dist/exporter/native/index.d.ts +20 -0
  52. package/dist/exporter/native/index.d.ts.map +1 -0
  53. package/dist/exporter/native/index.js +109 -0
  54. package/dist/exporter/native/index.js.map +1 -0
  55. package/dist/exporter/odt/index.d.ts +27 -0
  56. package/dist/exporter/odt/index.d.ts.map +1 -0
  57. package/dist/exporter/odt/index.js +123 -0
  58. package/dist/exporter/odt/index.js.map +1 -0
  59. package/dist/exporter/odt/render.d.ts +15 -0
  60. package/dist/exporter/odt/render.d.ts.map +1 -0
  61. package/dist/exporter/odt/render.js +119 -0
  62. package/dist/exporter/odt/render.js.map +1 -0
  63. package/dist/exporter/print/index.d.ts +24 -0
  64. package/dist/exporter/print/index.d.ts.map +1 -0
  65. package/dist/exporter/print/index.js +60 -0
  66. package/dist/exporter/print/index.js.map +1 -0
  67. package/dist/exporter/print/templates.d.ts +2 -0
  68. package/dist/exporter/print/templates.d.ts.map +1 -0
  69. package/dist/exporter/print/templates.js +5 -0
  70. package/dist/exporter/print/templates.js.map +1 -0
  71. package/dist/exporter/tools.d.ts +29 -0
  72. package/dist/exporter/tools.d.ts.map +1 -0
  73. package/dist/exporter/tools.js +151 -0
  74. package/dist/exporter/tools.js.map +1 -0
  75. package/dist/i18n.d.ts +7 -0
  76. package/dist/i18n.d.ts.map +1 -0
  77. package/dist/i18n.js +918 -0
  78. package/dist/i18n.js.map +1 -0
  79. package/dist/importer/native/index.d.ts +34 -0
  80. package/dist/importer/native/index.d.ts.map +1 -0
  81. package/dist/importer/native/index.js +152 -0
  82. package/dist/importer/native/index.js.map +1 -0
  83. package/dist/importer/native/reader.d.ts +26 -0
  84. package/dist/importer/native/reader.d.ts.map +1 -0
  85. package/dist/importer/native/reader.js +105 -0
  86. package/dist/importer/native/reader.js.map +1 -0
  87. package/dist/index.d.ts +3 -0
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/index.js +2 -0
  90. package/dist/index.js.map +1 -0
  91. package/dist/schema/index.d.ts +4 -0
  92. package/dist/schema/index.d.ts.map +1 -0
  93. package/dist/schema/index.js +4 -0
  94. package/dist/schema/index.js.map +1 -0
  95. package/dist/types.d.ts +151 -0
  96. package/dist/types.d.ts.map +1 -0
  97. package/dist/types.js +5 -0
  98. package/dist/types.js.map +1 -0
  99. package/package.json +101 -0
  100. package/src/exporter/bits/index.ts +163 -0
  101. package/src/exporter/bits/templates.ts +107 -0
  102. package/src/exporter/docx/index.ts +239 -0
  103. package/src/exporter/docx/render.ts +142 -0
  104. package/src/exporter/epub/index.ts +426 -0
  105. package/src/exporter/epub/templates.ts +401 -0
  106. package/src/exporter/epub/tools.ts +68 -0
  107. package/src/exporter/html/index.ts +443 -0
  108. package/src/exporter/html/templates.ts +363 -0
  109. package/src/exporter/html/tools.ts +26 -0
  110. package/src/exporter/latex/index.ts +161 -0
  111. package/src/exporter/latex/templates.ts +35 -0
  112. package/src/exporter/native/index.ts +187 -0
  113. package/src/exporter/odt/index.ts +211 -0
  114. package/src/exporter/odt/render.ts +146 -0
  115. package/src/exporter/print/index.ts +92 -0
  116. package/src/exporter/print/templates.ts +8 -0
  117. package/src/exporter/tools.ts +233 -0
  118. package/src/global.d.ts +2 -0
  119. package/src/i18n.ts +936 -0
  120. package/src/importer/native/index.ts +233 -0
  121. package/src/importer/native/reader.ts +165 -0
  122. package/src/index.ts +19 -0
  123. package/src/modules.d.ts +11 -0
  124. package/src/schema/index.ts +4 -0
  125. package/src/types.ts +188 -0
@@ -0,0 +1,363 @@
1
+ import {escapeText, localizeDate} from "fwtoolkit"
2
+
3
+ import type {Book} from "../../types.js"
4
+ import {bookTerm} from "../../i18n.js"
5
+
6
+ export const htmlBookChapterTemplate = ({body, back}: Record<string, unknown>) =>
7
+ `${body}${back}`
8
+
9
+ interface HtmlBookExportParams {
10
+ styleSheets: Array<{filename: string}>
11
+ part?: string
12
+ currentPart?: string
13
+ contents: string
14
+ title: string
15
+ settings: Record<string, string>
16
+ }
17
+
18
+ /** A template for HTML export of a book. */
19
+ export const htmlBookExportTemplate = ({
20
+ styleSheets,
21
+ part,
22
+ currentPart,
23
+ contents,
24
+ title,
25
+ settings
26
+ }: HtmlBookExportParams) =>
27
+ `<!DOCTYPE html>
28
+ <html lang="${settings.language.split("-")[0]}">
29
+ <head>
30
+ <meta charset="UTF-8">
31
+ <title>${title}</title>
32
+ ${styleSheets
33
+ .map(
34
+ sheet =>
35
+ `<link type="text/css" rel="stylesheet" href="${sheet.filename}" />`
36
+ )
37
+ .join("")}
38
+ </head>
39
+ <body class="user-contents book-chapter${
40
+ currentPart?.length
41
+ ? ` ${currentPart.toLowerCase().replace(/[^a-z]/g, "")}`
42
+ : ""
43
+ }">
44
+ ${
45
+ part?.length
46
+ ? `<h1 class="part">${escapeText(part)}</h1>`
47
+ : ""
48
+ }
49
+ ${contents}
50
+ </body>
51
+ </html>`
52
+
53
+ /** A template to create the book index item. */
54
+ const htmlBookIndexItemTemplate = ({
55
+ item,
56
+ multiDoc
57
+ }: {
58
+ item: Record<string, unknown>
59
+ multiDoc: boolean
60
+ }): string =>
61
+ `<li>
62
+ <a href="${
63
+ item.link
64
+ ? item.link
65
+ : multiDoc
66
+ ? item.docNum
67
+ ? `document-${item.docNum}.html#${item.id}`
68
+ : `document.html#${item.id}`
69
+ : `#${item.id}`
70
+ }">
71
+ ${escapeText(item.title as string)}
72
+ </a>
73
+ ${
74
+ (item.subItems as Array<Record<string, unknown>>)?.length
75
+ ? `<ol>
76
+ ${(item.subItems as Array<Record<string, unknown>>)
77
+ .map(subItem =>
78
+ htmlBookIndexItemTemplate({item: subItem, multiDoc})
79
+ )
80
+ .join("")}
81
+ </ol>`
82
+ : ""
83
+ }
84
+ </li>`
85
+
86
+ interface HtmlBookIndexBodyParams {
87
+ book: Book
88
+ contentItems: Array<Record<string, unknown>>
89
+ language: string
90
+ creator: string
91
+ multiDoc: boolean
92
+ }
93
+
94
+ /** A template to create the book index. */
95
+ export const htmlBookIndexBodyTemplate = ({
96
+ book,
97
+ contentItems,
98
+ language,
99
+ creator,
100
+ multiDoc
101
+ }: HtmlBookIndexBodyParams) =>
102
+ `<div class="titlepage frontmatter">
103
+ <h1 class="booktitle">${escapeText(book.title)}</h1>
104
+ ${
105
+ book.metadata.subtitle?.length
106
+ ? `<h2 class="booksubtitle">${escapeText(book.metadata.subtitle)}</h2>`
107
+ : ""
108
+ }
109
+ ${
110
+ book.metadata.author?.length
111
+ ? `<h3 class="bookauthor">${bookTerm(
112
+ "by",
113
+ book.settings.language
114
+ )} ${escapeText(book.metadata.author)}</h3>`
115
+ : ""
116
+ }
117
+ ${
118
+ book.metadata.version?.length
119
+ ? `<h4 class="bookversion">${escapeText(book.metadata.version)}</h4>`
120
+ : ""
121
+ }
122
+ ${
123
+ book.metadata.series_title?.length
124
+ ? `<p class="bookseries">${escapeText(book.metadata.series_title)}${
125
+ book.metadata.series_position?.length
126
+ ? ` \u2013 ${bookTerm("Series position", book.settings.language)} ${escapeText(book.metadata.series_position)}`
127
+ : ""
128
+ }</p>`
129
+ : ""
130
+ }
131
+ </div>
132
+ <div class="copyrightpage frontmatter">
133
+ ${
134
+ book.metadata.publisher?.length
135
+ ? `<p>${bookTerm(
136
+ "Published by",
137
+ book.settings.language
138
+ )}: ${escapeText(book.metadata.publisher)}</p>`
139
+ : ""
140
+ }
141
+ ${
142
+ book.metadata.isbn?.length
143
+ ? `<p>${bookTerm("ISBN", book.settings.language)}: ${escapeText(book.metadata.isbn)}</p>`
144
+ : ""
145
+ }
146
+ ${
147
+ book.metadata.publication_date?.length
148
+ ? `<p>${bookTerm("Publication date", book.settings.language)}: ${escapeText(book.metadata.publication_date)}</p>`
149
+ : ""
150
+ }
151
+ ${
152
+ book.metadata.series_title?.length
153
+ ? `<p>${bookTerm("Series", book.settings.language)}: ${escapeText(book.metadata.series_title)}${
154
+ book.metadata.series_position?.length
155
+ ? ` (${bookTerm("Series position", book.settings.language)}: ${escapeText(book.metadata.series_position)})`
156
+ : ""
157
+ }</p>`
158
+ : ""
159
+ }
160
+ ${
161
+ book.metadata.description?.length
162
+ ? `<p class="book-description">${escapeText(book.metadata.description).replace(/\n/g, "<br>")}</p>`
163
+ : ""
164
+ }
165
+ <p>${bookTerm("Last updated", book.settings.language)}: ${localizeDate(
166
+ (book.updated || 0) * 1000,
167
+ "sortable-date"
168
+ )}</p>
169
+ <p>${bookTerm("Created", book.settings.language)}: ${localizeDate(
170
+ (book.added || 0) * 1000,
171
+ "sortable-date"
172
+ )}</p>
173
+ <p>${bookTerm("Language", book.settings.language)}: ${language}</p>
174
+ <p>${bookTerm("Created by", book.settings.language)}: ${escapeText(
175
+ creator
176
+ )}</p>
177
+ </div>
178
+ <div class="tocpage frontmatter">
179
+ <nav role="doc-toc"><ol>
180
+ ${contentItems
181
+ .map(item => htmlBookIndexItemTemplate({item, multiDoc}))
182
+ .join("")}
183
+ </ol></nav>
184
+ </div>`
185
+
186
+ interface HtmlBookIndexParams {
187
+ book: Book
188
+ contentItems: Array<Record<string, unknown>>
189
+ language: string
190
+ creator: string
191
+ styleSheets: Array<{filename: string}>
192
+ multiDoc: boolean
193
+ }
194
+
195
+ /** A template to create the book index. */
196
+ export const htmlBookIndexTemplate = ({
197
+ book,
198
+ contentItems,
199
+ language,
200
+ creator,
201
+ styleSheets,
202
+ multiDoc
203
+ }: HtmlBookIndexParams) =>
204
+ `<!DOCTYPE html>
205
+ <html lang="${book.settings.language.split("-")[0]}">
206
+ <head>
207
+ <meta charset="utf-8"></meta>
208
+ ${
209
+ book.metadata.description
210
+ ? `<meta name="description" content="${escapeText(book.metadata.description.replace(/\n/g, " "))}">`
211
+ : ""
212
+ }
213
+ <title>${escapeText(book.title)}</title>
214
+ <link type="text/css" rel="stylesheet" href="css/book.css" />
215
+ ${styleSheets
216
+ .map(
217
+ sheet =>
218
+ `<link type="text/css" rel="stylesheet" href="${sheet.filename}" />`
219
+ )
220
+ .join("")}
221
+ </head>
222
+ <body class="user-contents book-index">
223
+ ${htmlBookIndexBodyTemplate({
224
+ book,
225
+ contentItems,
226
+ language,
227
+ creator,
228
+ multiDoc
229
+ })}
230
+ </body>
231
+ </html>`
232
+
233
+ export const singleFileHTMLBookChapterTemplate = ({
234
+ part,
235
+ contents
236
+ }: Record<string, unknown>) => `
237
+ ${part && (part as string).length ? `<h1 class="part">${escapeText(part as string)}</h1>` : ""}
238
+ ${contents}`
239
+
240
+ export const singleFileHTMLBookTemplate = ({
241
+ css,
242
+ html,
243
+ title,
244
+ styleSheets,
245
+ settings
246
+ }: Record<string, unknown>) => `<!DOCTYPE html>
247
+ <html lang="${(settings as Record<string, string>).language.split("-")[0]}">
248
+ <head>
249
+ <meta charset="UTF-8">
250
+ <title>${title}</title>
251
+ <style>
252
+ ${css}
253
+ </style>
254
+ ${(styleSheets as Array<{filename?: string; contents?: string}>)
255
+ .map(sheet =>
256
+ sheet.filename
257
+ ? `<link type="text/css" rel="stylesheet" href="${sheet.filename}" />`
258
+ : sheet.contents
259
+ ? `<style>${sheet.contents}</style>`
260
+ : ""
261
+ )
262
+ .join("")}
263
+ </head>
264
+ <body>
265
+ <div class="user-contents" id="flow">
266
+ ${html}
267
+ </div>
268
+ </body>
269
+ </html>`
270
+
271
+ const CSS_PAPER_SIZES: Record<string, string> = {
272
+ folio: "12in 15in",
273
+ quarto: "9.5in 12in",
274
+ octavo: "6in 9in",
275
+ a5: "A5",
276
+ a4: "A4"
277
+ }
278
+
279
+ export const singleFileHTMLBookCSSTemplate = ({
280
+ papersize
281
+ }: Record<string, unknown>) =>
282
+ `a.fn {
283
+ -adapt-template: url(data:application/xml,${encodeURI(
284
+ '<html xmlns="http://www.w3.org/1999/xhtml" xmlns:s="http://www.pyroxy.com/ns/shadow"><head><style>.footnote-content{float:footnote}</style></head><body><s:template id="footnote"><s:content/><s:include class="footnote-content"/></s:template></body></html>#footnote'
285
+ )});
286
+ text-decoration: none;
287
+ color: inherit;
288
+ vertical-align: baseline;
289
+ font-size: 70%;
290
+ position: relative;
291
+ top: -0.3em;
292
+
293
+ }
294
+ body {
295
+ background-color: white;
296
+ }
297
+ section[role=doc-footnote] .footnote-counter:after {
298
+ content: ". ";
299
+ }
300
+ section.fnlist {
301
+ display: none;
302
+ }
303
+ section:footnote-content {
304
+ display: block;
305
+ font-style:normal;
306
+ font-weight:normal;
307
+ text-decoration:none;
308
+ }
309
+ .table-of-contents a {
310
+ display: inline-flex;
311
+ width: 100%;
312
+ text-decoration: none;
313
+ color: currentColor;
314
+ break-inside: avoid;
315
+ align-items: baseline;
316
+ }
317
+ .table-of-contents a::before {
318
+ margin-left: 1px;
319
+ margin-right: 1px;
320
+ border-bottom: solid 1px lightgray;
321
+ content: "";
322
+ order: 1;
323
+ flex: auto;
324
+ }
325
+ .table-of-contents a::after {
326
+ text-align: right;
327
+ content: target-counter(attr(href, url), page);
328
+ align-self: flex-end;
329
+ flex: none;
330
+ order: 2;
331
+ }
332
+ @page {
333
+ size: ${CSS_PAPER_SIZES[papersize as string]};
334
+ @top-center {
335
+ content: env(doc-title);
336
+ }
337
+ @bottom-center {
338
+ content: counter(page);
339
+ }
340
+ }
341
+ @page :first {
342
+ @bottom-center { content: normal; }
343
+ @top-center { content: normal; }
344
+ }
345
+ figure img {
346
+ max-width: 100%;
347
+ }
348
+ .doc-title {
349
+ page-break-before: right;
350
+ counter-reset: cat-figure cat-equation cat-photo cat-table;
351
+ }
352
+ h1.part {
353
+ page-break-before: right;
354
+ }
355
+ .copyrightpage {
356
+ page-break-before: left;
357
+ }
358
+ .tocpage {
359
+ page-break-before: right;
360
+ }
361
+ .booktitle {
362
+ text-align: center;
363
+ }`
@@ -0,0 +1,26 @@
1
+ export function orderLinks(
2
+ contentItems: Array<Record<string, unknown>>
3
+ ): Array<Record<string, unknown>> {
4
+ for (let i = 0; i < contentItems.length; i++) {
5
+ contentItems[i].subItems = []
6
+ if (i > 0) {
7
+ for (let j = i - 1; j > -1; j--) {
8
+ if ((contentItems[j].level as number) < (contentItems[i].level as number)) {
9
+ ;(contentItems[j].subItems as Array<Record<string, unknown>>).push(
10
+ contentItems[i]
11
+ )
12
+ contentItems[i].delete = true
13
+ break
14
+ }
15
+ }
16
+ }
17
+ }
18
+
19
+ for (let i = contentItems.length; i > -1; i--) {
20
+ if (contentItems[i]?.delete) {
21
+ delete contentItems[i].delete
22
+ contentItems.splice(i, 1)
23
+ }
24
+ }
25
+ return contentItems
26
+ }
@@ -0,0 +1,161 @@
1
+ /**
2
+ * LaTeX book exporter.
3
+ */
4
+
5
+ import type {Schema} from "prosemirror-model"
6
+ import type {User} from "@fiduswriter/document"
7
+ import {BibLatexExporter} from "biblatex-csl-converter"
8
+ import {LatexExporterConvert} from "@fiduswriter/document/exporter/latex/convert"
9
+ import {removeHidden} from "@fiduswriter/document/exporter/tools/doc_content"
10
+ import {createSlug} from "@fiduswriter/document/exporter/tools/file"
11
+ import {ZipFileCreator} from "@fiduswriter/document/exporter/tools/zip"
12
+
13
+ import type {Book, DocumentListEntry} from "../../types.js"
14
+ import {getMissingChapterData} from "../tools.js"
15
+ import {bookTexTemplate} from "./templates.js"
16
+
17
+ interface TextFile {
18
+ filename: string
19
+ contents: string
20
+ }
21
+
22
+ interface HttpFile {
23
+ url: string
24
+ filename: string
25
+ }
26
+
27
+ export class LatexBookExporter {
28
+ schema: Schema
29
+ book: Book
30
+ user: User
31
+ docList: DocumentListEntry[]
32
+ updated: any
33
+ textFiles: TextFile[]
34
+ httpFiles: HttpFile[]
35
+ zipFileName: string
36
+
37
+ constructor(
38
+ schema: Schema,
39
+ book: Book,
40
+ user: User,
41
+ docList: DocumentListEntry[],
42
+ updated: any
43
+ ) {
44
+ this.schema = schema
45
+ this.book = book
46
+ this.book.chapters.sort((a, b) => (a.number > b.number ? 1 : -1))
47
+ this.user = user
48
+ this.docList = docList
49
+ this.updated = updated
50
+
51
+ this.textFiles = []
52
+ this.httpFiles = []
53
+ this.zipFileName = ""
54
+ }
55
+
56
+ init(): Promise<Blob> {
57
+ return getMissingChapterData(this.book, this.docList, this.schema).then(
58
+ () => this.export()
59
+ )
60
+ }
61
+
62
+ export(): Promise<Blob> {
63
+ this.zipFileName = `${createSlug(this.book.title)}.latex.zip`
64
+ let bibIds: string[] = []
65
+ let imageIds: string[] = []
66
+ const features: Record<string, boolean> = {}
67
+ const combinedBibliography: Record<string, unknown> = {}
68
+ const combinedImages: Record<string, {image: string}> = {}
69
+ this.book.chapters.forEach((chapter, index) => {
70
+ const doc = this.docList.find(d => d.id === chapter.text)
71
+ if (!doc) {
72
+ return
73
+ }
74
+ const converter = new LatexExporterConvert(
75
+ this as any,
76
+ {db: doc.images || {}},
77
+ {db: doc.bibliography || {}},
78
+ doc.settings
79
+ )
80
+ const chapterContent = removeHidden(doc.content as any)
81
+ const convertedDoc = converter.init(chapterContent)
82
+ this.textFiles.push({
83
+ filename: `chapter-${index + 1}.tex`,
84
+ contents: convertedDoc.latex
85
+ })
86
+ bibIds = [
87
+ ...new Set(bibIds.concat(Object.keys(convertedDoc.usedBibDB)))
88
+ ]
89
+ imageIds = [...new Set(imageIds.concat(convertedDoc.imageIds))]
90
+ Object.assign(features, converter.features as Record<string, boolean>)
91
+ Object.keys(convertedDoc.usedBibDB).forEach(
92
+ bibId =>
93
+ (combinedBibliography[bibId] = doc.bibliography?.[bibId])
94
+ )
95
+ convertedDoc.imageIds.forEach(
96
+ (imageId: string) =>
97
+ (combinedImages[imageId] = doc.images?.[imageId] as {
98
+ image: string
99
+ })
100
+ )
101
+ })
102
+ if (bibIds.length > 0) {
103
+ const bibExport = new BibLatexExporter(
104
+ combinedBibliography as any,
105
+ bibIds
106
+ )
107
+ this.textFiles.push({
108
+ filename: "bibliography.bib",
109
+ contents: (bibExport as any).output
110
+ })
111
+ }
112
+ imageIds.forEach(id => {
113
+ const image = combinedImages[id]
114
+ if (image?.image) {
115
+ this.httpFiles.push({
116
+ filename: image.image.split("/").pop() || id,
117
+ url: image.image
118
+ })
119
+ }
120
+ })
121
+ const bookConverter = new LatexExporterConvert(
122
+ this as any,
123
+ {db: combinedImages as any},
124
+ {db: combinedBibliography as any},
125
+ {language: this.book.settings.language, bibliography_header: {}}
126
+ )
127
+ bookConverter.features = features
128
+ const preamble = bookConverter.assemblePreamble()
129
+ const epilogue = bookConverter.assembleEpilogue()
130
+ this.textFiles.push({
131
+ filename: "book.tex",
132
+ contents: bookTexTemplate({
133
+ book: this.book,
134
+ preamble,
135
+ epilogue
136
+ })
137
+ })
138
+
139
+ return this.createZip()
140
+ }
141
+
142
+ createZip(): Promise<Blob> {
143
+ const zipper = new ZipFileCreator(
144
+ this.textFiles,
145
+ this.httpFiles,
146
+ undefined,
147
+ undefined,
148
+ this.updated
149
+ )
150
+
151
+ return zipper.init().then(blob => this.download(blob))
152
+ }
153
+
154
+ download(blob: Blob): Blob {
155
+ return blob
156
+ }
157
+
158
+ get defaultFilename(): string {
159
+ return this.zipFileName
160
+ }
161
+ }
@@ -0,0 +1,35 @@
1
+ import type {BookTexTemplateParams} from "../../types.js"
2
+
3
+ /** A template to create the latex book.tex file. */
4
+ export const bookTexTemplate = ({preamble, book, epilogue}: BookTexTemplateParams) =>
5
+ `\\documentclass[11pt]{book}
6
+ ${preamble}
7
+ \\usepackage{docmute}
8
+ \\title{${book.title}}
9
+ \\author{${book.metadata.author}}
10
+ ${
11
+ book.metadata.publication_date?.length || book.metadata.version?.length
12
+ ? `\\date{${book.metadata.publication_date || book.metadata.version}}`
13
+ : ""
14
+ }
15
+ \\begin{document}
16
+ \\maketitle
17
+ ${
18
+ book.metadata.description?.length
19
+ ? `\\chapter*{Abstract}
20
+ ${book.metadata.description}
21
+ `
22
+ : ""
23
+ }
24
+ \\def\\title#1{\\chapter{#1}}
25
+ \\tableofcontents
26
+ ${book.chapters
27
+ .map(
28
+ chapter =>
29
+ `${chapter.part && chapter.part.length ? `\n\\part{${chapter.part}}` : ""}
30
+ \\input{chapter-${chapter.number}}
31
+ `
32
+ )
33
+ .join("")}
34
+ ${epilogue}
35
+ \\end{document}`