@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,443 @@
1
+ /**
2
+ * HTML book exporter.
3
+ */
4
+
5
+ import type {Schema} from "prosemirror-model"
6
+ import type {CSL, User} from "@fiduswriter/document"
7
+ import {HTMLExporter} from "@fiduswriter/document/exporter/html/index"
8
+ import {createSlug} from "@fiduswriter/document/exporter/tools/file"
9
+ import {ZipFileCreator} from "@fiduswriter/document/exporter/tools/zip"
10
+ import {LANGUAGES} from "@fiduswriter/document/schema/const"
11
+ import {addAlert, get, staticUrl} from "fwtoolkit"
12
+ import pretty from "pretty"
13
+
14
+ import type {Book, BookStyle, BookStyles, DocumentListEntry} from "../../types.js"
15
+ import {getMissingChapterData} from "../tools.js"
16
+ import {
17
+ htmlBookChapterTemplate,
18
+ htmlBookExportTemplate,
19
+ htmlBookIndexBodyTemplate,
20
+ htmlBookIndexTemplate,
21
+ singleFileHTMLBookCSSTemplate,
22
+ singleFileHTMLBookChapterTemplate,
23
+ singleFileHTMLBookTemplate
24
+ } from "./templates.js"
25
+ import {orderLinks} from "./tools.js"
26
+
27
+ interface StyleSheet {
28
+ url?: string
29
+ filename?: string
30
+ contents?: string
31
+ }
32
+
33
+ interface TextFile {
34
+ filename: string
35
+ contents: string
36
+ }
37
+
38
+ interface HttpFile {
39
+ url: string
40
+ filename: string
41
+ }
42
+
43
+ interface IncludeZip {
44
+ directory: string
45
+ url: string
46
+ }
47
+
48
+ interface ChapterInfo {
49
+ number: number
50
+ part: string
51
+ doc: DocumentListEntry
52
+ metaData: Record<string, unknown>
53
+ toc: Array<Record<string, unknown>>
54
+ }
55
+
56
+ export class HTMLBookExporter {
57
+ schema: Schema
58
+ csl: CSL
59
+ bookStyles: BookStyles
60
+ book: Book
61
+ user: User
62
+ docList: DocumentListEntry[]
63
+ updated: any
64
+ multiDoc: boolean
65
+ relativeUrls: boolean
66
+ chapters: ChapterInfo[]
67
+ includeZips: IncludeZip[]
68
+ textFiles: TextFile[]
69
+ httpFiles: HttpFile[]
70
+ math: boolean
71
+ bibCSS: string
72
+ chapterTemplate: (...args: any[]) => string
73
+ indexTemplate: (...args: any[]) => string
74
+ singleFileHTMLBookTemplate: (...args: any[]) => string
75
+ singleFileHTMLBookCSSTemplate: (...args: any[]) => string
76
+ styleSheets: StyleSheet[]
77
+
78
+ constructor(
79
+ schema: Schema,
80
+ csl: CSL,
81
+ bookStyles: BookStyles,
82
+ book: Book,
83
+ user: User,
84
+ docList: DocumentListEntry[],
85
+ updated: any,
86
+ multiDoc = true,
87
+ {relativeUrls = true} = {}
88
+ ) {
89
+ this.schema = schema
90
+ this.csl = csl
91
+ this.bookStyles = bookStyles
92
+ this.book = book
93
+ this.user = user
94
+ this.docList = docList
95
+ this.updated = updated
96
+ this.multiDoc = multiDoc
97
+ this.relativeUrls = relativeUrls
98
+ this.chapters = []
99
+ this.includeZips = []
100
+ this.textFiles = []
101
+ this.httpFiles = []
102
+ this.math = false
103
+ this.bibCSS = ""
104
+ this.chapterTemplate = multiDoc
105
+ ? htmlBookExportTemplate
106
+ : (singleFileHTMLBookChapterTemplate as any)
107
+ this.indexTemplate = multiDoc
108
+ ? htmlBookIndexTemplate
109
+ : htmlBookIndexBodyTemplate
110
+ this.singleFileHTMLBookTemplate = singleFileHTMLBookTemplate
111
+ this.singleFileHTMLBookCSSTemplate = singleFileHTMLBookCSSTemplate
112
+ this.styleSheets = [{url: staticUrl("css/book.css")}]
113
+ }
114
+
115
+ async init(): Promise<Blob | false | void> {
116
+ if (this.book.chapters.length === 0) {
117
+ addAlert(
118
+ "error",
119
+ gettext("Book cannot be exported due to lack of chapters.")
120
+ )
121
+ return false
122
+ }
123
+
124
+ await getMissingChapterData(this.book, this.docList, this.schema)
125
+
126
+ this.addBookStyle()
127
+
128
+ await Promise.all(
129
+ this.styleSheets.map(async sheet => this.loadStyle(sheet))
130
+ )
131
+
132
+ return this.exportChapters()
133
+ }
134
+
135
+ async loadStyle(sheet: StyleSheet): Promise<StyleSheet> {
136
+ if (sheet.url) {
137
+ const response = await get(sheet.url)
138
+ const text = await response.text()
139
+ sheet.contents = text
140
+ sheet.filename = `css/${sheet.url.split("/").pop()?.split("?")[0]}`
141
+ delete sheet.url
142
+ }
143
+ if (sheet.filename) {
144
+ this.textFiles.push(sheet as TextFile)
145
+ }
146
+ return sheet
147
+ }
148
+
149
+ async exportChapters(): Promise<Blob | void> {
150
+ let footnoteCounter = 0,
151
+ affiliationCounter = 0,
152
+ figureCounter = 0,
153
+ equationCounter = 0,
154
+ photoCounter = 0,
155
+ tableCounter = 0
156
+
157
+ for (const chapterInfo of this.book.chapters.sort(
158
+ (a, b) => a.number - b.number
159
+ )) {
160
+ const chapterNumber = chapterInfo.number
161
+ const chapterPart = chapterInfo.part || ""
162
+ const doc = this.docList.find(d => d.id === chapterInfo.text)
163
+
164
+ if (!doc) {
165
+ continue
166
+ }
167
+
168
+ const imageDB = {db: doc.images || {}}
169
+ const bibDB = {db: doc.bibliography || {}}
170
+ const styleSheets = this.styleSheets.slice()
171
+
172
+ const options = {
173
+ xhtml: false,
174
+ epub: false,
175
+ relativeUrls: this.relativeUrls,
176
+ footnoteNumbering: "decimal",
177
+ affiliationNumbering: "alpha",
178
+ idPrefix: `c-${chapterNumber}-`,
179
+ footnoteOffset: footnoteCounter,
180
+ affiliationOffset: affiliationCounter,
181
+ figureOffset: {
182
+ figure: figureCounter,
183
+ equation: equationCounter,
184
+ photo: photoCounter,
185
+ table: tableCounter
186
+ }
187
+ }
188
+
189
+ const documentHTMLExporter = new HTMLExporter(
190
+ doc as any,
191
+ bibDB as any,
192
+ imageDB as any,
193
+ this.csl,
194
+ this.updated,
195
+ [],
196
+ options,
197
+ htmlBookChapterTemplate as any
198
+ )
199
+
200
+ await documentHTMLExporter.process()
201
+ const {metaData, converter, textFiles, httpFiles} =
202
+ documentHTMLExporter.getProcessedFiles() as any
203
+
204
+ const contents = textFiles.find(
205
+ (textFile: TextFile) => textFile.filename === "document.html"
206
+ )?.contents
207
+ if (!contents) {
208
+ continue
209
+ }
210
+ this.httpFiles = this.httpFiles.concat(httpFiles)
211
+
212
+ footnoteCounter = converter.fnCounter
213
+ affiliationCounter = converter.affCounter
214
+ figureCounter = converter.categoryCounter.figure || figureCounter
215
+ equationCounter =
216
+ converter.categoryCounter.equation || equationCounter
217
+ photoCounter = converter.categoryCounter.photo || photoCounter
218
+ tableCounter = converter.categoryCounter.table || tableCounter
219
+
220
+ if (converter.features.math) {
221
+ this.math = true
222
+ styleSheets.push({filename: "css/mathlive.css"})
223
+ }
224
+
225
+ if (converter.citations.bibCSS) {
226
+ if (!this.bibCSS) {
227
+ this.bibCSS = pretty(converter.citations.bibCSS, {
228
+ ocd: true
229
+ })
230
+ }
231
+ styleSheets.push({filename: "css/bibliography.css"})
232
+ }
233
+
234
+ const chapterHTML = this.chapterTemplate({
235
+ part: chapterInfo.part,
236
+ currentPart: chapterPart,
237
+ contents,
238
+ title: doc.title,
239
+ settings: doc.settings,
240
+ styleSheets
241
+ })
242
+
243
+ this.textFiles.push({
244
+ filename: `document-${chapterNumber}.html`,
245
+ contents: pretty(chapterHTML, {ocd: true})
246
+ })
247
+
248
+ this.chapters.push({
249
+ number: chapterNumber,
250
+ part: chapterPart,
251
+ doc,
252
+ metaData,
253
+ toc: converter.metaData.toc
254
+ })
255
+ }
256
+
257
+ return this.exportBook()
258
+ }
259
+
260
+ async exportBook(): Promise<Blob | void> {
261
+ if (this.math) {
262
+ this.includeZips.push({
263
+ directory: "css",
264
+ url: staticUrl("zip/mathlive_style.zip")
265
+ })
266
+ }
267
+
268
+ if (this.bibCSS) {
269
+ this.textFiles.push({
270
+ filename: "css/bibliography.css",
271
+ contents: this.bibCSS
272
+ })
273
+ }
274
+
275
+ let contentItems: Array<Record<string, unknown>> = []
276
+ for (const chapter of this.chapters) {
277
+ const chapterNumber = chapter.number
278
+ const chapterPart = chapter.part
279
+
280
+ if (chapterPart && chapterPart !== "") {
281
+ contentItems.push({
282
+ link: this.multiDoc
283
+ ? this.getChapterLink(chapterNumber)
284
+ : `#c-${chapterNumber}-body`,
285
+ title: chapterPart,
286
+ docNum: chapterNumber,
287
+ id: 0,
288
+ level: -1,
289
+ subItems: []
290
+ })
291
+ }
292
+
293
+ const contentItemsFromChapter = chapter.toc.map(item => {
294
+ return {
295
+ link: `${this.multiDoc ? this.getChapterLink(chapter.number) : ""}#c-${chapter.number}-${item.id}`,
296
+ title: item.title,
297
+ docNum: chapterNumber,
298
+ id: item.id,
299
+ level: item.level,
300
+ subItems: []
301
+ }
302
+ })
303
+
304
+ contentItems = contentItems.concat(contentItemsFromChapter)
305
+ }
306
+
307
+ contentItems = orderLinks(contentItems)
308
+
309
+ const language = LANGUAGES.find(
310
+ lang => lang[0] === this.book.settings.language
311
+ )?.[1]
312
+
313
+ this.textFiles.push({
314
+ filename: "index.html",
315
+ contents: pretty(
316
+ this.indexTemplate({
317
+ contentItems,
318
+ book: this.book,
319
+ creator: this.user.name,
320
+ styleSheets: this.styleSheets,
321
+ language,
322
+ multiDoc: this.multiDoc
323
+ }),
324
+ {ocd: true}
325
+ )
326
+ })
327
+ if (!this.multiDoc) {
328
+ this.joinChapters()
329
+ }
330
+ return this.createZip()
331
+ }
332
+
333
+ joinChapters(): void {
334
+ const styleSheets = this.styleSheets.slice()
335
+ if (this.bibCSS) {
336
+ styleSheets.push(
337
+ this.relativeUrls
338
+ ? {filename: "css/bibliography.css"}
339
+ : {contents: this.bibCSS}
340
+ )
341
+ }
342
+ if (this.math) {
343
+ styleSheets.push(
344
+ this.relativeUrls
345
+ ? {filename: "css/mathlive.css"}
346
+ : {filename: staticUrl("css/mathlive.css")}
347
+ )
348
+ }
349
+ let html = ""
350
+ this.textFiles = this.textFiles
351
+ .sort((a, b) => {
352
+ if (a.filename === "index.html") {
353
+ return -1
354
+ }
355
+ if (b.filename === "index.html") {
356
+ return 1
357
+ }
358
+ const aNum = Number.parseInt(a.filename.match(/\d+/g)?.[0] || "0")
359
+ const bNum = Number.parseInt(b.filename.match(/\d+/g)?.[0] || "0")
360
+ if (aNum < bNum) {
361
+ return -1
362
+ }
363
+ if (aNum > bNum) {
364
+ return 1
365
+ }
366
+ return 0
367
+ })
368
+ .filter(({filename, contents}) => {
369
+ if (filename.slice(-5) !== ".html") {
370
+ return true
371
+ }
372
+ html += contents
373
+ return false
374
+ })
375
+ const css = this.singleFileHTMLBookCSSTemplate({
376
+ papersize: this.book.settings.papersize
377
+ }),
378
+ title = this.book.title,
379
+ settings = this.book.settings,
380
+ htmlDoc = this.singleFileHTMLBookTemplate({
381
+ css,
382
+ html,
383
+ title,
384
+ styleSheets,
385
+ settings
386
+ })
387
+
388
+ this.textFiles.push({
389
+ filename: "index.html",
390
+ contents: pretty(htmlDoc, {ocd: true})
391
+ })
392
+ }
393
+
394
+ addBookStyle(): boolean {
395
+ const bookStyle = this.bookStyles.find(
396
+ (style: BookStyle) => style.slug === this.book.settings.book_style
397
+ )
398
+ if (!bookStyle) {
399
+ return false
400
+ }
401
+ let contents = bookStyle.contents
402
+ bookStyle.bookstylefile_set.forEach(
403
+ ([_url, filename]: [string, string]) =>
404
+ (contents = contents.replace(
405
+ new RegExp(filename, "g"),
406
+ `media/${filename}`
407
+ ))
408
+ )
409
+
410
+ this.styleSheets.push({contents, filename: `css/${bookStyle.slug}.css`})
411
+ this.httpFiles = this.httpFiles.concat(
412
+ bookStyle.bookstylefile_set.map(([url, filename]: [string, string]) => ({
413
+ filename: `css/media/${filename}`,
414
+ url
415
+ }))
416
+ )
417
+ return true
418
+ }
419
+
420
+ async createZip(): Promise<Blob | void> {
421
+ const zipper = new ZipFileCreator(
422
+ this.textFiles.concat(this.styleSheets as any),
423
+ this.httpFiles,
424
+ this.includeZips,
425
+ "application/zip",
426
+ new Date(this.updated * 1000)
427
+ )
428
+ const blob = await zipper.init()
429
+ return this.download(blob)
430
+ }
431
+
432
+ download(blob: Blob): Blob {
433
+ return blob
434
+ }
435
+
436
+ get defaultFilename(): string {
437
+ return `${createSlug(this.book.title)}.html.zip`
438
+ }
439
+
440
+ getChapterLink(chapterNumber: number): string {
441
+ return `document-${chapterNumber}.html`
442
+ }
443
+ }