@fiduswriter/document 0.1.0-alpha.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 (110) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +16 -0
  3. package/jest.config.js +23 -0
  4. package/package.json +59 -0
  5. package/schema.json +1 -0
  6. package/scripts/export-schema.js +16 -0
  7. package/src/bibliography/common.js +92 -0
  8. package/src/bibliography/csl_bib.js +139 -0
  9. package/src/citations/citeproc_sys.js +42 -0
  10. package/src/citations/format.js +194 -0
  11. package/src/common/blob.js +10 -0
  12. package/src/common/file.js +25 -0
  13. package/src/common/index.js +12 -0
  14. package/src/common/network.js +79 -0
  15. package/src/common/text.js +44 -0
  16. package/src/editor/e2ee/encryptor.js +228 -0
  17. package/src/exporter/docx/citations.js +177 -0
  18. package/src/exporter/docx/comments.js +165 -0
  19. package/src/exporter/docx/footnotes.js +240 -0
  20. package/src/exporter/docx/images.js +101 -0
  21. package/src/exporter/docx/index.js +185 -0
  22. package/src/exporter/docx/lists.js +260 -0
  23. package/src/exporter/docx/math.js +46 -0
  24. package/src/exporter/docx/metadata.js +289 -0
  25. package/src/exporter/docx/rels.js +193 -0
  26. package/src/exporter/docx/render.js +941 -0
  27. package/src/exporter/docx/richtext.js +1182 -0
  28. package/src/exporter/docx/tables.js +112 -0
  29. package/src/exporter/docx/tools.js +50 -0
  30. package/src/exporter/epub/index.js +142 -0
  31. package/src/exporter/epub/templates.js +140 -0
  32. package/src/exporter/epub/tools.js +96 -0
  33. package/src/exporter/html/citations.js +121 -0
  34. package/src/exporter/html/convert.js +813 -0
  35. package/src/exporter/html/index.js +192 -0
  36. package/src/exporter/html/templates.js +34 -0
  37. package/src/exporter/html/tools.js +50 -0
  38. package/src/exporter/jats/bibliography.js +183 -0
  39. package/src/exporter/jats/citations.js +109 -0
  40. package/src/exporter/jats/convert.js +871 -0
  41. package/src/exporter/jats/index.js +92 -0
  42. package/src/exporter/jats/templates.js +35 -0
  43. package/src/exporter/jats/text.js +72 -0
  44. package/src/exporter/latex/convert.js +934 -0
  45. package/src/exporter/latex/escape_latex.js +21 -0
  46. package/src/exporter/latex/index.js +74 -0
  47. package/src/exporter/latex/readme.js +22 -0
  48. package/src/exporter/native/shrink.js +132 -0
  49. package/src/exporter/odt/citations.js +101 -0
  50. package/src/exporter/odt/footnotes.js +147 -0
  51. package/src/exporter/odt/images.js +115 -0
  52. package/src/exporter/odt/index.js +156 -0
  53. package/src/exporter/odt/math.js +57 -0
  54. package/src/exporter/odt/metadata.js +251 -0
  55. package/src/exporter/odt/render.js +806 -0
  56. package/src/exporter/odt/richtext.js +865 -0
  57. package/src/exporter/odt/styles.js +387 -0
  58. package/src/exporter/odt/track.js +68 -0
  59. package/src/exporter/pandoc/citations.js +98 -0
  60. package/src/exporter/pandoc/convert.js +1017 -0
  61. package/src/exporter/pandoc/index.js +92 -0
  62. package/src/exporter/pandoc/readme.js +8 -0
  63. package/src/exporter/pandoc/tools.js +51 -0
  64. package/src/exporter/print/index.js +177 -0
  65. package/src/exporter/tools/doc_content.js +144 -0
  66. package/src/exporter/tools/file.js +9 -0
  67. package/src/exporter/tools/json.js +73 -0
  68. package/src/exporter/tools/svg.js +29 -0
  69. package/src/exporter/tools/xml.js +531 -0
  70. package/src/exporter/tools/xml_zip.js +95 -0
  71. package/src/exporter/tools/zip.js +90 -0
  72. package/src/exporter/tools/zotero_csl.js +93 -0
  73. package/src/importer/citations.js +129 -0
  74. package/src/importer/docx/citations.js +123 -0
  75. package/src/importer/docx/convert.js +1427 -0
  76. package/src/importer/docx/helpers.js +9 -0
  77. package/src/importer/docx/omml2mathml.js +1448 -0
  78. package/src/importer/docx/parse.js +735 -0
  79. package/src/importer/native/get_images.js +76 -0
  80. package/src/importer/native/update.js +29 -0
  81. package/src/importer/odt/citations.js +87 -0
  82. package/src/importer/odt/convert.js +1855 -0
  83. package/src/importer/pandoc/convert.js +884 -0
  84. package/src/importer/pandoc/helpers.js +84 -0
  85. package/src/importer/zip_analyzer.js +102 -0
  86. package/src/index.js +1 -0
  87. package/src/mathlive/opf_includes.js +24 -0
  88. package/src/schema/common/annotate.js +76 -0
  89. package/src/schema/common/base.js +118 -0
  90. package/src/schema/common/citation.js +62 -0
  91. package/src/schema/common/equation.js +31 -0
  92. package/src/schema/common/figure.js +190 -0
  93. package/src/schema/common/heading.js +43 -0
  94. package/src/schema/common/index.js +40 -0
  95. package/src/schema/common/list.js +95 -0
  96. package/src/schema/common/reference.js +100 -0
  97. package/src/schema/common/table.js +103 -0
  98. package/src/schema/common/track.js +190 -0
  99. package/src/schema/const.js +58 -0
  100. package/src/schema/convert.js +1272 -0
  101. package/src/schema/document/content.js +187 -0
  102. package/src/schema/document/index.js +117 -0
  103. package/src/schema/document/structure.js +452 -0
  104. package/src/schema/export.js +21 -0
  105. package/src/schema/footnotes.js +126 -0
  106. package/src/schema/footnotes_convert.js +31 -0
  107. package/src/schema/i18n.js +595 -0
  108. package/src/schema/index.js +5 -0
  109. package/src/schema/mini_json.js +61 -0
  110. package/src/schema/text.js +22 -0
@@ -0,0 +1,192 @@
1
+ import download from "downloadjs"
2
+ import pretty from "pretty"
3
+
4
+ import {shortFileTitle} from "../../common/index.js"
5
+ import {removeHidden} from "../tools/doc_content.js"
6
+ import {createSlug} from "../tools/file.js"
7
+ import {ZipFileCreator} from "../tools/zip.js"
8
+
9
+ import {HTMLExporterConvert} from "./convert.js"
10
+ import {htmlExportTemplate} from "./templates.js"
11
+ /*
12
+ Exporter to HTML
13
+ */
14
+
15
+ export class HTMLExporter {
16
+ constructor(
17
+ doc,
18
+ bibDB,
19
+ imageDB,
20
+ csl,
21
+ updated,
22
+ documentStyles,
23
+ converterOptions = {},
24
+ template = htmlExportTemplate
25
+ ) {
26
+ this.doc = doc
27
+ this.bibDB = bibDB
28
+ this.imageDB = imageDB
29
+ this.csl = csl
30
+ this.updated = updated
31
+ this.documentStyles = documentStyles
32
+ this.converterOptions = converterOptions
33
+
34
+ this.docTitle = shortFileTitle(this.doc.title, this.doc.path)
35
+
36
+ this.docContent = false
37
+ this.zipFileName = false
38
+ this.textFiles = []
39
+ this.httpFiles = []
40
+ this.includeZips = []
41
+ this.metaData = {} // Information to be used in sub classes.
42
+ // To override in subclasses
43
+ this.htmlExportTemplate = template
44
+ this.contentFileName = "document.html"
45
+ this.fileEnding = "html.zip"
46
+ this.mimeType = "application/zip"
47
+
48
+ // Stylesheets will have one of:
49
+ // * a url - which means they will be fetched before they are included as a separate file
50
+ // * a filename and contents - which means they will be included as a separate file
51
+ // * only contents - which means they will be incldued inside <style></style> tags in the document header
52
+ // * only filename - which means they will be referenced as a separate file. You need to add the file yourself.
53
+ this.styleSheets = [{url: staticUrl("css/document.css")}]
54
+ }
55
+
56
+ async init() {
57
+ await this.process()
58
+ return await this.createZip()
59
+ }
60
+
61
+ async process() {
62
+ // Process the document and prepare files
63
+ this.zipFileName = `${createSlug(this.docTitle)}.${this.fileEnding}`
64
+ this.docContent = removeHidden(this.doc.content)
65
+
66
+ const docStyle = this.getDocStyle(this.doc)
67
+
68
+ if (docStyle) {
69
+ this.styleSheets.push(docStyle)
70
+ }
71
+ await Promise.all(
72
+ this.styleSheets.map(async sheet => await this.loadStyle(sheet))
73
+ )
74
+
75
+ this.converter = new HTMLExporterConvert(
76
+ this.docTitle,
77
+ this.doc.settings,
78
+ this.docContent,
79
+ this.htmlExportTemplate,
80
+ this.imageDB,
81
+ this.bibDB,
82
+ this.csl,
83
+ this.styleSheets,
84
+ this.converterOptions
85
+ )
86
+ const {html, imageIds, metaData, extraStyleSheets} =
87
+ await this.converter.init()
88
+ this.metaData = metaData
89
+ if (this.converter.features.math) {
90
+ this.includeZips.push({
91
+ directory: "css",
92
+ url: staticUrl("zip/mathlive_style.zip")
93
+ })
94
+ }
95
+ this.addDoc(html)
96
+ this.addImages(imageIds)
97
+ await Promise.all(
98
+ extraStyleSheets.map(async sheet => await this.loadStyle(sheet))
99
+ )
100
+ }
101
+
102
+ getProcessedFiles() {
103
+ // Return the processed files and metadata. Used when using the
104
+ // exporter in a different context than creating a zip file.
105
+ return {
106
+ textFiles: this.textFiles,
107
+ httpFiles: this.httpFiles,
108
+ includeZips: this.includeZips,
109
+ metaData: this.metaData,
110
+ converter: this.converter
111
+ }
112
+ }
113
+
114
+ addDoc(html) {
115
+ this.textFiles.push({
116
+ filename: this.contentFileName,
117
+ contents: pretty(html, {ocd: true})
118
+ })
119
+ }
120
+
121
+ addImages(imageIds) {
122
+ imageIds.forEach(id => {
123
+ const image = this.imageDB.db[id]
124
+ this.httpFiles.push({
125
+ filename: `images/${image.image.split("/").pop()}`,
126
+ url: image.image
127
+ })
128
+ })
129
+ }
130
+
131
+ getDocStyle(doc) {
132
+ const docStyle = this.documentStyles.find(
133
+ docStyle => docStyle.slug === doc.settings.documentstyle
134
+ )
135
+
136
+ // The files will be in the base directory. The filenames of
137
+ // DocumentStyleFiles will therefore not need to replaced with their URLs.
138
+ if (!docStyle) {
139
+ return false
140
+ }
141
+ let contents = docStyle.contents
142
+ docStyle.documentstylefile_set.forEach(
143
+ ([_url, filename]) =>
144
+ (contents = contents.replace(
145
+ new RegExp(filename, "g"),
146
+ `media/${filename}`
147
+ ))
148
+ )
149
+ this.httpFiles = this.httpFiles.concat(
150
+ docStyle.documentstylefile_set.map(([url, filename]) => ({
151
+ filename: `css/media/${filename}`,
152
+ url
153
+ }))
154
+ )
155
+ return {contents, filename: `css/${docStyle.slug}.css`}
156
+ }
157
+
158
+ async loadStyle(sheet) {
159
+ if (sheet.url) {
160
+ // Use simple fetch without X-Requested-With header and credentials
161
+ // to avoid CORS preflight redirect issues with CDNs
162
+ const response = await fetch(sheet.url)
163
+ if (!response.ok) {
164
+ throw response
165
+ }
166
+ const text = await response.text()
167
+ sheet.contents = text
168
+ sheet.filename = `css/${sheet.url.split("/").pop().split("?")[0]}`
169
+ delete sheet.url
170
+ }
171
+ if (sheet.filename) {
172
+ this.textFiles.push(sheet)
173
+ }
174
+ return Promise.resolve(sheet)
175
+ }
176
+
177
+ async createZip() {
178
+ const zipper = new ZipFileCreator(
179
+ this.textFiles,
180
+ this.httpFiles,
181
+ this.includeZips,
182
+ this.mimeType,
183
+ this.updated
184
+ )
185
+ const blob = await zipper.init()
186
+ return this.download(blob)
187
+ }
188
+
189
+ download(blob) {
190
+ return download(blob, this.zipFileName, this.mimeType)
191
+ }
192
+ }
@@ -0,0 +1,34 @@
1
+ import {escapeText} from "../../common/index.js"
2
+
3
+ /** A template for HTML export of a document. */
4
+ export const htmlExportTemplate = ({
5
+ head,
6
+ body,
7
+ back,
8
+ settings,
9
+ lang,
10
+ xhtml,
11
+ epub
12
+ }) =>
13
+ `${xhtml ? '<?xml version="1.0" encoding="UTF-8"?>' : "<!DOCTYPE html>"}
14
+ <html ${xhtml ? `xmlns="http://www.w3.org/1999/xhtml" ${epub ? 'xmlns:epub="http://www.idpf.org/2007/ops"' : ""}` : ""} lang="${lang}"${xhtml ? ` xml:lang="${lang}"` : ""}>
15
+ <head>
16
+ <meta charset="UTF-8"${xhtml ? " /" : ""}>
17
+ ${settings.copyright && settings.copyright.holder ? `<meta name="copyright" content="© ${settings.copyright.year ? settings.copyright.year : new Date().getFullYear()} ${escapeText(settings.copyright.holder)}"${xhtml ? " /" : ""}>` : ""}
18
+ ${head}
19
+ </head>
20
+ <body class="doc user-contents">
21
+ ${body}
22
+ ${back}
23
+ ${
24
+ settings.copyright && settings.copyright.holder
25
+ ? `<div>© ${settings.copyright.year ? settings.copyright.year : new Date().getFullYear()} ${escapeText(settings.copyright.holder)}</div>`
26
+ : ""
27
+ }
28
+ ${
29
+ settings.copyright && settings.copyright.licenses.length
30
+ ? `<div>${settings.copyright.licenses.map(license => `<a rel="license" href="${escapeText(license.url)}">${escapeText(license.title)}${license.start ? ` (${license.start})` : ""}</a>`).join("</div><div>")}</div>`
31
+ : ""
32
+ }
33
+ </body>
34
+ </html>`
@@ -0,0 +1,50 @@
1
+ const numberToRoman = number => {
2
+ let roman = ""
3
+ const romanNumList = {
4
+ M: 1000,
5
+ CM: 900,
6
+ D: 500,
7
+ CD: 400,
8
+ C: 100,
9
+ XC: 90,
10
+ L: 50,
11
+ XL: 40,
12
+ X: 10,
13
+ IX: 9,
14
+ V: 5,
15
+ IV: 4,
16
+ I: 1
17
+ }
18
+ let a
19
+ for (const key in romanNumList) {
20
+ a = Math.floor(number / romanNumList[key])
21
+ if (a >= 0) {
22
+ for (let i = 0; i < a; i++) {
23
+ roman += key
24
+ }
25
+ }
26
+ number = number % romanNumList[key]
27
+ }
28
+ return roman
29
+ }
30
+
31
+ const numberToAlpha = number => {
32
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
33
+ let alpha = ""
34
+ let a
35
+ for (let i = 0; i < number; i++) {
36
+ a = i % 26
37
+ alpha += alphabet[a]
38
+ }
39
+ return alpha
40
+ }
41
+
42
+ export const displayNumber = (number, system) => {
43
+ if (system === "roman") {
44
+ return numberToRoman(number)
45
+ }
46
+ if (system === "alpha") {
47
+ return numberToAlpha(number)
48
+ }
49
+ return number
50
+ }
@@ -0,0 +1,183 @@
1
+ import {escapeText} from "../../common/index.js"
2
+ import {convertTexts} from "./text.js"
3
+
4
+ // This list is based on values listed at https://jats.nlm.nih.gov/archiving/tag-library/1.2/attribute/publication-type.html
5
+ // And the advice given here: https://jats4r.org/citations/#recommendation
6
+ const PUBLICATION_TYPES = {
7
+ article: "journal",
8
+ "article-journal": "journal",
9
+ "article-magazine": "journal",
10
+ "article-newspaper": "journal",
11
+ book: "book",
12
+ bookinbook: "book",
13
+ booklet: "book",
14
+ chapter: "book",
15
+ collection: "standard",
16
+ dataset: "dataset",
17
+ "entry-dictionary": "standard",
18
+ "entry-encyclopedia": "standard",
19
+ inbook: "book",
20
+ incollection: "book",
21
+ inproceedings: "standard",
22
+ inreference: "standard",
23
+ manual: "book",
24
+ misc: "standard",
25
+ mvbook: "book",
26
+ mvcollection: "standard",
27
+ mvproceedings: "book",
28
+ mvreference: "standard",
29
+ online: "standard",
30
+ patent: "patent",
31
+ periodical: "book",
32
+ post: "standards",
33
+ "post-weblog": "standard",
34
+ proceedings: "book",
35
+ reference: "standard",
36
+ report: "report",
37
+ review: "review",
38
+ suppbook: "book",
39
+ suppcollection: "book",
40
+ suppperiodical: "journal",
41
+ thesis: "standard",
42
+ unpublished: "standard"
43
+ }
44
+
45
+ export function jatsBib(bib, id) {
46
+ let start = "",
47
+ end = ""
48
+ start += `<ref id="ref-${id}">`
49
+ end = "</ref>" + end
50
+ // Type
51
+ const publicationType = PUBLICATION_TYPES[bib.bib_type] ?? "standard"
52
+ start += `<element-citation publication-type="${publicationType}">`
53
+ end = "</element-citation>" + end
54
+
55
+ // authors
56
+ if (bib.fields.author && bib.fields.author.length) {
57
+ start += `<person-group person-group-type="author">${bib.fields.author
58
+ .map(author => {
59
+ if (author.literal) {
60
+ return `<collab>${convertTexts(author.literal)}</collab>`
61
+ }
62
+ let nameStart = `<name><surname>${convertTexts(author.family)}</surname> <given-names>${convertTexts(author.given)}</given-names>`
63
+ if (author.prefix && author.prefix.length) {
64
+ nameStart += ` <prefix>${convertTexts(author.prefix)}</prefix>`
65
+ }
66
+ if (author.suffix && author.suffix.length) {
67
+ nameStart += ` <suffix>${convertTexts(author.suffix)}</suffix>`
68
+ }
69
+ const nameEnd = "</name>"
70
+ return nameStart + nameEnd
71
+ })
72
+ .join(", ")}</person-group>`
73
+ }
74
+
75
+ // title && container title
76
+ if (bib.fields.title) {
77
+ if (
78
+ bib.fields.shortjournal ||
79
+ bib.fields.booktitle ||
80
+ bib.fields.journaltitle
81
+ ) {
82
+ start += `<source>${convertTexts(bib.fields.shortjournal || bib.fields.booktitle || bib.fields.journaltitle)}</source>`
83
+ start += `<article-title>${convertTexts(bib.fields.title)}</article-title>`
84
+ } else {
85
+ start += `<source>${convertTexts(bib.fields.title)}</source>`
86
+ }
87
+ }
88
+
89
+ // editors
90
+ if (bib.fields.editor && bib.fields.editor.length) {
91
+ start += `<person-group person-group-type="editor">${bib.fields.editor
92
+ .map(editor => {
93
+ if (editor.literal) {
94
+ return `<collab>${convertTexts(editor.literal)}</collab>`
95
+ }
96
+ let nameStart = `<name><surname>${convertTexts(editor.family)}</surname> <given-names>${convertTexts(editor.given)}</given-names>`
97
+ const nameEnd = "</name>"
98
+ if (editor.prefix && editor.prefix.length) {
99
+ nameStart = `<prefix>${convertTexts(editor.prefix)}</prefix>`
100
+ }
101
+ if (editor.suffix && editor.suffix.length) {
102
+ nameStart = `<suffix>${convertTexts(editor.suffix)}</suffix>`
103
+ }
104
+ return nameStart + nameEnd
105
+ })
106
+ .join(", ")}</person-group>`
107
+ }
108
+
109
+ // publisher
110
+ if (bib.fields.publisher && bib.fields.publisher.length) {
111
+ start += bib.fields.publisher
112
+ .map(
113
+ publisher =>
114
+ `<publisher-name>${convertTexts(publisher)}</publisher-name>`
115
+ )
116
+ .join("")
117
+ }
118
+
119
+ // location
120
+ if (bib.fields.location && bib.fields.location.length) {
121
+ start += bib.fields.location
122
+ .map(
123
+ location =>
124
+ `<publisher-loc>${convertTexts(location)}</publisher-loc>`
125
+ )
126
+ .join("")
127
+ }
128
+
129
+ // date
130
+ if (bib.fields.date && bib.fields.date.length) {
131
+ const date = bib.fields.date
132
+ const dateParts = date.split("-")
133
+ start += `<date iso-8601-date="${date}" date-type="published">${
134
+ dateParts.length > 2 ? `<day>${dateParts[2]}</day>` : ""
135
+ }${
136
+ dateParts.length > 1 ? `<month>${dateParts[1]}</month>` : ""
137
+ }<year>${dateParts[0]}</year></date>`
138
+ }
139
+
140
+ // volume
141
+ if (bib.fields.volume && bib.fields.volume.length) {
142
+ start += `<volume>${convertTexts(bib.fields.volume)}</volume>`
143
+ }
144
+
145
+ // issue
146
+ if (bib.fields.issue && bib.fields.issue.length) {
147
+ start += `<issue>${convertTexts(bib.fields.issue)}</issue>`
148
+ }
149
+
150
+ // pages
151
+ if (bib.fields.pages && bib.fields.pages.length) {
152
+ start += `<fpage>${convertTexts(bib.fields.pages[0][0])}</fpage>`
153
+ start += `<lpage>${convertTexts(bib.fields.pages.slice(-1)[0].slice(-1)[0])}</lpage>`
154
+ if (bib.fields.pages.length > 1) {
155
+ start += `<page-range>${bib.fields.pages
156
+ .map(pages => pages.map(page => convertTexts(page)).join("-"))
157
+ .join(", ")}</page-range>`
158
+ }
159
+ }
160
+
161
+ // doi
162
+ if (bib.fields.doi && bib.fields.doi.length) {
163
+ start += `<pub-id pub-id-type="doi">${escapeText(bib.fields.doi)}</pub-id>`
164
+ }
165
+
166
+ // url
167
+ if (bib.fields.url && bib.fields.url.length) {
168
+ start += `<ext-link ext-link-type="web" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${escapeText(bib.fields.url)}"/>`
169
+ }
170
+
171
+ // url date
172
+ if (bib.fields.urldate && bib.fields.urldate.length) {
173
+ const date = bib.fields.urldate
174
+ const dateParts = date.split("-")
175
+ start += `<date-in-citation content-type="access-date" iso-8601-date="${date}">${
176
+ dateParts.length > 2 ? `<day>${dateParts[2]}</day>` : ""
177
+ }${
178
+ dateParts.length > 1 ? `<month>${dateParts[1]}</month>` : ""
179
+ }<year>${dateParts[0]}</year></date-in-citation>`
180
+ }
181
+
182
+ return start + end
183
+ }
@@ -0,0 +1,109 @@
1
+ import {FormatCitations} from "../../citations/format.js"
2
+
3
+ import {jatsBib} from "./bibliography.js"
4
+
5
+ export class JATSExporterCitations {
6
+ constructor(doc, bibDB, csl) {
7
+ this.doc = doc
8
+ this.bibDB = bibDB
9
+ this.csl = csl
10
+
11
+ this.citationTexts = []
12
+ this.citFm = false
13
+ this.jatsBib = ""
14
+ this.jatsIdConvert = {}
15
+ }
16
+
17
+ init(citInfos) {
18
+ this.citInfos = citInfos
19
+ if (!citInfos.length) {
20
+ return Promise.resolve()
21
+ }
22
+ return this.formatCitations()
23
+ }
24
+
25
+ // Citations are highly interdependent -- so we need to format them all
26
+ // together before laying out the document.
27
+ // We disregard the styling of the bibliography and instead create our own, JATS-specific bibliography.
28
+ formatCitations() {
29
+ return this.csl
30
+ .getStyle(this.doc.settings.citationstyle)
31
+ .then(citationstyle => {
32
+ const modStyle = JSON.parse(JSON.stringify(citationstyle))
33
+ const citationLayout = modStyle.children
34
+ .find(section => section.name === "citation")
35
+ .children.find(section => section.name === "layout").attrs
36
+ const origCitationLayout = JSON.parse(
37
+ JSON.stringify(citationLayout)
38
+ )
39
+ citationLayout.prefix = "{{prefix}}"
40
+ citationLayout.suffix = "{{suffix}}"
41
+ citationLayout.delimiter = "{{delimiter}}"
42
+ this.citFm = new FormatCitations(
43
+ this.csl,
44
+ this.citInfos,
45
+ modStyle,
46
+ "",
47
+ this.bibDB,
48
+ false,
49
+ this.doc.settings.language
50
+ )
51
+ return Promise.all([
52
+ Promise.resolve(origCitationLayout),
53
+ this.citFm.init()
54
+ ])
55
+ })
56
+ .then(([origCitationLayout]) => {
57
+ // We need to add xref-links to the bibliography items. And there may be more than one work cited
58
+ // so we need to first split, then add the links and eventually put the citation back together
59
+ // again.
60
+ // The IDs used in the jats bibliography are 1 and up in this order
61
+ this.citFm.bibliography[0].entry_ids.forEach((id, index) => {
62
+ this.jatsIdConvert[id] = index + 1
63
+ this.jatsBib += jatsBib(this.bibDB.db[id], index + 1)
64
+ })
65
+ this.citationTexts = this.citFm.citationTexts.map(
66
+ (ref, index) => {
67
+ const content = ref
68
+ .split("{{delimiter}}")
69
+ .map((citationText, conIndex) => {
70
+ const prefixSplit =
71
+ citationText.split("{{prefix}}")
72
+ const prefix =
73
+ prefixSplit.length > 1
74
+ ? prefixSplit.shift() +
75
+ (origCitationLayout.prefix || "")
76
+ : ""
77
+ citationText = prefixSplit[0]
78
+ const suffixSplit =
79
+ citationText.split("{{suffix}}")
80
+ const suffix =
81
+ suffixSplit.length > 1
82
+ ? (origCitationLayout.suffix || "") +
83
+ suffixSplit.pop()
84
+ : ""
85
+ citationText = suffixSplit[0]
86
+ const citId =
87
+ this.citFm.citations[index].sortedItems[
88
+ conIndex
89
+ ][1].id
90
+ const jatsId = this.jatsIdConvert[citId]
91
+ return `${prefix}<xref ref-type="bibr" rid="ref-${jatsId}">${citationText}</xref>${suffix}`
92
+ })
93
+ .join(origCitationLayout.delimiter || "")
94
+ return content
95
+ .replace(/<b>/g, "<bold>")
96
+ .replace(/<\/b>/g, "</bold>")
97
+ .replace(/<i>/g, "<italic>")
98
+ .replace(/<\/i>/g, "</italic>")
99
+ .replace(
100
+ /<span style="font-variant:small-caps;">/g,
101
+ "<sc>"
102
+ )
103
+ .replace(/<\/span>/g, "</sc>")
104
+ }
105
+ )
106
+ return Promise.resolve()
107
+ })
108
+ }
109
+ }