@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.
- package/LICENSE +661 -0
- package/README.md +16 -0
- package/jest.config.js +23 -0
- package/package.json +59 -0
- package/schema.json +1 -0
- package/scripts/export-schema.js +16 -0
- package/src/bibliography/common.js +92 -0
- package/src/bibliography/csl_bib.js +139 -0
- package/src/citations/citeproc_sys.js +42 -0
- package/src/citations/format.js +194 -0
- package/src/common/blob.js +10 -0
- package/src/common/file.js +25 -0
- package/src/common/index.js +12 -0
- package/src/common/network.js +79 -0
- package/src/common/text.js +44 -0
- package/src/editor/e2ee/encryptor.js +228 -0
- package/src/exporter/docx/citations.js +177 -0
- package/src/exporter/docx/comments.js +165 -0
- package/src/exporter/docx/footnotes.js +240 -0
- package/src/exporter/docx/images.js +101 -0
- package/src/exporter/docx/index.js +185 -0
- package/src/exporter/docx/lists.js +260 -0
- package/src/exporter/docx/math.js +46 -0
- package/src/exporter/docx/metadata.js +289 -0
- package/src/exporter/docx/rels.js +193 -0
- package/src/exporter/docx/render.js +941 -0
- package/src/exporter/docx/richtext.js +1182 -0
- package/src/exporter/docx/tables.js +112 -0
- package/src/exporter/docx/tools.js +50 -0
- package/src/exporter/epub/index.js +142 -0
- package/src/exporter/epub/templates.js +140 -0
- package/src/exporter/epub/tools.js +96 -0
- package/src/exporter/html/citations.js +121 -0
- package/src/exporter/html/convert.js +813 -0
- package/src/exporter/html/index.js +192 -0
- package/src/exporter/html/templates.js +34 -0
- package/src/exporter/html/tools.js +50 -0
- package/src/exporter/jats/bibliography.js +183 -0
- package/src/exporter/jats/citations.js +109 -0
- package/src/exporter/jats/convert.js +871 -0
- package/src/exporter/jats/index.js +92 -0
- package/src/exporter/jats/templates.js +35 -0
- package/src/exporter/jats/text.js +72 -0
- package/src/exporter/latex/convert.js +934 -0
- package/src/exporter/latex/escape_latex.js +21 -0
- package/src/exporter/latex/index.js +74 -0
- package/src/exporter/latex/readme.js +22 -0
- package/src/exporter/native/shrink.js +132 -0
- package/src/exporter/odt/citations.js +101 -0
- package/src/exporter/odt/footnotes.js +147 -0
- package/src/exporter/odt/images.js +115 -0
- package/src/exporter/odt/index.js +156 -0
- package/src/exporter/odt/math.js +57 -0
- package/src/exporter/odt/metadata.js +251 -0
- package/src/exporter/odt/render.js +806 -0
- package/src/exporter/odt/richtext.js +865 -0
- package/src/exporter/odt/styles.js +387 -0
- package/src/exporter/odt/track.js +68 -0
- package/src/exporter/pandoc/citations.js +98 -0
- package/src/exporter/pandoc/convert.js +1017 -0
- package/src/exporter/pandoc/index.js +92 -0
- package/src/exporter/pandoc/readme.js +8 -0
- package/src/exporter/pandoc/tools.js +51 -0
- package/src/exporter/print/index.js +177 -0
- package/src/exporter/tools/doc_content.js +144 -0
- package/src/exporter/tools/file.js +9 -0
- package/src/exporter/tools/json.js +73 -0
- package/src/exporter/tools/svg.js +29 -0
- package/src/exporter/tools/xml.js +531 -0
- package/src/exporter/tools/xml_zip.js +95 -0
- package/src/exporter/tools/zip.js +90 -0
- package/src/exporter/tools/zotero_csl.js +93 -0
- package/src/importer/citations.js +129 -0
- package/src/importer/docx/citations.js +123 -0
- package/src/importer/docx/convert.js +1427 -0
- package/src/importer/docx/helpers.js +9 -0
- package/src/importer/docx/omml2mathml.js +1448 -0
- package/src/importer/docx/parse.js +735 -0
- package/src/importer/native/get_images.js +76 -0
- package/src/importer/native/update.js +29 -0
- package/src/importer/odt/citations.js +87 -0
- package/src/importer/odt/convert.js +1855 -0
- package/src/importer/pandoc/convert.js +884 -0
- package/src/importer/pandoc/helpers.js +84 -0
- package/src/importer/zip_analyzer.js +102 -0
- package/src/index.js +1 -0
- package/src/mathlive/opf_includes.js +24 -0
- package/src/schema/common/annotate.js +76 -0
- package/src/schema/common/base.js +118 -0
- package/src/schema/common/citation.js +62 -0
- package/src/schema/common/equation.js +31 -0
- package/src/schema/common/figure.js +190 -0
- package/src/schema/common/heading.js +43 -0
- package/src/schema/common/index.js +40 -0
- package/src/schema/common/list.js +95 -0
- package/src/schema/common/reference.js +100 -0
- package/src/schema/common/table.js +103 -0
- package/src/schema/common/track.js +190 -0
- package/src/schema/const.js +58 -0
- package/src/schema/convert.js +1272 -0
- package/src/schema/document/content.js +187 -0
- package/src/schema/document/index.js +117 -0
- package/src/schema/document/structure.js +452 -0
- package/src/schema/export.js +21 -0
- package/src/schema/footnotes.js +126 -0
- package/src/schema/footnotes_convert.js +31 -0
- package/src/schema/i18n.js +595 -0
- package/src/schema/index.js +5 -0
- package/src/schema/mini_json.js +61 -0
- 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
|
+
}
|