@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,187 @@
1
+ /**
2
+ * Native `.fidusbook` exporter.
3
+ */
4
+
5
+ import type {Schema} from "prosemirror-model"
6
+ import {ShrinkFidus} from "@fiduswriter/document/exporter/native/shrink"
7
+ import {createSlug} from "@fiduswriter/document/exporter/tools/file"
8
+ import {ZipFileCreator} from "@fiduswriter/document/exporter/tools/zip"
9
+ import {addAlert} from "fwtoolkit"
10
+
11
+ import {FIDUSBOOK_VERSION} from "../../schema/index.js"
12
+ import type {Book, DocumentListEntry, User} from "../../types.js"
13
+ import {getMissingChapterData} from "../tools.js"
14
+
15
+ interface FileInclude {
16
+ url: string
17
+ filename: string
18
+ }
19
+
20
+ interface TextFile {
21
+ filename: string
22
+ contents: string
23
+ }
24
+
25
+ export {FIDUSBOOK_VERSION}
26
+
27
+ export class NativeBookExporter {
28
+ schema: Schema
29
+ book: Book
30
+ user: User
31
+ documentList: DocumentListEntry[]
32
+ updated: any
33
+
34
+ constructor(
35
+ schema: Schema,
36
+ book: Book,
37
+ user: User,
38
+ documentList: DocumentListEntry[],
39
+ updated: any
40
+ ) {
41
+ this.schema = schema
42
+ this.book = book
43
+ this.user = user
44
+ this.documentList = documentList
45
+ this.updated = updated
46
+ }
47
+
48
+ init(): Promise<Blob> {
49
+ if (this.book.chapters.length === 0) {
50
+ addAlert(
51
+ "error",
52
+ gettext("Book cannot be exported due to lack of chapters.")
53
+ )
54
+ return Promise.resolve(new Blob([]))
55
+ }
56
+
57
+ addAlert(
58
+ "info",
59
+ `${this.book.title}: ${gettext("Fidusbook export has been initiated.")}`
60
+ )
61
+
62
+ return getMissingChapterData(this.book, this.documentList, this.schema)
63
+ .then(() => this.exportContents())
64
+ .catch(error => {
65
+ addAlert(
66
+ "error",
67
+ `${this.book.title}: ${gettext("Fidusbook export failed.")}`
68
+ )
69
+ throw error
70
+ })
71
+ }
72
+
73
+ exportContents(): Promise<Blob> {
74
+ const textFiles: TextFile[] = []
75
+ const httpFiles: FileInclude[] = []
76
+
77
+ const sortedChapters = [...this.book.chapters].sort(
78
+ (a, b) => a.number - b.number
79
+ )
80
+
81
+ const bookData: Record<string, unknown> = {
82
+ title: this.book.title,
83
+ path: this.book.path || "/",
84
+ metadata: this.book.metadata || {},
85
+ settings: this.book.settings || {},
86
+ chapters: sortedChapters.map((chapter, index) => ({
87
+ number: chapter.number,
88
+ part: chapter.part || "",
89
+ chapter_index: index
90
+ }))
91
+ }
92
+
93
+ if (this.book.cover_image_data) {
94
+ const coverImage = this.book.cover_image_data
95
+ const imageUrl = (coverImage.image || "").split("?")[0]
96
+ const filename = imageUrl.split("/").pop() || "cover"
97
+ bookData.cover_image = {
98
+ title: coverImage.title || "",
99
+ checksum: coverImage.checksum || "",
100
+ file_type: coverImage.file_type,
101
+ image: `cover/${filename}`
102
+ }
103
+ httpFiles.push({url: imageUrl, filename: `cover/${filename}`})
104
+ }
105
+
106
+ const processChapter = (index: number): Promise<void> => {
107
+ if (index >= sortedChapters.length) {
108
+ return Promise.resolve()
109
+ }
110
+ const chapter = sortedChapters[index]
111
+ const doc = this.documentList.find(d => d.id === chapter.text)
112
+ if (!doc) {
113
+ return processChapter(index + 1)
114
+ }
115
+
116
+ const shrinker = new ShrinkFidus(
117
+ doc as any,
118
+ {db: doc.images || {}},
119
+ {db: doc.bibliography || {}},
120
+ true
121
+ )
122
+
123
+ return shrinker
124
+ .init()
125
+ .then(
126
+ ({
127
+ doc: shrunkDoc,
128
+ shrunkImageDB,
129
+ shrunkBibDB,
130
+ httpIncludes
131
+ }: {
132
+ doc: Record<string, unknown>
133
+ shrunkImageDB: Record<string, unknown>
134
+ shrunkBibDB: Record<string, unknown>
135
+ httpIncludes: FileInclude[]
136
+ }) => {
137
+ httpIncludes.forEach(include => {
138
+ include.filename = `chapters/${index}/${include.filename}`
139
+ })
140
+
141
+ textFiles.push(
142
+ {
143
+ filename: `chapters/${index}/document.json`,
144
+ contents: JSON.stringify(shrunkDoc)
145
+ },
146
+ {
147
+ filename: `chapters/${index}/images.json`,
148
+ contents: JSON.stringify(shrunkImageDB)
149
+ },
150
+ {
151
+ filename: `chapters/${index}/bibliography.json`,
152
+ contents: JSON.stringify(shrunkBibDB)
153
+ }
154
+ )
155
+ httpFiles.push(...httpIncludes)
156
+ }
157
+ )
158
+ .then(() => processChapter(index + 1))
159
+ }
160
+
161
+ return processChapter(0).then(() => {
162
+ textFiles.push(
163
+ {filename: "book.json", contents: JSON.stringify(bookData)},
164
+ {filename: "filetype-version", contents: FIDUSBOOK_VERSION}
165
+ )
166
+
167
+ const zipper = new ZipFileCreator(
168
+ textFiles,
169
+ httpFiles,
170
+ [],
171
+ "application/fidusbook+zip",
172
+ this.updated
173
+ )
174
+ return zipper.init().then(blob => this.download(blob))
175
+ })
176
+ }
177
+
178
+ download(blob: Blob): Blob {
179
+ // Base implementation returns the Blob. Browser/CLI subclasses can
180
+ // override this method to trigger a real download.
181
+ return blob
182
+ }
183
+
184
+ get defaultFilename(): string {
185
+ return `${createSlug(this.book.title)}.fidusbook`
186
+ }
187
+ }
@@ -0,0 +1,211 @@
1
+ /**
2
+ * ODT book exporter.
3
+ */
4
+
5
+ import type {Schema} from "prosemirror-model"
6
+ import type {CSL, User} from "@fiduswriter/document"
7
+ import {
8
+ fixTables,
9
+ removeHidden
10
+ } from "@fiduswriter/document/exporter/tools/doc_content"
11
+ import {createSlug} from "@fiduswriter/document/exporter/tools/file"
12
+ import {XmlZip} from "@fiduswriter/document/exporter/tools/xml_zip"
13
+ import {addAlert} from "fwtoolkit"
14
+
15
+ import {ODTExporterCitations} from "@fiduswriter/document/exporter/odt/citations"
16
+ import {ODTExporterImages} from "@fiduswriter/document/exporter/odt/images"
17
+ import {ODTExporterFootnotes} from "@fiduswriter/document/exporter/odt/footnotes"
18
+ import {ODTExporterMath} from "@fiduswriter/document/exporter/odt/math"
19
+ import {ODTExporterMetadata} from "@fiduswriter/document/exporter/odt/metadata"
20
+ import {ODTExporterRichtext} from "@fiduswriter/document/exporter/odt/richtext"
21
+ import {ODTExporterStyles} from "@fiduswriter/document/exporter/odt/styles"
22
+ import {ODTExporterTracks} from "@fiduswriter/document/exporter/odt/track"
23
+
24
+ import type {Book, DocumentListEntry} from "../../types.js"
25
+ import {getMissingChapterData} from "../tools.js"
26
+ import {ODTBookExporterRender} from "./render.js"
27
+
28
+ export class ODTBookExporter {
29
+ schema: Schema
30
+ csl: CSL
31
+ book: Book
32
+ user: User
33
+ docList: DocumentListEntry[]
34
+ templateUrl: string
35
+ updated: any
36
+ textFiles: Array<Record<string, unknown>>
37
+ httpFiles: Array<Record<string, unknown>>
38
+ mimeType: string
39
+
40
+ constructor(
41
+ schema: Schema,
42
+ csl: CSL,
43
+ book: Book,
44
+ user: User,
45
+ docList: DocumentListEntry[],
46
+ updated: any
47
+ ) {
48
+ this.schema = schema
49
+ this.csl = csl
50
+ this.book = book
51
+ this.user = user
52
+ this.docList = docList
53
+ this.templateUrl = book.odt_template || ""
54
+ this.updated = updated
55
+ this.textFiles = []
56
+ this.httpFiles = []
57
+
58
+ this.mimeType = "application/vnd.oasis.opendocument.text"
59
+ }
60
+
61
+ init(): Promise<Blob> | false {
62
+ if (this.book.chapters.length === 0) {
63
+ addAlert(
64
+ "error",
65
+ gettext("Book cannot be exported due to lack of chapters.")
66
+ )
67
+ return false
68
+ }
69
+ return getMissingChapterData(
70
+ this.book,
71
+ this.docList,
72
+ this.schema,
73
+ {rawContent: true}
74
+ ).then(() => this.export())
75
+ }
76
+
77
+ export(): Promise<Blob> {
78
+ this.book.chapters.sort((a, b) => (a.number > b.number ? 1 : -1))
79
+ const xml = new XmlZip(this.templateUrl, this.mimeType)
80
+ const styles = new ODTExporterStyles(xml as any)
81
+ const math = new ODTExporterMath(xml as any)
82
+ const tracks = new ODTExporterTracks(xml as any)
83
+ const render = new ODTBookExporterRender(xml as any, styles)
84
+ const metadata = new ODTExporterMetadata(
85
+ xml as any,
86
+ styles,
87
+ this.getBaseMetadata() as any
88
+ )
89
+
90
+ return xml
91
+ .init()
92
+ .then(() => styles.init())
93
+ .then(() => tracks.init())
94
+ .then(() => render.init())
95
+ .then(() => metadata.init())
96
+ .then(() => math.init())
97
+ .then(() => this.exportChapters(xml as any, render, styles, math, tracks))
98
+ .then(() => xml.prepareBlob())
99
+ .then(blob => this.download(blob))
100
+ }
101
+
102
+ exportChapters(
103
+ xml: any,
104
+ render: ODTBookExporterRender,
105
+ styles: any,
106
+ math: any,
107
+ tracks: any
108
+ ): Promise<void> {
109
+ return this.book.chapters
110
+ .map((chapter, chapterIndex) => {
111
+ return (): Promise<void> => {
112
+ const doc = this.docList.find(d => d.id === chapter.text)
113
+ if (!doc) {
114
+ return Promise.resolve()
115
+ }
116
+ const docContent = fixTables(
117
+ removeHidden(doc.rawContent as any) as any
118
+ ) as any
119
+ const citations = new ODTExporterCitations(
120
+ docContent as any,
121
+ doc.settings,
122
+ styles,
123
+ {db: doc.bibliography || {}},
124
+ this.csl
125
+ )
126
+ const footnotes = new ODTExporterFootnotes(
127
+ docContent,
128
+ doc.settings,
129
+ xml,
130
+ citations,
131
+ styles,
132
+ {db: doc.bibliography || {}},
133
+ {db: doc.images || {}},
134
+ this.csl
135
+ )
136
+
137
+ const images = new ODTExporterImages(docContent, xml, {
138
+ db: doc.images || {}
139
+ })
140
+ const richtext = new ODTExporterRichtext(
141
+ doc.comments || {},
142
+ doc.settings,
143
+ styles,
144
+ tracks,
145
+ footnotes,
146
+ citations,
147
+ math,
148
+ images
149
+ )
150
+ return citations
151
+ .init()
152
+ .then(() => images.init())
153
+ .then(() => footnotes.init())
154
+ .then(() => {
155
+ const pmBib = footnotes.pmBib || citations.pmBib
156
+ render.render(
157
+ docContent as any,
158
+ pmBib,
159
+ doc.settings,
160
+ richtext,
161
+ citations,
162
+ chapterIndex
163
+ )
164
+ return Promise.resolve()
165
+ })
166
+ }
167
+ })
168
+ .reduce(
169
+ (promiseChain, currentChapter) =>
170
+ promiseChain.then(() => currentChapter()),
171
+ Promise.resolve()
172
+ )
173
+ .then(() =>
174
+ render.renderAmbles(
175
+ Object.assign(
176
+ {
177
+ title: this.book.title,
178
+ language: this.book.settings.language
179
+ },
180
+ this.book.metadata
181
+ )
182
+ )
183
+ )
184
+ .then(() => render.assemble())
185
+ }
186
+
187
+ getBaseMetadata(): Record<string, unknown> {
188
+ const authors = this.book.metadata.author?.length
189
+ ? [{institution: this.book.metadata.author}]
190
+ : []
191
+ const keywords = this.book.metadata.keywords?.length
192
+ ? this.book.metadata.keywords
193
+ .split(",")
194
+ .map(keyword => keyword.trim())
195
+ : []
196
+ return {
197
+ authors,
198
+ keywords,
199
+ title: this.book.title,
200
+ language: this.book.settings.language
201
+ }
202
+ }
203
+
204
+ download(blob: Blob): Blob {
205
+ return blob
206
+ }
207
+
208
+ get defaultFilename(): string {
209
+ return `${createSlug(this.book.title)}.odt`
210
+ }
211
+ }
@@ -0,0 +1,146 @@
1
+ import {ODTExporterRender} from "@fiduswriter/document/exporter/odt/render"
2
+
3
+ export class ODTBookExporterRender extends ODTExporterRender {
4
+ styles: any
5
+ preamble: any
6
+ bodyTemplate: any
7
+ postamble: any
8
+ bodyParts: any[]
9
+ fileXml: any
10
+
11
+ constructor(xml: any, styles: any) {
12
+ super(xml)
13
+
14
+ this.styles = styles
15
+
16
+ this.preamble = null
17
+ this.bodyTemplate = null
18
+ this.postamble = null
19
+
20
+ this.bodyParts = []
21
+ this.fileXml = null
22
+ }
23
+
24
+ init(): Promise<void> {
25
+ return this.xml.getXml(this.filePath).then((xml: any) => {
26
+ this.fileXml = xml
27
+ const text = xml.query("office:text")
28
+ this.preamble = text.cloneNode(false)
29
+ this.bodyTemplate = text.cloneNode(false)
30
+ this.postamble = text.cloneNode(false)
31
+ let currentSection: any
32
+ const textChildren = Array.from(text.children)
33
+ textChildren.forEach((node: any) => {
34
+ if (["text:p", "text:h"].includes(node.tagName)) {
35
+ const bookmark = node.query("text:bookmark")
36
+ if (bookmark) {
37
+ const sectionName = String(
38
+ bookmark.getAttribute("text:name")
39
+ ).toLowerCase()
40
+ if (sectionName === "preamble") {
41
+ currentSection = this.preamble
42
+ } else if (sectionName === "postamble") {
43
+ currentSection = this.postamble
44
+ } else if (sectionName === "body") {
45
+ currentSection = this.bodyTemplate
46
+ } else {
47
+ currentSection = currentSection || this.bodyTemplate
48
+ }
49
+ } else {
50
+ currentSection = currentSection || this.bodyTemplate
51
+ }
52
+ }
53
+ if (currentSection) {
54
+ currentSection.appendChild(node)
55
+ }
56
+ })
57
+ return Promise.resolve()
58
+ })
59
+ }
60
+
61
+ render(...args: any[]): void {
62
+ const [docContent, pmBib, settings, richtext, citations, chapterIndex] = args
63
+ this.text = this.bodyTemplate.cloneNode(true)
64
+ const bodyBookmark = (this.text as any).query("text:bookmark", {
65
+ "text:name": "body"
66
+ })
67
+ if (bodyBookmark) {
68
+ bodyBookmark.setAttribute(
69
+ "text:name",
70
+ `chapter ${chapterIndex + 1}`
71
+ )
72
+ }
73
+ super.render(docContent, pmBib, settings, richtext, citations)
74
+ this.bodyParts.push(this.text)
75
+ }
76
+
77
+ renderAmbles({
78
+ title,
79
+ subtitle,
80
+ version,
81
+ publisher,
82
+ copyright,
83
+ author,
84
+ keywords,
85
+ language,
86
+ description,
87
+ isbn,
88
+ publication_date,
89
+ series_title,
90
+ series_position
91
+ }: Record<string, unknown>): void {
92
+ const tags = [
93
+ {title: "book.title", content: title},
94
+ {title: "book.subtitle", content: subtitle},
95
+ {title: "book.version", content: version},
96
+ {title: "book.publisher", content: publisher},
97
+ {title: "book.copyright", content: copyright},
98
+ {title: "book.author", content: author},
99
+ {title: "book.keywords", content: keywords},
100
+ {title: "book.language", content: language},
101
+ {title: "book.description", content: description},
102
+ {title: "book.isbn", content: isbn},
103
+ {title: "book.publication_date", content: publication_date},
104
+ {title: "book.series_title", content: series_title},
105
+ {title: "book.series_position", content: series_position}
106
+ ]
107
+ const usedTags: any[] = []
108
+ const ambles = [this.preamble, this.postamble]
109
+ ambles.forEach(amble => {
110
+ const blocks = amble.queryAll(["text:p", "text:h"])
111
+ blocks.forEach((block: any) => {
112
+ if (block.parentElement.nodeName === "text:deletion") {
113
+ return
114
+ }
115
+ const text = block.textContent
116
+ tags.forEach(tag => {
117
+ const tagString = tag.title
118
+ if (text.includes(`{${tagString}}`)) {
119
+ usedTags.push(Object.assign({block}, tag))
120
+ }
121
+ })
122
+ })
123
+ })
124
+ usedTags.forEach(tag => this.inlineRender(tag))
125
+ }
126
+
127
+ assemble(): void {
128
+ this.styles.addPageBreakStyle()
129
+ const text = this.fileXml.query("office:text")
130
+ Array.from(this.preamble.children).forEach((node: any) =>
131
+ text.appendChild(node)
132
+ )
133
+ this.bodyParts.forEach((bodyPart: any, index: number) => {
134
+ const children = bodyPart.children.slice()
135
+ children.forEach((node: any) => {
136
+ text.appendChild(node)
137
+ })
138
+ if (index < this.bodyParts.length - 1) {
139
+ text.appendXML('<text:p text:style-name="PageBreak"/>')
140
+ }
141
+ })
142
+ Array.from(this.postamble.children).forEach((node: any) =>
143
+ text.appendChild(node)
144
+ )
145
+ }
146
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Print book exporter.
3
+ *
4
+ * Uses @vivliostyle/print to render the book in the browser.
5
+ */
6
+
7
+ import type {Schema} from "prosemirror-model"
8
+ import type {CSL, User} from "@fiduswriter/document"
9
+ import {printHTML} from "@vivliostyle/print"
10
+
11
+ import type {Book, BookStyles, DocumentListEntry} from "../../types.js"
12
+ import {HTMLBookExporter} from "../html/index.js"
13
+ import {chapterTemplate} from "./templates.js"
14
+
15
+ export class PrintBookExporter extends HTMLBookExporter {
16
+ constructor(
17
+ schema: Schema,
18
+ csl: CSL,
19
+ documentStyles: BookStyles,
20
+ book: Book,
21
+ user: User,
22
+ docList: DocumentListEntry[]
23
+ ) {
24
+ super(schema, csl, documentStyles, book, user, docList, 0, false, {
25
+ relativeUrls: false
26
+ })
27
+ this.chapterTemplate = chapterTemplate
28
+ }
29
+
30
+ addBookStyle(): boolean {
31
+ const bookStyle = this.bookStyles.find(
32
+ style => style.slug === this.book.settings.book_style
33
+ )
34
+ if (!bookStyle) {
35
+ return false
36
+ }
37
+ let contents = bookStyle.contents
38
+ bookStyle.bookstylefile_set.forEach(
39
+ ([url, filename]: [string, string]) =>
40
+ (contents = contents.replace(
41
+ new RegExp(filename, "g"),
42
+ url
43
+ ))
44
+ )
45
+
46
+ this.styleSheets.push({contents})
47
+ return true
48
+ }
49
+
50
+ async createZip(): Promise<void> {
51
+ const htmlDoc = this.textFiles.find(
52
+ file => file.filename === "index.html"
53
+ )?.contents
54
+ if (!htmlDoc) {
55
+ return
56
+ }
57
+ const config: any = {title: this.book.title}
58
+
59
+ if (navigator.userAgent.includes("Gecko/")) {
60
+ config.printCallback = (iframeWin: Window) => {
61
+ const oldBody = document.body
62
+ document.body.parentElement!.dataset.vivliostylePaginated =
63
+ "true"
64
+ document.body = iframeWin.document.body
65
+ iframeWin.document
66
+ .querySelectorAll("style")
67
+ .forEach(el => document.body.appendChild(el))
68
+ const backgroundStyle = document.createElement("style")
69
+ backgroundStyle.innerHTML = "body {background-color: white;}"
70
+ document.body.appendChild(backgroundStyle)
71
+ window.print()
72
+ document.body = oldBody
73
+ delete document.body.parentElement!.dataset
74
+ .vivliostylePaginated
75
+ }
76
+ }
77
+
78
+ printHTML(htmlDoc, config)
79
+ }
80
+
81
+ async loadStyle(sheet: {
82
+ url?: string
83
+ filename?: string
84
+ contents?: string
85
+ }): Promise<{url?: string; filename?: string; contents?: string}> {
86
+ if (sheet.url) {
87
+ sheet.filename = sheet.url
88
+ delete sheet.url
89
+ }
90
+ return sheet
91
+ }
92
+ }
@@ -0,0 +1,8 @@
1
+ import {escapeText} from "fwtoolkit"
2
+
3
+ export const chapterTemplate = ({
4
+ part,
5
+ contents
6
+ }: Record<string, unknown>) => `
7
+ ${part && (part as string).length ? `<h1 class="part">${escapeText(part as string)}</h1>` : ""}
8
+ ${contents}`