@manuscripts/transform 4.5.1 → 4.5.3
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/dist/cjs/jats/__tests__/data/section-categories.js +5 -5
- package/dist/cjs/jats/__tests__/jats-importer.test.js +19 -5
- package/dist/cjs/jats/exporter/jats-exporter.js +725 -910
- package/dist/cjs/jats/exporter/jats-versions.js +9 -9
- package/dist/cjs/jats/importer/jats-dom-parser.js +25 -24
- package/dist/cjs/jats/importer/jats-transformations.js +14 -30
- package/dist/cjs/lib/section-categories.js +31 -1
- package/dist/cjs/schema/index.js +3 -0
- package/dist/cjs/schema/migration/migration-scripts/4.5.3.js +37 -0
- package/dist/cjs/schema/migration/migration-scripts/index.js +2 -0
- package/dist/cjs/schema/nodes/abstract.js +51 -0
- package/dist/cjs/schema/nodes/abstracts.js +1 -1
- package/dist/cjs/schema/nodes/footnote.js +1 -0
- package/dist/cjs/schema/nodes/general_table_footnote.js +1 -0
- package/dist/cjs/transformer/node-names.js +1 -0
- package/dist/cjs/transformer/node-title.js +2 -0
- package/dist/cjs/version.js +1 -1
- package/dist/es/jats/__tests__/data/section-categories.js +5 -5
- package/dist/es/jats/__tests__/jats-importer.test.js +19 -5
- package/dist/es/jats/exporter/jats-exporter.js +728 -913
- package/dist/es/jats/exporter/jats-versions.js +7 -7
- package/dist/es/jats/importer/jats-dom-parser.js +25 -24
- package/dist/es/jats/importer/jats-transformations.js +14 -30
- package/dist/es/lib/section-categories.js +28 -0
- package/dist/es/schema/index.js +3 -0
- package/dist/es/schema/migration/migration-scripts/4.5.3.js +35 -0
- package/dist/es/schema/migration/migration-scripts/index.js +2 -0
- package/dist/es/schema/nodes/abstract.js +47 -0
- package/dist/es/schema/nodes/abstracts.js +1 -1
- package/dist/es/schema/nodes/footnote.js +1 -0
- package/dist/es/schema/nodes/general_table_footnote.js +1 -0
- package/dist/es/transformer/node-names.js +1 -0
- package/dist/es/transformer/node-title.js +2 -0
- package/dist/es/version.js +1 -1
- package/dist/types/jats/exporter/jats-exporter.d.ts +31 -27
- package/dist/types/jats/exporter/jats-versions.d.ts +4 -4
- package/dist/types/jats/importer/jats-dom-parser.d.ts +0 -1
- package/dist/types/lib/section-categories.d.ts +3 -0
- package/dist/types/schema/index.d.ts +1 -0
- package/dist/types/schema/migration/migration-scripts/4.5.3.d.ts +8 -0
- package/dist/types/schema/migration/migration-scripts/index.d.ts +2 -1
- package/dist/types/schema/nodes/abstract.d.ts +26 -0
- package/dist/types/schema/types.d.ts +1 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/jats/__tests__/__snapshots__/jats-exporter.test.ts.snap +3 -3
- package/src/jats/__tests__/__snapshots__/jats-importer.test.ts.snap +86 -132
- package/src/jats/__tests__/__snapshots__/jats-roundtrip.test.ts.snap +3 -3
- package/src/jats/__tests__/data/section-categories.ts +5 -5
- package/src/jats/__tests__/jats-importer.test.ts +22 -6
- package/src/jats/exporter/jats-exporter.ts +855 -1126
- package/src/jats/exporter/jats-versions.ts +11 -11
- package/src/jats/importer/jats-dom-parser.ts +34 -34
- package/src/jats/importer/jats-transformations.ts +21 -37
- package/src/lib/section-categories.ts +36 -0
- package/src/schema/index.ts +3 -0
- package/src/schema/migration/migration-scripts/4.5.3.ts +57 -0
- package/src/schema/migration/migration-scripts/index.ts +2 -0
- package/src/schema/nodes/abstract.ts +66 -0
- package/src/schema/nodes/abstracts.ts +2 -1
- package/src/schema/nodes/footnote.ts +1 -0
- package/src/schema/nodes/general_table_footnote.ts +1 -0
- package/src/schema/types.ts +1 -0
- package/src/transformer/node-names.ts +1 -0
- package/src/transformer/node-title.ts +2 -0
- package/src/version.ts +1 -1
|
@@ -59,7 +59,7 @@ const w3c_xmlserializer_1 = __importDefault(require("w3c-xmlserializer"));
|
|
|
59
59
|
const citeproc_1 = require("../../lib/citeproc");
|
|
60
60
|
const credit_roles_1 = require("../../lib/credit-roles");
|
|
61
61
|
const footnotes_1 = require("../../lib/footnotes");
|
|
62
|
-
const
|
|
62
|
+
const section_categories_1 = require("../../lib/section-categories");
|
|
63
63
|
const xml_1 = require("../../lib/xml");
|
|
64
64
|
const schema_1 = require("../../schema");
|
|
65
65
|
const transformer_1 = require("../../transformer");
|
|
@@ -67,20 +67,6 @@ const citeproc_2 = require("./citeproc");
|
|
|
67
67
|
const jats_versions_1 = require("./jats-versions");
|
|
68
68
|
const labels_1 = require("./labels");
|
|
69
69
|
const normalizeID = (id) => id.replace(/:/g, '_');
|
|
70
|
-
const parser = prosemirror_model_1.DOMParser.fromSchema(schema_1.schema);
|
|
71
|
-
const insertAbstractNode = (front, abstractNode) => {
|
|
72
|
-
const articleMeta = front.querySelector(':scope > article-meta');
|
|
73
|
-
if (!articleMeta) {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
const insertBeforeElement = articleMeta.querySelector('kwd-group, funding-group, support-group, conference, counts, custom-meta-group');
|
|
77
|
-
if (insertBeforeElement) {
|
|
78
|
-
articleMeta.insertBefore(abstractNode, insertBeforeElement);
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
articleMeta.appendChild(abstractNode);
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
70
|
const createCounter = () => {
|
|
85
71
|
const counts = new Map();
|
|
86
72
|
return {
|
|
@@ -93,7 +79,7 @@ const createCounter = () => {
|
|
|
93
79
|
};
|
|
94
80
|
};
|
|
95
81
|
exports.createCounter = createCounter;
|
|
96
|
-
const
|
|
82
|
+
const createDefaultIDGenerator = () => {
|
|
97
83
|
const counter = (0, exports.createCounter)();
|
|
98
84
|
return async (element) => {
|
|
99
85
|
const value = String(counter.increment(element.nodeName));
|
|
@@ -111,6 +97,7 @@ const chooseRefType = (type) => {
|
|
|
111
97
|
case schema_1.schema.nodes.table_element:
|
|
112
98
|
return 'table';
|
|
113
99
|
case schema_1.schema.nodes.section:
|
|
100
|
+
case schema_1.schema.nodes.abstract:
|
|
114
101
|
return 'sec';
|
|
115
102
|
case schema_1.schema.nodes.equation:
|
|
116
103
|
case schema_1.schema.nodes.equation_element:
|
|
@@ -119,10 +106,10 @@ const chooseRefType = (type) => {
|
|
|
119
106
|
return 'supplementary-material';
|
|
120
107
|
}
|
|
121
108
|
};
|
|
122
|
-
const sortContributors = (a, b) => Number(a.attrs.priority) - Number(b.attrs.priority);
|
|
123
109
|
class JATSExporter {
|
|
124
110
|
constructor() {
|
|
125
111
|
this.nodesMap = new Map();
|
|
112
|
+
this.contributorLabels = new Map();
|
|
126
113
|
this.populateNodesMap = () => {
|
|
127
114
|
this.manuscriptNode.descendants((node) => {
|
|
128
115
|
const type = node.type;
|
|
@@ -136,53 +123,53 @@ class JATSExporter {
|
|
|
136
123
|
this.populateNodesMap();
|
|
137
124
|
this.initCiteprocEngine(options);
|
|
138
125
|
this.createSerializer();
|
|
139
|
-
const
|
|
140
|
-
this.document = document.implementation.createDocument(null, 'article', document.implementation.createDocumentType('article',
|
|
141
|
-
const article = this.document.documentElement;
|
|
142
|
-
article.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', xml_1.XLINK_NAMESPACE);
|
|
143
|
-
const front = this.buildFront();
|
|
144
|
-
article.appendChild(front);
|
|
145
|
-
article.setAttribute('article-type', manuscriptNode.attrs.articleType || 'other');
|
|
146
|
-
article.setAttributeNS(xml_1.XML_NAMESPACE, 'lang', manuscriptNode.attrs.primaryLanguageCode || 'en');
|
|
126
|
+
const versionIDs = (0, jats_versions_1.selectVersionIDs)(options.version ?? '1.2');
|
|
127
|
+
this.document = document.implementation.createDocument(null, 'article', document.implementation.createDocumentType('article', versionIDs.publicID, versionIDs.systemID));
|
|
128
|
+
const $article = this.document.documentElement;
|
|
129
|
+
$article.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', xml_1.XLINK_NAMESPACE);
|
|
147
130
|
this.labelTargets = (0, labels_1.buildTargets)(manuscriptNode.descendants.bind(manuscriptNode));
|
|
148
131
|
this.footnoteLabels = (0, footnotes_1.generateFootnoteLabels)(manuscriptNode);
|
|
149
|
-
const body = this.buildBody();
|
|
150
|
-
|
|
151
|
-
this.
|
|
152
|
-
const
|
|
153
|
-
this.
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
this.
|
|
161
|
-
this.
|
|
162
|
-
this.
|
|
163
|
-
this.
|
|
132
|
+
const $body = this.buildBody();
|
|
133
|
+
const $back = this.buildBack();
|
|
134
|
+
this.routeBackmatterSections($body, $back);
|
|
135
|
+
const $coiStatement = this.extractCoiStatement($back);
|
|
136
|
+
$back.appendChild(this.buildRefList());
|
|
137
|
+
const $front = this.buildFront($coiStatement);
|
|
138
|
+
$article.appendChild($front);
|
|
139
|
+
$article.setAttribute('article-type', manuscriptNode.attrs.articleType || 'other');
|
|
140
|
+
$article.setAttributeNS(xml_1.XML_NAMESPACE, 'lang', manuscriptNode.attrs.primaryLanguageCode || 'en');
|
|
141
|
+
$article.appendChild($body);
|
|
142
|
+
$article.appendChild($back);
|
|
143
|
+
this.addParagraphsToSections($article);
|
|
144
|
+
this.fillEmptyTableFooters($article);
|
|
145
|
+
this.fillEmptyFootnotes($article);
|
|
146
|
+
this.fillEmptyListItem($article);
|
|
147
|
+
const $floatsGroup = this.buildFloatsGroup();
|
|
148
|
+
if ($floatsGroup) {
|
|
149
|
+
$article.appendChild($floatsGroup);
|
|
150
|
+
}
|
|
164
151
|
await this.rewriteIDs();
|
|
165
152
|
return (0, w3c_xmlserializer_1.default)(this.document);
|
|
166
153
|
};
|
|
167
|
-
this.appendChildNodeOfType = (element, node, type) => {
|
|
154
|
+
this.appendChildNodeOfType = ($element, node, type) => {
|
|
168
155
|
const childNode = this.getFirstChildOfType(type, node);
|
|
169
156
|
if (childNode) {
|
|
170
|
-
element.appendChild(this.serializeNode(childNode));
|
|
157
|
+
$element.appendChild(this.serializeNode(childNode));
|
|
171
158
|
}
|
|
172
159
|
};
|
|
173
|
-
this.appendChildrenNodeOfType = (element, node, type) => {
|
|
160
|
+
this.appendChildrenNodeOfType = ($element, node, type) => {
|
|
174
161
|
const children = this.getChildrenOfType(type, node);
|
|
175
|
-
children.map((childNode) => element.appendChild(this.serializeNode(childNode)));
|
|
162
|
+
children.map((childNode) => $element.appendChild(this.serializeNode(childNode)));
|
|
176
163
|
};
|
|
177
|
-
this.appendCaption = (element, node) => {
|
|
178
|
-
const caption = this.createElement('caption');
|
|
179
|
-
this.appendChildNodeOfType(caption, node, schema_1.schema.nodes.caption_title);
|
|
164
|
+
this.appendCaption = ($element, node) => {
|
|
165
|
+
const $caption = this.createElement('caption');
|
|
166
|
+
this.appendChildNodeOfType($caption, node, schema_1.schema.nodes.caption_title);
|
|
180
167
|
const captionNode = this.getChildrenOfType(schema_1.schema.nodes.caption, node)[0];
|
|
181
168
|
if (captionNode && captionNode.content.size > 2) {
|
|
182
|
-
this.appendChildrenNodeOfType(caption, captionNode, schema_1.schema.nodes.text_block);
|
|
169
|
+
this.appendChildrenNodeOfType($caption, captionNode, schema_1.schema.nodes.text_block);
|
|
183
170
|
}
|
|
184
|
-
if (caption.children.length > 0) {
|
|
185
|
-
element.appendChild(caption);
|
|
171
|
+
if ($caption.children.length > 0) {
|
|
172
|
+
$element.appendChild($caption);
|
|
186
173
|
}
|
|
187
174
|
};
|
|
188
175
|
this.initCiteprocEngine = (options) => {
|
|
@@ -217,33 +204,32 @@ class JATSExporter {
|
|
|
217
204
|
this.engine = engine;
|
|
218
205
|
this.renderedCitations = new Map(output.map((i) => [i[0], i[2]]));
|
|
219
206
|
};
|
|
220
|
-
this.nodeFromJATS = (
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
if (!JATSFragment.length) {
|
|
207
|
+
this.nodeFromJATS = (fragment) => {
|
|
208
|
+
fragment = fragment.trim().replace(' ', ' ');
|
|
209
|
+
if (!fragment.length) {
|
|
224
210
|
return null;
|
|
225
211
|
}
|
|
226
|
-
const template = this.createElement('template');
|
|
227
|
-
template.innerHTML =
|
|
228
|
-
return template.firstChild;
|
|
212
|
+
const $template = this.createElement('template');
|
|
213
|
+
$template.innerHTML = fragment;
|
|
214
|
+
return $template.firstChild;
|
|
229
215
|
};
|
|
230
|
-
this.rewriteIDs = async (generator =
|
|
216
|
+
this.rewriteIDs = async (generator = createDefaultIDGenerator()) => {
|
|
231
217
|
const ids = new Map();
|
|
232
|
-
for (const element of this.document.querySelectorAll('[id]')) {
|
|
233
|
-
const oldID = element.getAttribute('id');
|
|
234
|
-
const newID = await generator(element);
|
|
218
|
+
for (const $element of this.document.querySelectorAll('[id]')) {
|
|
219
|
+
const oldID = $element.getAttribute('id');
|
|
220
|
+
const newID = await generator($element);
|
|
235
221
|
if (newID) {
|
|
236
|
-
element.setAttribute('id', newID);
|
|
222
|
+
$element.setAttribute('id', newID);
|
|
237
223
|
}
|
|
238
224
|
else {
|
|
239
|
-
element.removeAttribute('id');
|
|
225
|
+
$element.removeAttribute('id');
|
|
240
226
|
}
|
|
241
227
|
if (oldID) {
|
|
242
228
|
ids.set(oldID, newID);
|
|
243
229
|
}
|
|
244
230
|
}
|
|
245
|
-
for (const node of this.document.querySelectorAll('[rid]')) {
|
|
246
|
-
const rids = node.getAttribute('rid');
|
|
231
|
+
for (const $node of this.document.querySelectorAll('[rid]')) {
|
|
232
|
+
const rids = $node.getAttribute('rid');
|
|
247
233
|
if (rids) {
|
|
248
234
|
const newRids = rids
|
|
249
235
|
.split(/\s+/)
|
|
@@ -251,126 +237,113 @@ class JATSExporter {
|
|
|
251
237
|
.map((rid) => ids.get(rid))
|
|
252
238
|
.filter(Boolean);
|
|
253
239
|
if (newRids.length) {
|
|
254
|
-
node.setAttribute('rid', newRids.join(' '));
|
|
240
|
+
$node.setAttribute('rid', newRids.join(' '));
|
|
255
241
|
}
|
|
256
242
|
}
|
|
257
243
|
}
|
|
258
244
|
};
|
|
259
|
-
this.
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
245
|
+
this.buildFront = ($coiStatement) => {
|
|
246
|
+
const $front = this.createElement('front');
|
|
247
|
+
const $articleMeta = this.createElement('article-meta');
|
|
248
|
+
$front.appendChild($articleMeta);
|
|
249
|
+
const contributors = this.getChildrenOfType(schema_1.schema.nodes.contributor).sort((a, b) => Number(a.attrs.priority) - Number(b.attrs.priority));
|
|
250
|
+
this.contributorLabels = this.computeContributorLabels(contributors);
|
|
251
|
+
const $frontNodes = [
|
|
252
|
+
this.buildArticleID(),
|
|
253
|
+
this.buildTitleGroup(),
|
|
254
|
+
this.buildContributorGroup(contributors),
|
|
255
|
+
this.buildAuthorNotes($coiStatement),
|
|
256
|
+
this.buildSupplements(),
|
|
257
|
+
this.buildHistory(),
|
|
258
|
+
this.buildSelfUris(),
|
|
259
|
+
this.buildAbstracts(),
|
|
260
|
+
this.buildKeywords(),
|
|
261
|
+
this.buildAwards(),
|
|
262
|
+
this.buildCounts(),
|
|
263
|
+
];
|
|
264
|
+
$frontNodes.forEach(($nodes) => this.appendChildren($articleMeta, $nodes));
|
|
265
|
+
return $front;
|
|
266
|
+
};
|
|
267
|
+
this.appendChildren = ($parent, $elements) => {
|
|
268
|
+
if (!$elements) {
|
|
269
|
+
return;
|
|
269
270
|
}
|
|
271
|
+
const list = Array.isArray($elements) ? $elements : [$elements];
|
|
272
|
+
list.forEach(($element) => $parent.appendChild($element));
|
|
270
273
|
};
|
|
271
|
-
this.
|
|
272
|
-
const front = this.createElement('front');
|
|
273
|
-
const articleMeta = this.createElement('article-meta');
|
|
274
|
-
front.appendChild(articleMeta);
|
|
274
|
+
this.buildArticleID = () => {
|
|
275
275
|
if (this.manuscriptNode.attrs.doi) {
|
|
276
|
-
const articleID = this.createElement('article-id');
|
|
277
|
-
articleID.setAttribute('pub-id-type', 'doi');
|
|
278
|
-
articleID.textContent = this.manuscriptNode.attrs.doi;
|
|
279
|
-
|
|
276
|
+
const $articleID = this.createElement('article-id');
|
|
277
|
+
$articleID.setAttribute('pub-id-type', 'doi');
|
|
278
|
+
$articleID.textContent = this.manuscriptNode.attrs.doi;
|
|
279
|
+
return $articleID;
|
|
280
280
|
}
|
|
281
|
-
|
|
281
|
+
};
|
|
282
|
+
this.buildTitleGroup = () => {
|
|
283
|
+
const $titleGroup = this.createElement('title-group');
|
|
282
284
|
const titleNode = this.getFirstChildOfType(schema_1.schema.nodes.title);
|
|
283
285
|
if (titleNode) {
|
|
284
|
-
|
|
285
|
-
this.setTitleContent(element, titleNode.textContent);
|
|
286
|
-
titleGroup.appendChild(element);
|
|
286
|
+
$titleGroup.appendChild(this.serializeNode(titleNode));
|
|
287
287
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
this.
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
supplementaryMaterial.setAttributeNS(xml_1.XLINK_NAMESPACE, 'href', node.attrs.href ?? '');
|
|
308
|
-
supplementaryMaterial.setAttribute('mimetype', node.attrs.mimeType ?? '');
|
|
309
|
-
supplementaryMaterial.setAttribute('mime-subtype', node.attrs.mimeSubType ?? '');
|
|
310
|
-
this.appendCaption(supplementaryMaterial, node);
|
|
311
|
-
articleMeta.append(supplementaryMaterial);
|
|
288
|
+
this.getChildrenOfType(schema_1.schema.nodes.subtitle).forEach((node) => $titleGroup.appendChild(this.serializeNode(node)));
|
|
289
|
+
this.getChildrenOfType(schema_1.schema.nodes.alt_title).forEach((node) => $titleGroup.appendChild(this.serializeNode(node)));
|
|
290
|
+
return $titleGroup;
|
|
291
|
+
};
|
|
292
|
+
this.buildSupplements = () => this.getChildrenOfType(schema_1.schema.nodes.supplement).map((node) => this.serializeNode(node));
|
|
293
|
+
this.buildHistory = () => {
|
|
294
|
+
const $history = this.createElement('history');
|
|
295
|
+
const dates = new Map([
|
|
296
|
+
['accepted', this.manuscriptNode.attrs.acceptanceDate],
|
|
297
|
+
['corrected', this.manuscriptNode.attrs.correctionDate],
|
|
298
|
+
['retracted', this.manuscriptNode.attrs.retractionDate],
|
|
299
|
+
['received', this.manuscriptNode.attrs.receiveDate],
|
|
300
|
+
['rev-recd', this.manuscriptNode.attrs.revisionReceiveDate],
|
|
301
|
+
['rev-request', this.manuscriptNode.attrs.revisionRequestDate],
|
|
302
|
+
]);
|
|
303
|
+
dates.forEach((val, key) => {
|
|
304
|
+
if (val) {
|
|
305
|
+
$history.appendChild(this.buildDateElement(val, key));
|
|
306
|
+
}
|
|
312
307
|
});
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
const date = this.buildDateElement(this.manuscriptNode.attrs.acceptanceDate, 'accepted');
|
|
316
|
-
history.appendChild(date);
|
|
317
|
-
}
|
|
318
|
-
if (this.manuscriptNode.attrs.correctionDate) {
|
|
319
|
-
const date = this.buildDateElement(this.manuscriptNode.attrs.correctionDate, 'corrected');
|
|
320
|
-
history.appendChild(date);
|
|
308
|
+
if ($history.childElementCount) {
|
|
309
|
+
return $history;
|
|
321
310
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
311
|
+
};
|
|
312
|
+
this.buildCounts = () => {
|
|
313
|
+
const $counts = this.createElement('counts');
|
|
314
|
+
const counts = new Map([
|
|
315
|
+
['fig-count', this.getChildrenOfType(schema_1.schema.nodes.figure).length],
|
|
316
|
+
['table-count', this.getChildrenOfType(schema_1.schema.nodes.table).length],
|
|
317
|
+
[
|
|
318
|
+
'equation-count',
|
|
319
|
+
this.getChildrenOfType(schema_1.schema.nodes.equation_element).length,
|
|
320
|
+
],
|
|
321
|
+
[
|
|
322
|
+
'ref-count',
|
|
323
|
+
this.getChildrenOfType(schema_1.schema.nodes.bibliography_item).length,
|
|
324
|
+
],
|
|
325
|
+
['word-count', this.manuscriptNode.textContent.split(/\s+/).length],
|
|
326
|
+
]);
|
|
327
|
+
counts.forEach((val, key) => {
|
|
328
|
+
if (val) {
|
|
329
|
+
$counts.appendChild(this.createElement(key, undefined, { count: String(val) }));
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
if ($counts.childElementCount) {
|
|
333
|
+
return $counts;
|
|
340
334
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
const
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
countingElements.push(this.buildCountingElement('table-count', tableCount));
|
|
347
|
-
const equationCount = this.getChildrenOfType(schema_1.schema.nodes.equation_element).length;
|
|
348
|
-
countingElements.push(this.buildCountingElement('equation-count', equationCount));
|
|
349
|
-
const referencesCount = this.getChildrenOfType(schema_1.schema.nodes.bibliography_item).length;
|
|
350
|
-
countingElements.push(this.buildCountingElement('ref-count', referencesCount));
|
|
351
|
-
const wordCount = this.manuscriptNode.textContent.split(/\s+/).length;
|
|
352
|
-
countingElements.push(this.buildCountingElement('word-count', wordCount));
|
|
353
|
-
countingElements = countingElements.filter((el) => el);
|
|
354
|
-
if (countingElements.length > 0) {
|
|
355
|
-
const counts = this.createElement('counts');
|
|
356
|
-
counts.append(...countingElements);
|
|
357
|
-
articleMeta.append(counts);
|
|
335
|
+
};
|
|
336
|
+
this.buildAwards = () => {
|
|
337
|
+
const awards = this.getFirstChildOfType(schema_1.schema.nodes.awards);
|
|
338
|
+
if (!awards || !awards.childCount) {
|
|
339
|
+
return;
|
|
358
340
|
}
|
|
359
|
-
|
|
360
|
-
attachments.forEach((attachment) => {
|
|
361
|
-
const $selfUri = this.createElement('self-uri');
|
|
362
|
-
$selfUri.setAttribute('content-type', attachment.attrs.type);
|
|
363
|
-
$selfUri.setAttributeNS(xml_1.XLINK_NAMESPACE, 'href', attachment.attrs.href);
|
|
364
|
-
const insertBeforeElements = articleMeta.querySelector('related-article, related-object, abstract, trans-abstract, kwd-group, funding-group, support-group, conference, counts, custom-meta-group');
|
|
365
|
-
insertBeforeElements
|
|
366
|
-
? articleMeta.insertBefore($selfUri, insertBeforeElements)
|
|
367
|
-
: articleMeta.appendChild($selfUri);
|
|
368
|
-
});
|
|
369
|
-
return front;
|
|
341
|
+
return this.serializeNode(awards);
|
|
370
342
|
};
|
|
343
|
+
this.buildSelfUris = () => this.getChildrenOfType(schema_1.schema.nodes.attachment).map((attachment) => this.serializeNode(attachment));
|
|
371
344
|
this.buildDateElement = (timestamp, type) => {
|
|
372
|
-
const
|
|
373
|
-
|
|
345
|
+
const $date = this.createElement('date');
|
|
346
|
+
$date.setAttribute('date-type', type);
|
|
374
347
|
const date = new Date(timestamp * 1000);
|
|
375
348
|
const lookup = {
|
|
376
349
|
year: date.getUTCFullYear().toString(),
|
|
@@ -378,127 +351,154 @@ class JATSExporter {
|
|
|
378
351
|
day: date.getUTCDate().toString().padStart(2, '0'),
|
|
379
352
|
};
|
|
380
353
|
for (const [key, value] of Object.entries(lookup).reverse()) {
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
dateElement.appendChild(el);
|
|
384
|
-
}
|
|
385
|
-
return dateElement;
|
|
386
|
-
};
|
|
387
|
-
this.buildCountingElement = (tagName, count) => {
|
|
388
|
-
if (count) {
|
|
389
|
-
const wordCount = this.createElement(tagName);
|
|
390
|
-
wordCount.setAttribute('count', String(count));
|
|
391
|
-
return wordCount;
|
|
354
|
+
const $datePart = this.createElement(key, value);
|
|
355
|
+
$date.appendChild($datePart);
|
|
392
356
|
}
|
|
357
|
+
return $date;
|
|
393
358
|
};
|
|
394
359
|
this.buildBody = () => {
|
|
395
|
-
const body = this.
|
|
396
|
-
this.
|
|
397
|
-
|
|
398
|
-
body.
|
|
360
|
+
const body = this.getFirstChildOfType(schema_1.schema.nodes.body);
|
|
361
|
+
const $body = this.createElement('body');
|
|
362
|
+
body?.forEach((node) => {
|
|
363
|
+
$body.appendChild(this.serializeNode(node));
|
|
399
364
|
});
|
|
400
|
-
|
|
401
|
-
return body;
|
|
365
|
+
return $body;
|
|
402
366
|
};
|
|
403
|
-
this.buildBack = (
|
|
404
|
-
const
|
|
405
|
-
this.
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
previousParent.remove();
|
|
417
|
-
}
|
|
367
|
+
this.buildBack = () => {
|
|
368
|
+
const backmatter = this.getFirstChildOfType(schema_1.schema.nodes.backmatter);
|
|
369
|
+
const $back = this.createElement('back');
|
|
370
|
+
backmatter?.forEach((node) => {
|
|
371
|
+
$back.appendChild(this.serializeNode(node));
|
|
372
|
+
});
|
|
373
|
+
return $back;
|
|
374
|
+
};
|
|
375
|
+
this.findSection = (category, ...$roots) => {
|
|
376
|
+
for (const $root of $roots) {
|
|
377
|
+
const $match = $root.querySelector(`sec[sec-type="${category}"]`);
|
|
378
|
+
if ($match) {
|
|
379
|
+
return $match;
|
|
418
380
|
}
|
|
419
381
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
382
|
+
};
|
|
383
|
+
this.findSections = (category, ...$roots) => $roots.flatMap(($root) => Array.from($root.querySelectorAll(`sec[sec-type="${category}"]`)));
|
|
384
|
+
this.routeBackmatterSections = ($body, $back) => {
|
|
385
|
+
const $footnoteSections = section_categories_1.FOOTNOTE_SECTION_CATEGORY_IDS.flatMap((category) => this.findSections(category, $body, $back).map(($section) => ({
|
|
386
|
+
$section,
|
|
387
|
+
category,
|
|
388
|
+
})));
|
|
389
|
+
let $fnGroup;
|
|
390
|
+
if ($footnoteSections.length) {
|
|
391
|
+
$fnGroup = this.createElement('fn-group');
|
|
392
|
+
for (const { $section, category } of $footnoteSections) {
|
|
393
|
+
$fnGroup.appendChild(this.sectionToFootnote($section, category));
|
|
394
|
+
}
|
|
423
395
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
396
|
+
const $appendices = this.findSections('appendices', $body, $back);
|
|
397
|
+
let $appGroup;
|
|
398
|
+
if ($appendices.length) {
|
|
399
|
+
$appGroup = this.createElement('app-group');
|
|
400
|
+
for (const $section of $appendices) {
|
|
401
|
+
const $app = this.createElement('app');
|
|
402
|
+
$app.appendChild($section);
|
|
403
|
+
$appGroup.appendChild($app);
|
|
432
404
|
}
|
|
433
405
|
}
|
|
434
|
-
|
|
406
|
+
const $ackSection = this.findSection('acknowledgements', $body, $back);
|
|
407
|
+
let $ack;
|
|
408
|
+
if ($ackSection) {
|
|
409
|
+
$ack = this.createElement('ack');
|
|
410
|
+
$ack.append(...$ackSection.childNodes);
|
|
411
|
+
$ackSection.remove();
|
|
412
|
+
}
|
|
413
|
+
const $availabilitySection = this.findSection('availability', $body, $back);
|
|
414
|
+
const $ethicsSection = this.findSection('ethics-statement', $body, $back);
|
|
415
|
+
const $prepend = [
|
|
416
|
+
$appGroup,
|
|
417
|
+
$ack,
|
|
418
|
+
$availabilitySection,
|
|
419
|
+
$ethicsSection,
|
|
420
|
+
$fnGroup,
|
|
421
|
+
].filter((el) => el != null);
|
|
422
|
+
if ($prepend.length) {
|
|
423
|
+
$back.prepend(...$prepend);
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
this.extractCoiStatement = ($back) => {
|
|
427
|
+
const $coiStatement = $back.querySelector('fn[fn-type="coi-statement"]');
|
|
428
|
+
if (!$coiStatement) {
|
|
429
|
+
return undefined;
|
|
430
|
+
}
|
|
431
|
+
const $fnGroup = $coiStatement.parentElement;
|
|
432
|
+
$coiStatement.remove();
|
|
433
|
+
if ($fnGroup && !$fnGroup.hasChildNodes()) {
|
|
434
|
+
$fnGroup.remove();
|
|
435
|
+
}
|
|
436
|
+
return $coiStatement;
|
|
437
|
+
};
|
|
438
|
+
this.buildRefList = () => {
|
|
439
|
+
const $refList = this.createElement('ref-list');
|
|
440
|
+
const [, bibliography] = this.engine.makeBibliography();
|
|
441
|
+
const parser = new DOMParser();
|
|
442
|
+
bibliography.forEach((item) => {
|
|
443
|
+
const fragment = `<template xmlns:xlink="${xml_1.XLINK_NAMESPACE}">${(0, xml_1.sanitizeXmlString)(item)}</template>`;
|
|
444
|
+
const $ref = parser
|
|
445
|
+
.parseFromString(fragment, 'text/xml')
|
|
446
|
+
.querySelector('ref');
|
|
447
|
+
if ($ref) {
|
|
448
|
+
$refList.appendChild($ref);
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
return $refList;
|
|
435
452
|
};
|
|
436
453
|
this.createElement = (tag, content, attrs) => {
|
|
437
|
-
const
|
|
454
|
+
const $element = this.document.createElement(tag);
|
|
438
455
|
if (content) {
|
|
439
|
-
|
|
456
|
+
$element.textContent = content;
|
|
440
457
|
}
|
|
441
458
|
if (attrs) {
|
|
442
459
|
Object.entries(attrs).forEach(([k, v]) => {
|
|
443
460
|
if (v) {
|
|
444
|
-
|
|
461
|
+
$element.setAttribute(k, v);
|
|
445
462
|
}
|
|
446
463
|
});
|
|
447
464
|
}
|
|
448
|
-
return
|
|
465
|
+
return $element;
|
|
449
466
|
};
|
|
450
|
-
this.appendElement = (parent, tag, content, attrs) => {
|
|
451
|
-
const
|
|
452
|
-
parent.appendChild(
|
|
453
|
-
return
|
|
467
|
+
this.appendElement = ($parent, tag, content, attrs) => {
|
|
468
|
+
const $element = this.createElement(tag, content, attrs);
|
|
469
|
+
$parent.appendChild($element);
|
|
470
|
+
return $element;
|
|
454
471
|
};
|
|
455
472
|
this.createSerializer = () => {
|
|
456
473
|
const nodes = {
|
|
457
|
-
trans_abstract: (node) =>
|
|
458
|
-
|
|
459
|
-
id: normalizeID(node.attrs.id),
|
|
460
|
-
};
|
|
461
|
-
if (node.attrs.lang) {
|
|
462
|
-
attrs[`${xml_1.XML_NAMESPACE} lang`] = node.attrs.lang;
|
|
463
|
-
}
|
|
464
|
-
if (node.attrs.category) {
|
|
465
|
-
attrs['sec-type'] = node.attrs.category;
|
|
466
|
-
}
|
|
467
|
-
return ['trans-abstract', attrs, 0];
|
|
468
|
-
},
|
|
469
|
-
trans_graphical_abstract: (node) => {
|
|
470
|
-
const attrs = {
|
|
471
|
-
id: normalizeID(node.attrs.id),
|
|
472
|
-
};
|
|
473
|
-
if (node.attrs.lang) {
|
|
474
|
-
attrs[`${xml_1.XML_NAMESPACE} lang`] = node.attrs.lang;
|
|
475
|
-
}
|
|
476
|
-
if (node.attrs.category) {
|
|
477
|
-
attrs['sec-type'] = node.attrs.category;
|
|
478
|
-
}
|
|
479
|
-
return ['trans-abstract', attrs, 0];
|
|
480
|
-
},
|
|
474
|
+
trans_abstract: (node) => createTransAbstract(node),
|
|
475
|
+
trans_graphical_abstract: (node) => createTransAbstract(node),
|
|
481
476
|
hero_image: () => '',
|
|
482
477
|
headshot_grid: () => ['p', { 'content-type': 'headshots' }, 0],
|
|
483
478
|
headshot_element: (node) => createImage(node),
|
|
484
479
|
headshot_image: () => '',
|
|
485
480
|
alt_text: (node) => {
|
|
486
481
|
if (node.textContent) {
|
|
487
|
-
const altText = this.createElement('alt-text');
|
|
488
|
-
altText.textContent = node.textContent;
|
|
489
|
-
return altText;
|
|
482
|
+
const $altText = this.createElement('alt-text');
|
|
483
|
+
$altText.textContent = node.textContent;
|
|
484
|
+
return $altText;
|
|
490
485
|
}
|
|
491
486
|
return '';
|
|
492
487
|
},
|
|
493
488
|
long_desc: (node) => {
|
|
494
489
|
if (node.textContent) {
|
|
495
|
-
const longDesc = this.createElement('long-desc');
|
|
496
|
-
longDesc.textContent = node.textContent;
|
|
497
|
-
return longDesc;
|
|
490
|
+
const $longDesc = this.createElement('long-desc');
|
|
491
|
+
$longDesc.textContent = node.textContent;
|
|
492
|
+
return $longDesc;
|
|
498
493
|
}
|
|
499
494
|
return '';
|
|
500
495
|
},
|
|
501
|
-
attachment: () =>
|
|
496
|
+
attachment: (node) => {
|
|
497
|
+
const $selfUri = this.createElement('self-uri');
|
|
498
|
+
$selfUri.setAttribute('content-type', node.attrs.type);
|
|
499
|
+
$selfUri.setAttributeNS(xml_1.XLINK_NAMESPACE, 'href', node.attrs.href);
|
|
500
|
+
return $selfUri;
|
|
501
|
+
},
|
|
502
502
|
attachments: () => '',
|
|
503
503
|
image_element: (node) => createImage(node),
|
|
504
504
|
embed: (node) => {
|
|
@@ -506,41 +506,45 @@ class JATSExporter {
|
|
|
506
506
|
if (!href) {
|
|
507
507
|
return '';
|
|
508
508
|
}
|
|
509
|
-
const
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
509
|
+
const $media = this.createElement('media');
|
|
510
|
+
$media.setAttribute('id', normalizeID(id));
|
|
511
|
+
$media.setAttributeNS(xml_1.XLINK_NAMESPACE, 'show', 'embed');
|
|
512
|
+
$media.setAttributeNS(xml_1.XLINK_NAMESPACE, 'href', href);
|
|
513
513
|
if (mimetype) {
|
|
514
|
-
|
|
514
|
+
$media.setAttribute('mimetype', node.attrs.mimetype);
|
|
515
515
|
}
|
|
516
516
|
if (mimeSubtype) {
|
|
517
|
-
|
|
517
|
+
$media.setAttribute('mime-subtype', node.attrs.mimeSubtype);
|
|
518
518
|
}
|
|
519
|
-
appendLabels(
|
|
520
|
-
this.appendChildNodeOfType(
|
|
521
|
-
this.appendChildNodeOfType(
|
|
522
|
-
this.appendCaption(
|
|
523
|
-
return
|
|
519
|
+
appendLabels($media, node);
|
|
520
|
+
this.appendChildNodeOfType($media, node, schema_1.schema.nodes.alt_text);
|
|
521
|
+
this.appendChildNodeOfType($media, node, schema_1.schema.nodes.long_desc);
|
|
522
|
+
this.appendCaption($media, node);
|
|
523
|
+
return $media;
|
|
524
524
|
},
|
|
525
525
|
awards: () => ['funding-group', 0],
|
|
526
526
|
award: (node) => {
|
|
527
527
|
const awardGroup = node;
|
|
528
|
-
const
|
|
529
|
-
|
|
530
|
-
appendChildIfPresent(
|
|
528
|
+
const $awardGroup = this.createElement('award-group');
|
|
529
|
+
$awardGroup.setAttribute('id', normalizeID(awardGroup.attrs.id));
|
|
530
|
+
appendChildIfPresent($awardGroup, 'funding-source', awardGroup.attrs.source);
|
|
531
531
|
awardGroup.attrs.code
|
|
532
532
|
?.split(';')
|
|
533
|
-
.forEach((code) => appendChildIfPresent(
|
|
534
|
-
appendChildIfPresent(
|
|
535
|
-
return
|
|
533
|
+
.forEach((code) => appendChildIfPresent($awardGroup, 'award-id', code));
|
|
534
|
+
appendChildIfPresent($awardGroup, 'principal-award-recipient', awardGroup.attrs.recipient);
|
|
535
|
+
return $awardGroup;
|
|
536
536
|
},
|
|
537
537
|
box_element: (node) => createBoxElement(node),
|
|
538
538
|
author_notes: () => '',
|
|
539
539
|
corresp: () => '',
|
|
540
|
-
title: () => '',
|
|
541
|
-
alt_title: () =>
|
|
540
|
+
title: () => ['article-title', 0],
|
|
541
|
+
alt_title: (node) => [
|
|
542
|
+
'alt-title',
|
|
543
|
+
{ 'alt-title-type': node.attrs.type },
|
|
544
|
+
0,
|
|
545
|
+
],
|
|
542
546
|
alt_titles: () => '',
|
|
543
|
-
subtitle: () => '',
|
|
547
|
+
subtitle: () => ['subtitle', 0],
|
|
544
548
|
subtitles: () => '',
|
|
545
549
|
text_block: (node) => nodes.paragraph(node),
|
|
546
550
|
affiliations: () => '',
|
|
@@ -548,17 +552,31 @@ class JATSExporter {
|
|
|
548
552
|
table_element_footer: (node) => node.childCount == 0
|
|
549
553
|
? ['table-wrap-foot', ['fn-group', ['fn', ['p']]]]
|
|
550
554
|
: ['table-wrap-foot', 0],
|
|
551
|
-
contributor: () =>
|
|
552
|
-
affiliation: () =>
|
|
555
|
+
contributor: (node) => this.buildContributorElement(node),
|
|
556
|
+
affiliation: (node) => this.buildAffiliationElement(node),
|
|
553
557
|
attribution: () => ['attrib', 0],
|
|
554
558
|
bibliography_element: () => '',
|
|
555
559
|
bibliography_item: () => '',
|
|
556
560
|
comments: () => '',
|
|
557
|
-
keyword_group: () =>
|
|
561
|
+
keyword_group: (node) => {
|
|
562
|
+
const attrs = {};
|
|
563
|
+
if (node.attrs.type) {
|
|
564
|
+
attrs['kwd-group-type'] = node.attrs.type;
|
|
565
|
+
}
|
|
566
|
+
return ['kwd-group', attrs, 0];
|
|
567
|
+
},
|
|
558
568
|
body: () => ['body', 0],
|
|
559
569
|
abstracts: () => ['abstract', 0],
|
|
560
570
|
backmatter: () => ['backmatter', 0],
|
|
561
|
-
supplement: () =>
|
|
571
|
+
supplement: (node) => {
|
|
572
|
+
const $supplementaryMaterial = this.createElement('supplementary-material');
|
|
573
|
+
$supplementaryMaterial.setAttribute('id', normalizeID(node.attrs.id));
|
|
574
|
+
$supplementaryMaterial.setAttributeNS(xml_1.XLINK_NAMESPACE, 'href', node.attrs.href ?? '');
|
|
575
|
+
$supplementaryMaterial.setAttribute('mimetype', node.attrs.mimeType ?? '');
|
|
576
|
+
$supplementaryMaterial.setAttribute('mime-subtype', node.attrs.mimeSubType ?? '');
|
|
577
|
+
this.appendCaption($supplementaryMaterial, node);
|
|
578
|
+
return $supplementaryMaterial;
|
|
579
|
+
},
|
|
562
580
|
supplements: () => '',
|
|
563
581
|
bibliography_section: () => '',
|
|
564
582
|
blockquote_element: () => ['disp-quote', { 'content-type': 'quote' }, 0],
|
|
@@ -582,14 +600,14 @@ class JATSExporter {
|
|
|
582
600
|
if (!rids.length) {
|
|
583
601
|
return '';
|
|
584
602
|
}
|
|
585
|
-
const xref = this.createElement('xref');
|
|
586
|
-
xref.setAttribute('ref-type', 'bibr');
|
|
587
|
-
xref.setAttribute('rid', normalizeID(rids.join(' ')));
|
|
603
|
+
const $xref = this.createElement('xref');
|
|
604
|
+
$xref.setAttribute('ref-type', 'bibr');
|
|
605
|
+
$xref.setAttribute('rid', normalizeID(rids.join(' ')));
|
|
588
606
|
const fragment = this.renderedCitations.get(node.attrs.id);
|
|
589
607
|
if (fragment) {
|
|
590
|
-
xref.innerHTML = fragment;
|
|
608
|
+
$xref.innerHTML = fragment;
|
|
591
609
|
}
|
|
592
|
-
return xref;
|
|
610
|
+
return $xref;
|
|
593
611
|
},
|
|
594
612
|
cross_reference: (node) => {
|
|
595
613
|
const cross = node;
|
|
@@ -603,40 +621,41 @@ class JATSExporter {
|
|
|
603
621
|
if (!target) {
|
|
604
622
|
return text ?? '';
|
|
605
623
|
}
|
|
606
|
-
const xref = this.createElement('xref');
|
|
624
|
+
const $xref = this.createElement('xref');
|
|
607
625
|
const type = chooseRefType(target.type);
|
|
608
626
|
if (type) {
|
|
609
|
-
xref.setAttribute('ref-type', type);
|
|
627
|
+
$xref.setAttribute('ref-type', type);
|
|
610
628
|
}
|
|
611
|
-
xref.setAttribute('rid', normalizeID(rids.join(' ')));
|
|
612
|
-
xref.textContent = text ?? '';
|
|
613
|
-
return xref;
|
|
629
|
+
$xref.setAttribute('rid', normalizeID(rids.join(' ')));
|
|
630
|
+
$xref.textContent = text ?? '';
|
|
631
|
+
return $xref;
|
|
614
632
|
},
|
|
615
633
|
doc: () => '',
|
|
616
634
|
equation: (node) => {
|
|
617
635
|
return node.attrs.contents ? this.createEquation(node) : '';
|
|
618
636
|
},
|
|
619
637
|
general_table_footnote: (node) => {
|
|
620
|
-
const
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
638
|
+
const $fragment = this.document.createDocumentFragment();
|
|
639
|
+
node.forEach((child) => {
|
|
640
|
+
$fragment.appendChild(this.serializeNode(child));
|
|
641
|
+
});
|
|
642
|
+
return $fragment;
|
|
624
643
|
},
|
|
625
644
|
inline_equation: (node) => {
|
|
626
645
|
if (!node.attrs.contents) {
|
|
627
646
|
return '';
|
|
628
647
|
}
|
|
629
|
-
const
|
|
648
|
+
const $inlineFormula = this.createElement('inline-formula');
|
|
630
649
|
const equation = this.createEquation(node, true);
|
|
631
|
-
|
|
632
|
-
return
|
|
650
|
+
$inlineFormula.append(equation);
|
|
651
|
+
return $inlineFormula;
|
|
633
652
|
},
|
|
634
653
|
equation_element: (node) => {
|
|
635
|
-
const
|
|
636
|
-
|
|
637
|
-
appendLabels(
|
|
638
|
-
processChildNodes(
|
|
639
|
-
return
|
|
654
|
+
const $dispFormula = this.createElement('disp-formula');
|
|
655
|
+
$dispFormula.setAttribute('id', normalizeID(node.attrs.id));
|
|
656
|
+
appendLabels($dispFormula, node);
|
|
657
|
+
processChildNodes($dispFormula, node, schema_1.schema.nodes.equation);
|
|
658
|
+
return $dispFormula;
|
|
640
659
|
},
|
|
641
660
|
figure: (node) => createGraphic(node),
|
|
642
661
|
figure_element: (node) => createFigureElement(node, node.type.schema.nodes.figure),
|
|
@@ -654,25 +673,39 @@ class JATSExporter {
|
|
|
654
673
|
? ['fn-group', { id: normalizeID(node.attrs.id) }, ['fn', ['p']]]
|
|
655
674
|
: ['fn-group', { id: normalizeID(node.attrs.id) }, 0],
|
|
656
675
|
footnotes_section: (node) => {
|
|
657
|
-
const
|
|
676
|
+
const $fnGroup = this.createElement('fn-group', undefined, {
|
|
658
677
|
id: normalizeID(node.attrs.id),
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
678
|
+
});
|
|
679
|
+
const titleNode = this.getFirstChildOfType(schema_1.schema.nodes.section_title, node);
|
|
680
|
+
if (titleNode) {
|
|
681
|
+
$fnGroup.appendChild(this.serializeNode(titleNode));
|
|
682
|
+
}
|
|
683
|
+
const footnotesNode = this.getFirstChildOfType(schema_1.schema.nodes.footnotes_element, node);
|
|
684
|
+
if (footnotesNode?.childCount) {
|
|
685
|
+
footnotesNode.forEach((footnote) => {
|
|
686
|
+
$fnGroup.appendChild(this.serializeNode(footnote));
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
else {
|
|
690
|
+
const $fn = this.createElement('fn');
|
|
691
|
+
$fn.appendChild(this.createElement('p'));
|
|
692
|
+
$fnGroup.appendChild($fn);
|
|
693
|
+
}
|
|
694
|
+
return $fnGroup;
|
|
662
695
|
},
|
|
663
696
|
hard_break: () => '',
|
|
664
697
|
highlight_marker: () => '',
|
|
665
698
|
inline_footnote: (node) => {
|
|
666
699
|
const rids = node.attrs.rids;
|
|
667
|
-
const xref = this.createElement('xref');
|
|
668
|
-
xref.setAttribute('ref-type', 'fn');
|
|
669
|
-
xref.setAttribute('rid', normalizeID(rids.join(' ')));
|
|
670
|
-
xref.textContent = rids
|
|
700
|
+
const $xref = this.createElement('xref');
|
|
701
|
+
$xref.setAttribute('ref-type', 'fn');
|
|
702
|
+
$xref.setAttribute('rid', normalizeID(rids.join(' ')));
|
|
703
|
+
$xref.textContent = rids
|
|
671
704
|
.map((rid) => this.footnoteLabels.get(rid))
|
|
672
705
|
.join(', ');
|
|
673
|
-
return xref;
|
|
706
|
+
return $xref;
|
|
674
707
|
},
|
|
675
|
-
keyword: () => '',
|
|
708
|
+
keyword: () => ['kwd', 0],
|
|
676
709
|
keywords_element: () => '',
|
|
677
710
|
keywords: () => '',
|
|
678
711
|
link: (node) => {
|
|
@@ -683,30 +716,30 @@ class JATSExporter {
|
|
|
683
716
|
if (!node.attrs.href) {
|
|
684
717
|
return text;
|
|
685
718
|
}
|
|
686
|
-
const
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
719
|
+
const $extLink = this.createElement('ext-link');
|
|
720
|
+
$extLink.setAttribute('ext-link-type', 'uri');
|
|
721
|
+
$extLink.setAttributeNS(xml_1.XLINK_NAMESPACE, 'href', node.attrs.href);
|
|
722
|
+
$extLink.textContent = text;
|
|
690
723
|
if (node.attrs.title) {
|
|
691
|
-
|
|
724
|
+
$extLink.setAttributeNS(xml_1.XLINK_NAMESPACE, 'xlink:title', node.attrs.title);
|
|
692
725
|
}
|
|
693
|
-
return
|
|
726
|
+
return $extLink;
|
|
694
727
|
},
|
|
695
728
|
list_item: () => ['list-item', 0],
|
|
696
729
|
listing: (node) => {
|
|
697
|
-
const code = this.createElement('code');
|
|
698
|
-
code.setAttribute('id', normalizeID(node.attrs.id));
|
|
699
|
-
code.setAttribute('language', node.attrs.languageKey);
|
|
700
|
-
code.textContent = node.attrs.contents;
|
|
701
|
-
return code;
|
|
730
|
+
const $code = this.createElement('code');
|
|
731
|
+
$code.setAttribute('id', normalizeID(node.attrs.id));
|
|
732
|
+
$code.setAttribute('language', node.attrs.languageKey);
|
|
733
|
+
$code.textContent = node.attrs.contents;
|
|
734
|
+
return $code;
|
|
702
735
|
},
|
|
703
736
|
listing_element: (node) => createFigureElement(node, node.type.schema.nodes.listing),
|
|
704
737
|
manuscript: (node) => ['article', { id: normalizeID(node.attrs.id) }, 0],
|
|
705
738
|
missing_figure: () => {
|
|
706
|
-
const graphic = this.createElement('graphic');
|
|
707
|
-
graphic.setAttribute('specific-use', 'MISSING');
|
|
708
|
-
graphic.setAttributeNS(xml_1.XLINK_NAMESPACE, 'xlink:href', '');
|
|
709
|
-
return graphic;
|
|
739
|
+
const $graphic = this.createElement('graphic');
|
|
740
|
+
$graphic.setAttribute('specific-use', 'MISSING');
|
|
741
|
+
$graphic.setAttributeNS(xml_1.XLINK_NAMESPACE, 'xlink:href', '');
|
|
742
|
+
return $graphic;
|
|
710
743
|
},
|
|
711
744
|
paragraph: (node) => {
|
|
712
745
|
if (!node.childCount) {
|
|
@@ -741,15 +774,7 @@ class JATSExporter {
|
|
|
741
774
|
}
|
|
742
775
|
return '';
|
|
743
776
|
},
|
|
744
|
-
graphical_abstract_section: (node) =>
|
|
745
|
-
const attrs = {
|
|
746
|
-
id: normalizeID(node.attrs.id),
|
|
747
|
-
};
|
|
748
|
-
if (node.attrs.category) {
|
|
749
|
-
attrs['sec-type'] = node.attrs.category;
|
|
750
|
-
}
|
|
751
|
-
return ['sec', attrs, 0];
|
|
752
|
-
},
|
|
777
|
+
graphical_abstract_section: (node) => createAbstract(node),
|
|
753
778
|
section: (node) => {
|
|
754
779
|
const attrs = {
|
|
755
780
|
id: normalizeID(node.attrs.id),
|
|
@@ -759,17 +784,18 @@ class JATSExporter {
|
|
|
759
784
|
}
|
|
760
785
|
return ['sec', attrs, 0];
|
|
761
786
|
},
|
|
787
|
+
abstract: (node) => createAbstract(node),
|
|
762
788
|
section_label: () => ['label', 0],
|
|
763
789
|
section_title: () => ['title', 0],
|
|
764
790
|
section_title_plain: () => ['title', 0],
|
|
765
791
|
table: (node) => ['table', { id: normalizeID(node.attrs.id) }, 0],
|
|
766
792
|
table_element: (node) => {
|
|
767
|
-
const
|
|
768
|
-
|
|
793
|
+
const $tableWrap = createTableElement(node);
|
|
794
|
+
$tableWrap.setAttribute('position', 'anchor');
|
|
769
795
|
if (node.attrs.type) {
|
|
770
|
-
|
|
796
|
+
$tableWrap.setAttribute('content-type', node.attrs.type);
|
|
771
797
|
}
|
|
772
|
-
return
|
|
798
|
+
return $tableWrap;
|
|
773
799
|
},
|
|
774
800
|
table_cell: (node) => [
|
|
775
801
|
'td',
|
|
@@ -815,84 +841,99 @@ class JATSExporter {
|
|
|
815
841
|
tracked_delete: () => ['del'],
|
|
816
842
|
};
|
|
817
843
|
this.serializer = new prosemirror_model_1.DOMSerializer(nodes, marks);
|
|
818
|
-
const appendChildIfPresent = (parent, tagName, textContent) => {
|
|
844
|
+
const appendChildIfPresent = ($parent, tagName, textContent) => {
|
|
819
845
|
if (!textContent) {
|
|
820
846
|
return;
|
|
821
847
|
}
|
|
822
|
-
const element = this.createElement(tagName);
|
|
823
|
-
element.textContent = textContent;
|
|
824
|
-
parent.appendChild(element);
|
|
848
|
+
const $element = this.createElement(tagName);
|
|
849
|
+
$element.textContent = textContent;
|
|
850
|
+
$parent.appendChild($element);
|
|
825
851
|
};
|
|
826
|
-
const processChildNodes = (element, node, contentNodeType) => {
|
|
852
|
+
const processChildNodes = ($element, node, contentNodeType) => {
|
|
827
853
|
node.forEach((childNode) => {
|
|
828
854
|
if (childNode.type === contentNodeType) {
|
|
829
855
|
if (childNode.attrs.id) {
|
|
830
|
-
element.appendChild(this.serializeNode(childNode));
|
|
856
|
+
$element.appendChild(this.serializeNode(childNode));
|
|
831
857
|
}
|
|
832
858
|
}
|
|
833
859
|
else if (childNode.type === node.type.schema.nodes.paragraph) {
|
|
834
|
-
element.appendChild(this.serializeNode(childNode));
|
|
860
|
+
$element.appendChild(this.serializeNode(childNode));
|
|
835
861
|
}
|
|
836
862
|
else if (childNode.type === node.type.schema.nodes.missing_figure) {
|
|
837
|
-
element.appendChild(this.serializeNode(childNode));
|
|
863
|
+
$element.appendChild(this.serializeNode(childNode));
|
|
838
864
|
}
|
|
839
865
|
});
|
|
840
866
|
};
|
|
841
867
|
const createElement = (node, nodeName) => {
|
|
842
|
-
const element = this.createElement(nodeName);
|
|
843
|
-
element.setAttribute('id', normalizeID(node.attrs.id));
|
|
844
|
-
return element;
|
|
868
|
+
const $element = this.createElement(nodeName);
|
|
869
|
+
$element.setAttribute('id', normalizeID(node.attrs.id));
|
|
870
|
+
return $element;
|
|
845
871
|
};
|
|
846
|
-
const appendLabels = (element, node) => {
|
|
872
|
+
const appendLabels = ($element, node) => {
|
|
847
873
|
if (this.labelTargets) {
|
|
848
874
|
const target = this.labelTargets.get(node.attrs.id);
|
|
849
875
|
if (target) {
|
|
850
|
-
const label = this.createElement('label');
|
|
851
|
-
label.textContent = target.label;
|
|
852
|
-
element.appendChild(label);
|
|
876
|
+
const $label = this.createElement('label');
|
|
877
|
+
$label.textContent = target.label;
|
|
878
|
+
$element.appendChild($label);
|
|
853
879
|
}
|
|
854
880
|
}
|
|
855
881
|
};
|
|
856
|
-
const appendAttributions = (element, node) => {
|
|
882
|
+
const appendAttributions = ($element, node) => {
|
|
857
883
|
if (node.attrs.attribution) {
|
|
858
|
-
const
|
|
859
|
-
|
|
860
|
-
element.appendChild(
|
|
884
|
+
const $attrib = this.createElement('attrib');
|
|
885
|
+
$attrib.textContent = node.attrs.attribution.literal;
|
|
886
|
+
$element.appendChild($attrib);
|
|
861
887
|
}
|
|
862
888
|
};
|
|
863
|
-
const appendTable = (element, node) => {
|
|
889
|
+
const appendTable = ($element, node) => {
|
|
864
890
|
const tableNode = this.getFirstChildOfType(schema_1.schema.nodes.table, node);
|
|
865
891
|
const colGroupNode = this.getFirstChildOfType(schema_1.schema.nodes.table_colgroup, node);
|
|
866
892
|
if (!tableNode) {
|
|
867
893
|
return;
|
|
868
894
|
}
|
|
869
|
-
const table = this.serializeNode(tableNode);
|
|
870
|
-
const
|
|
871
|
-
while (table.firstChild) {
|
|
872
|
-
const child = table.firstChild;
|
|
873
|
-
table.removeChild(child);
|
|
874
|
-
|
|
895
|
+
const $table = this.serializeNode(tableNode);
|
|
896
|
+
const $tbody = this.createElement('tbody');
|
|
897
|
+
while ($table.firstChild) {
|
|
898
|
+
const $child = $table.firstChild;
|
|
899
|
+
$table.removeChild($child);
|
|
900
|
+
$tbody.appendChild($child);
|
|
875
901
|
}
|
|
876
|
-
table.appendChild(
|
|
902
|
+
$table.appendChild($tbody);
|
|
903
|
+
this.normalizeTable($table);
|
|
877
904
|
if (colGroupNode) {
|
|
878
|
-
const colGroup = this.serializeNode(colGroupNode);
|
|
879
|
-
table.insertBefore(colGroup, table.firstChild);
|
|
905
|
+
const $colGroup = this.serializeNode(colGroupNode);
|
|
906
|
+
$table.insertBefore($colGroup, $table.firstChild);
|
|
880
907
|
}
|
|
881
|
-
element.appendChild(table);
|
|
908
|
+
$element.appendChild($table);
|
|
882
909
|
};
|
|
883
910
|
const createBoxElement = (node) => {
|
|
884
|
-
const
|
|
911
|
+
const $boxedText = createElement(node, 'boxed-text');
|
|
885
912
|
if (node.attrs.type) {
|
|
886
|
-
|
|
913
|
+
$boxedText.setAttribute('content-type', node.attrs.type);
|
|
887
914
|
}
|
|
888
|
-
appendLabels(
|
|
915
|
+
appendLabels($boxedText, node);
|
|
889
916
|
const child = node.firstChild;
|
|
890
917
|
if (child?.type === schema_1.schema.nodes.caption_title) {
|
|
891
|
-
this.appendCaption(
|
|
918
|
+
this.appendCaption($boxedText, node);
|
|
892
919
|
}
|
|
893
|
-
processChildNodes(
|
|
894
|
-
return
|
|
920
|
+
processChildNodes($boxedText, node, node.type.schema.nodes.section);
|
|
921
|
+
return $boxedText;
|
|
895
922
|
};
|
|
923
|
+
const abstractTypeAttrs = (category) => category && category !== 'abstract' ? { 'abstract-type': category } : {};
|
|
924
|
+
const createAbstract = (node) => [
|
|
925
|
+
'abstract',
|
|
926
|
+
abstractTypeAttrs(node.attrs.category),
|
|
927
|
+
0,
|
|
928
|
+
];
|
|
929
|
+
const createTransAbstract = (node) => [
|
|
930
|
+
'trans-abstract',
|
|
931
|
+
{
|
|
932
|
+
[`${xml_1.XML_NAMESPACE} lang`]: node.attrs.lang ?? '',
|
|
933
|
+
...abstractTypeAttrs(node.attrs.category),
|
|
934
|
+
},
|
|
935
|
+
0,
|
|
936
|
+
];
|
|
896
937
|
const isChildOfNodeType = (targetID, type, descend = false) => {
|
|
897
938
|
const nodes = this.getChildrenOfType(type);
|
|
898
939
|
return nodes.some((node) => {
|
|
@@ -909,94 +950,94 @@ class JATSExporter {
|
|
|
909
950
|
if (!graphicNode) {
|
|
910
951
|
return '';
|
|
911
952
|
}
|
|
912
|
-
const
|
|
953
|
+
const $graphic = createGraphic(graphicNode);
|
|
913
954
|
if (node.attrs.extLink) {
|
|
914
|
-
const extLink = this.appendElement(
|
|
915
|
-
extLink.setAttributeNS(xml_1.XLINK_NAMESPACE, 'href', node.attrs.extLink);
|
|
955
|
+
const $extLink = this.appendElement($graphic, 'ext-link');
|
|
956
|
+
$extLink.setAttributeNS(xml_1.XLINK_NAMESPACE, 'href', node.attrs.extLink);
|
|
916
957
|
}
|
|
917
|
-
this.appendCaption(
|
|
918
|
-
this.appendChildNodeOfType(
|
|
919
|
-
this.appendChildNodeOfType(
|
|
920
|
-
return
|
|
958
|
+
this.appendCaption($graphic, node);
|
|
959
|
+
this.appendChildNodeOfType($graphic, node, schema_1.schema.nodes.alt_text);
|
|
960
|
+
this.appendChildNodeOfType($graphic, node, schema_1.schema.nodes.long_desc);
|
|
961
|
+
return $graphic;
|
|
921
962
|
};
|
|
922
963
|
const createGraphic = (node) => {
|
|
923
|
-
const graphic = this.createElement('graphic');
|
|
924
|
-
graphic.setAttributeNS(xml_1.XLINK_NAMESPACE, 'xlink:href', node.attrs.src);
|
|
964
|
+
const $graphic = this.createElement('graphic');
|
|
965
|
+
$graphic.setAttributeNS(xml_1.XLINK_NAMESPACE, 'xlink:href', node.attrs.src);
|
|
925
966
|
const hero = findParentHeroImage(node.attrs.id);
|
|
926
967
|
if (hero) {
|
|
927
|
-
graphic.setAttribute('content-type', hero.attrs.type || 'leading');
|
|
968
|
+
$graphic.setAttribute('content-type', hero.attrs.type || 'leading');
|
|
928
969
|
}
|
|
929
970
|
else if (!isChildOfNodeType(node.attrs.id, schema_1.schema.nodes.figure_element) &&
|
|
930
971
|
node.attrs.type) {
|
|
931
|
-
graphic.setAttribute('content-type', node.attrs.type);
|
|
972
|
+
$graphic.setAttribute('content-type', node.attrs.type);
|
|
932
973
|
}
|
|
933
|
-
return graphic;
|
|
974
|
+
return $graphic;
|
|
934
975
|
};
|
|
935
976
|
const createFigureElement = (node, contentNodeType) => {
|
|
936
|
-
const
|
|
977
|
+
const $fig = createElement(node, 'fig');
|
|
937
978
|
const figNode = this.getFirstChildOfType(schema_1.schema.nodes.figure, node);
|
|
938
979
|
const figType = figNode?.attrs.type;
|
|
939
980
|
if (figType) {
|
|
940
|
-
|
|
981
|
+
$fig.setAttribute('fig-type', figType);
|
|
941
982
|
}
|
|
942
|
-
appendLabels(
|
|
943
|
-
this.appendCaption(
|
|
944
|
-
this.appendChildNodeOfType(
|
|
945
|
-
this.appendChildNodeOfType(
|
|
946
|
-
this.appendChildNodeOfType(
|
|
947
|
-
processChildNodes(
|
|
948
|
-
appendAttributions(
|
|
983
|
+
appendLabels($fig, node);
|
|
984
|
+
this.appendCaption($fig, node);
|
|
985
|
+
this.appendChildNodeOfType($fig, node, schema_1.schema.nodes.alt_text);
|
|
986
|
+
this.appendChildNodeOfType($fig, node, schema_1.schema.nodes.long_desc);
|
|
987
|
+
this.appendChildNodeOfType($fig, node, node.type.schema.nodes.footnotes_element);
|
|
988
|
+
processChildNodes($fig, node, contentNodeType);
|
|
989
|
+
appendAttributions($fig, node);
|
|
949
990
|
if ((0, transformer_1.isExecutableNodeType)(node.type)) {
|
|
950
|
-
processExecutableNode(node,
|
|
991
|
+
processExecutableNode(node, $fig);
|
|
951
992
|
}
|
|
952
|
-
moveAltTextAndLongDescToGraphics(
|
|
953
|
-
return
|
|
993
|
+
moveAltTextAndLongDescToGraphics($fig);
|
|
994
|
+
return $fig;
|
|
954
995
|
};
|
|
955
|
-
const moveAltTextAndLongDescToGraphics = (element) => {
|
|
956
|
-
const altText = element.querySelector('alt-text');
|
|
957
|
-
const longDesc = element.querySelector('long-desc');
|
|
958
|
-
const graphics = element.querySelectorAll('graphic');
|
|
959
|
-
if (graphics.length === 0) {
|
|
996
|
+
const moveAltTextAndLongDescToGraphics = ($element) => {
|
|
997
|
+
const $altText = $element.querySelector('alt-text');
|
|
998
|
+
const $longDesc = $element.querySelector('long-desc');
|
|
999
|
+
const $graphics = $element.querySelectorAll('graphic');
|
|
1000
|
+
if ($graphics.length === 0) {
|
|
960
1001
|
return;
|
|
961
1002
|
}
|
|
962
|
-
graphics.forEach((graphic) => {
|
|
963
|
-
if (longDesc) {
|
|
964
|
-
graphic.prepend(longDesc.cloneNode(true));
|
|
1003
|
+
$graphics.forEach(($graphic) => {
|
|
1004
|
+
if ($longDesc) {
|
|
1005
|
+
$graphic.prepend($longDesc.cloneNode(true));
|
|
965
1006
|
}
|
|
966
|
-
if (altText) {
|
|
967
|
-
graphic.prepend(altText.cloneNode(true));
|
|
1007
|
+
if ($altText) {
|
|
1008
|
+
$graphic.prepend($altText.cloneNode(true));
|
|
968
1009
|
}
|
|
969
1010
|
});
|
|
970
|
-
altText?.remove();
|
|
971
|
-
longDesc?.remove();
|
|
1011
|
+
$altText?.remove();
|
|
1012
|
+
$longDesc?.remove();
|
|
972
1013
|
};
|
|
973
1014
|
const createTableElement = (node) => {
|
|
974
1015
|
const nodeName = 'table-wrap';
|
|
975
|
-
const
|
|
976
|
-
appendLabels(
|
|
977
|
-
this.appendCaption(
|
|
978
|
-
this.appendChildNodeOfType(
|
|
979
|
-
this.appendChildNodeOfType(
|
|
980
|
-
appendTable(
|
|
981
|
-
this.appendChildNodeOfType(
|
|
1016
|
+
const $tableWrap = createElement(node, nodeName);
|
|
1017
|
+
appendLabels($tableWrap, node);
|
|
1018
|
+
this.appendCaption($tableWrap, node);
|
|
1019
|
+
this.appendChildNodeOfType($tableWrap, node, schema_1.schema.nodes.alt_text);
|
|
1020
|
+
this.appendChildNodeOfType($tableWrap, node, schema_1.schema.nodes.long_desc);
|
|
1021
|
+
appendTable($tableWrap, node);
|
|
1022
|
+
this.appendChildNodeOfType($tableWrap, node, node.type.schema.nodes.table_element_footer);
|
|
982
1023
|
if ((0, transformer_1.isExecutableNodeType)(node.type)) {
|
|
983
|
-
processExecutableNode(node,
|
|
1024
|
+
processExecutableNode(node, $tableWrap);
|
|
984
1025
|
}
|
|
985
|
-
return
|
|
1026
|
+
return $tableWrap;
|
|
986
1027
|
};
|
|
987
|
-
const processExecutableNode = (node, element) => {
|
|
1028
|
+
const processExecutableNode = (node, $element) => {
|
|
988
1029
|
const listingNode = this.getFirstChildOfType(schema_1.schema.nodes.listing, node);
|
|
989
1030
|
if (listingNode) {
|
|
990
1031
|
const { contents, languageKey } = listingNode.attrs;
|
|
991
1032
|
if (contents && languageKey) {
|
|
992
|
-
const
|
|
993
|
-
|
|
994
|
-
element.appendChild(
|
|
995
|
-
const code = this.createElement('code');
|
|
996
|
-
code.setAttribute('executable', 'true');
|
|
997
|
-
code.setAttribute('language', languageKey);
|
|
998
|
-
code.textContent = contents;
|
|
999
|
-
|
|
1033
|
+
const $fig = this.createElement('fig');
|
|
1034
|
+
$fig.setAttribute('specific-use', 'source');
|
|
1035
|
+
$element.appendChild($fig);
|
|
1036
|
+
const $code = this.createElement('code');
|
|
1037
|
+
$code.setAttribute('executable', 'true');
|
|
1038
|
+
$code.setAttribute('language', languageKey);
|
|
1039
|
+
$code.textContent = contents;
|
|
1040
|
+
$fig.appendChild($code);
|
|
1000
1041
|
}
|
|
1001
1042
|
}
|
|
1002
1043
|
};
|
|
@@ -1004,201 +1045,187 @@ class JATSExporter {
|
|
|
1004
1045
|
this.serializeNode = (node) => this.serializer.serializeNode(node, {
|
|
1005
1046
|
document: this.document,
|
|
1006
1047
|
});
|
|
1007
|
-
this.
|
|
1008
|
-
const contributors = this.getChildrenOfType(schema_1.schema.nodes.contributor).sort(sortContributors);
|
|
1048
|
+
this.buildContributorGroup = (contributors) => {
|
|
1009
1049
|
if (!contributors.length) {
|
|
1010
1050
|
return;
|
|
1011
1051
|
}
|
|
1012
|
-
const
|
|
1013
|
-
const
|
|
1014
|
-
|
|
1015
|
-
if (!
|
|
1016
|
-
|
|
1017
|
-
labels.set(id, label);
|
|
1052
|
+
const affiliationIDs = contributors.flatMap((n) => n.attrs.affiliationIDs);
|
|
1053
|
+
const affiliationOrder = new Map();
|
|
1054
|
+
affiliationIDs.forEach((id, index) => {
|
|
1055
|
+
if (!affiliationOrder.has(id)) {
|
|
1056
|
+
affiliationOrder.set(id, index);
|
|
1018
1057
|
}
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1058
|
+
});
|
|
1059
|
+
const affiliations = this.getChildrenOfType(schema_1.schema.nodes.affiliation)
|
|
1060
|
+
.filter((a) => affiliationIDs.includes(a.attrs.id))
|
|
1061
|
+
.sort((a, b) => (affiliationOrder.get(a.attrs.id) ?? Infinity) -
|
|
1062
|
+
(affiliationOrder.get(b.attrs.id) ?? Infinity));
|
|
1023
1063
|
const $contribGroup = this.createElement('contrib-group');
|
|
1024
1064
|
$contribGroup.setAttribute('content-type', 'authors');
|
|
1025
|
-
articleMeta.appendChild($contribGroup);
|
|
1026
1065
|
contributors.forEach((contributor) => {
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1066
|
+
$contribGroup.appendChild(this.serializeNode(contributor));
|
|
1067
|
+
});
|
|
1068
|
+
affiliations.forEach((affiliation) => {
|
|
1069
|
+
$contribGroup.appendChild(this.serializeNode(affiliation));
|
|
1070
|
+
});
|
|
1071
|
+
return $contribGroup;
|
|
1072
|
+
};
|
|
1073
|
+
this.buildAuthorNotes = ($coiStatement) => {
|
|
1074
|
+
const authorNotes = this.getFirstChildOfType(schema_1.schema.nodes.author_notes);
|
|
1075
|
+
const $authorNotes = this.createElement('author-notes');
|
|
1076
|
+
if (authorNotes) {
|
|
1077
|
+
this.appendAuthorNotes($authorNotes, authorNotes);
|
|
1078
|
+
}
|
|
1079
|
+
if ($coiStatement) {
|
|
1080
|
+
$authorNotes.appendChild($coiStatement);
|
|
1081
|
+
}
|
|
1082
|
+
return $authorNotes.hasChildNodes() ? $authorNotes : undefined;
|
|
1083
|
+
};
|
|
1084
|
+
this.computeContributorLabels = (contributors) => {
|
|
1085
|
+
const labels = new Map();
|
|
1086
|
+
const assign = (id) => {
|
|
1087
|
+
if (!labels.has(id)) {
|
|
1088
|
+
labels.set(id, labels.size + 1);
|
|
1049
1089
|
}
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1090
|
+
};
|
|
1091
|
+
contributors.forEach((contributor) => {
|
|
1092
|
+
contributor.attrs.affiliationIDs?.forEach(assign);
|
|
1093
|
+
contributor.attrs.footnoteIDs?.forEach(assign);
|
|
1094
|
+
contributor.attrs.correspIDs?.forEach(assign);
|
|
1095
|
+
});
|
|
1096
|
+
return labels;
|
|
1097
|
+
};
|
|
1098
|
+
this.createLabelSup = (id) => {
|
|
1099
|
+
const $sup = this.createElement('sup');
|
|
1100
|
+
$sup.textContent = String(this.contributorLabels.get(id));
|
|
1101
|
+
return $sup;
|
|
1102
|
+
};
|
|
1103
|
+
this.buildContributorElement = (contributor) => {
|
|
1104
|
+
const $contrib = this.createElement('contrib');
|
|
1105
|
+
$contrib.setAttribute('contrib-type', 'author');
|
|
1106
|
+
$contrib.setAttribute('id', normalizeID(contributor.attrs.id));
|
|
1107
|
+
if (contributor.attrs.isCorresponding) {
|
|
1108
|
+
$contrib.setAttribute('corresp', 'yes');
|
|
1109
|
+
}
|
|
1110
|
+
if (contributor.attrs.role) {
|
|
1111
|
+
this.appendElement($contrib, 'role', contributor.attrs.role);
|
|
1112
|
+
}
|
|
1113
|
+
if (contributor.attrs.ORCID) {
|
|
1114
|
+
const contribIDAttrs = {
|
|
1115
|
+
'contrib-id-type': 'orcid',
|
|
1116
|
+
};
|
|
1117
|
+
if (contributor.attrs.isAuthenticated) {
|
|
1118
|
+
contribIDAttrs['authenticated'] = 'true';
|
|
1055
1119
|
}
|
|
1056
|
-
contributor.attrs.
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1120
|
+
this.appendElement($contrib, 'contrib-id', contributor.attrs.ORCID, contribIDAttrs);
|
|
1121
|
+
}
|
|
1122
|
+
const $name = this.buildContributorName(contributor);
|
|
1123
|
+
$contrib.appendChild($name);
|
|
1124
|
+
if (contributor.attrs.suffix) {
|
|
1125
|
+
this.appendElement($name, 'suffix', contributor.attrs.suffix);
|
|
1126
|
+
}
|
|
1127
|
+
contributor.attrs.degrees?.forEach((degree) => {
|
|
1128
|
+
this.appendElement($contrib, 'degrees', degree);
|
|
1129
|
+
});
|
|
1130
|
+
if (contributor.attrs.email) {
|
|
1131
|
+
this.appendElement($contrib, 'email', contributor.attrs.email);
|
|
1132
|
+
}
|
|
1133
|
+
contributor.attrs.affiliationIDs?.forEach((rid) => {
|
|
1134
|
+
const $xref = this.appendElement($contrib, 'xref', '', {
|
|
1135
|
+
'ref-type': 'aff',
|
|
1136
|
+
rid: normalizeID(rid),
|
|
1069
1137
|
});
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1138
|
+
$xref.appendChild(this.createLabelSup(rid));
|
|
1139
|
+
});
|
|
1140
|
+
contributor.attrs.footnoteIDs?.forEach((rid) => {
|
|
1141
|
+
const $xref = this.appendElement($contrib, 'xref', '', {
|
|
1142
|
+
'ref-type': 'fn',
|
|
1143
|
+
rid: normalizeID(rid),
|
|
1076
1144
|
});
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
'vocab-identifier': 'http://credit.niso.org/',
|
|
1084
|
-
vocab: 'CRediT',
|
|
1085
|
-
'vocab-term': credit.vocabTerm,
|
|
1086
|
-
'vocab-term-identifier': url,
|
|
1087
|
-
});
|
|
1145
|
+
$xref.appendChild(this.createLabelSup(rid));
|
|
1146
|
+
});
|
|
1147
|
+
contributor.attrs.correspIDs?.forEach((rid) => {
|
|
1148
|
+
const $xref = this.appendElement($contrib, 'xref', '', {
|
|
1149
|
+
'ref-type': 'corresp',
|
|
1150
|
+
rid: normalizeID(rid),
|
|
1088
1151
|
});
|
|
1089
|
-
$
|
|
1152
|
+
$xref.appendChild(this.createLabelSup(rid));
|
|
1090
1153
|
});
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
.sort(sortAffiliations)
|
|
1096
|
-
.forEach((affiliation) => {
|
|
1097
|
-
const $content = [];
|
|
1098
|
-
if (affiliation.attrs.department) {
|
|
1099
|
-
const $institution = this.createElement('institution', affiliation.attrs.department, {
|
|
1100
|
-
'content-type': 'dept',
|
|
1101
|
-
});
|
|
1102
|
-
$content.push($institution);
|
|
1103
|
-
}
|
|
1104
|
-
if (affiliation.attrs.institution) {
|
|
1105
|
-
const $institution = this.createElement('institution', affiliation.attrs.institution);
|
|
1106
|
-
$content.push($institution);
|
|
1107
|
-
}
|
|
1108
|
-
if (affiliation.attrs.addressLine1) {
|
|
1109
|
-
const $addrLine = this.createElement('addr-line', affiliation.attrs.addressLine1);
|
|
1110
|
-
$content.push($addrLine);
|
|
1111
|
-
}
|
|
1112
|
-
if (affiliation.attrs.addressLine2) {
|
|
1113
|
-
const $addrLine = this.createElement('addr-line', affiliation.attrs.addressLine2);
|
|
1114
|
-
$content.push($addrLine);
|
|
1115
|
-
}
|
|
1116
|
-
if (affiliation.attrs.addressLine3) {
|
|
1117
|
-
const $addrLine = this.createElement('addr-line', affiliation.attrs.addressLine3);
|
|
1118
|
-
$content.push($addrLine);
|
|
1119
|
-
}
|
|
1120
|
-
if (affiliation.attrs.city) {
|
|
1121
|
-
const $city = this.createElement('city', affiliation.attrs.city);
|
|
1122
|
-
$content.push($city);
|
|
1123
|
-
}
|
|
1124
|
-
if (affiliation.attrs.county) {
|
|
1125
|
-
const $state = this.createElement('state', affiliation.attrs.county);
|
|
1126
|
-
$content.push($state);
|
|
1127
|
-
}
|
|
1128
|
-
if (affiliation.attrs.country) {
|
|
1129
|
-
const $country = this.createElement('country', affiliation.attrs.country);
|
|
1130
|
-
$content.push($country);
|
|
1131
|
-
}
|
|
1132
|
-
if (affiliation.attrs.postCode) {
|
|
1133
|
-
const $postalCode = this.createElement('postal-code', affiliation.attrs.postCode);
|
|
1134
|
-
$content.push($postalCode);
|
|
1135
|
-
}
|
|
1136
|
-
const $aff = this.createElement('aff');
|
|
1137
|
-
$aff.setAttribute('id', normalizeID(affiliation.attrs.id));
|
|
1138
|
-
$contribGroup.appendChild($aff);
|
|
1139
|
-
const label = labels.get(affiliation.attrs.id);
|
|
1140
|
-
if (label) {
|
|
1141
|
-
this.appendElement($aff, 'label', String(label));
|
|
1154
|
+
contributor.attrs.creditRoles?.forEach((credit) => {
|
|
1155
|
+
const url = credit_roles_1.CreditRoleUrls.get(credit.vocabTerm);
|
|
1156
|
+
if (!url) {
|
|
1157
|
+
return;
|
|
1142
1158
|
}
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1159
|
+
this.appendElement($contrib, 'role', credit.vocabTerm, {
|
|
1160
|
+
'vocab-identifier': 'http://credit.niso.org/',
|
|
1161
|
+
vocab: 'CRediT',
|
|
1162
|
+
'vocab-term': credit.vocabTerm,
|
|
1163
|
+
'vocab-term-identifier': url,
|
|
1148
1164
|
});
|
|
1149
1165
|
});
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1166
|
+
return $contrib;
|
|
1167
|
+
};
|
|
1168
|
+
this.buildAffiliationElement = (affiliation) => {
|
|
1169
|
+
const $content = [];
|
|
1170
|
+
if (affiliation.attrs.department) {
|
|
1171
|
+
$content.push(this.createElement('institution', affiliation.attrs.department, {
|
|
1172
|
+
'content-type': 'dept',
|
|
1173
|
+
}));
|
|
1174
|
+
}
|
|
1175
|
+
if (affiliation.attrs.institution) {
|
|
1176
|
+
$content.push(this.createElement('institution', affiliation.attrs.institution));
|
|
1177
|
+
}
|
|
1178
|
+
if (affiliation.attrs.addressLine1) {
|
|
1179
|
+
$content.push(this.createElement('addr-line', affiliation.attrs.addressLine1));
|
|
1180
|
+
}
|
|
1181
|
+
if (affiliation.attrs.addressLine2) {
|
|
1182
|
+
$content.push(this.createElement('addr-line', affiliation.attrs.addressLine2));
|
|
1183
|
+
}
|
|
1184
|
+
if (affiliation.attrs.addressLine3) {
|
|
1185
|
+
$content.push(this.createElement('addr-line', affiliation.attrs.addressLine3));
|
|
1186
|
+
}
|
|
1187
|
+
if (affiliation.attrs.city) {
|
|
1188
|
+
$content.push(this.createElement('city', affiliation.attrs.city));
|
|
1189
|
+
}
|
|
1190
|
+
if (affiliation.attrs.county) {
|
|
1191
|
+
$content.push(this.createElement('state', affiliation.attrs.county));
|
|
1192
|
+
}
|
|
1193
|
+
if (affiliation.attrs.country) {
|
|
1194
|
+
$content.push(this.createElement('country', affiliation.attrs.country));
|
|
1195
|
+
}
|
|
1196
|
+
if (affiliation.attrs.postCode) {
|
|
1197
|
+
$content.push(this.createElement('postal-code', affiliation.attrs.postCode));
|
|
1153
1198
|
}
|
|
1199
|
+
const $aff = this.createElement('aff');
|
|
1200
|
+
$aff.setAttribute('id', normalizeID(affiliation.attrs.id));
|
|
1201
|
+
const label = this.contributorLabels.get(affiliation.attrs.id);
|
|
1202
|
+
if (label) {
|
|
1203
|
+
this.appendElement($aff, 'label', String(label));
|
|
1204
|
+
}
|
|
1205
|
+
$content.forEach((node, i) => {
|
|
1206
|
+
if (i > 0) {
|
|
1207
|
+
$aff.appendChild(this.document.createTextNode(', '));
|
|
1208
|
+
}
|
|
1209
|
+
$aff.appendChild(node);
|
|
1210
|
+
});
|
|
1211
|
+
return $aff;
|
|
1154
1212
|
};
|
|
1155
1213
|
this.buildContributorName = (contributor) => {
|
|
1156
1214
|
const { given, family } = contributor.attrs;
|
|
1157
1215
|
if (Boolean(given) !== Boolean(family)) {
|
|
1158
1216
|
return this.createElement('string-name', given || family);
|
|
1159
1217
|
}
|
|
1160
|
-
const name = this.createElement('name');
|
|
1218
|
+
const $name = this.createElement('name');
|
|
1161
1219
|
if (contributor.attrs.family) {
|
|
1162
|
-
this.appendElement(name, 'surname', contributor.attrs.family);
|
|
1220
|
+
this.appendElement($name, 'surname', contributor.attrs.family);
|
|
1163
1221
|
}
|
|
1164
1222
|
if (contributor.attrs.given) {
|
|
1165
|
-
this.appendElement(name, 'given-names', contributor.attrs.given);
|
|
1223
|
+
this.appendElement($name, 'given-names', contributor.attrs.given);
|
|
1166
1224
|
}
|
|
1167
1225
|
if (contributor.attrs.prefix) {
|
|
1168
|
-
this.appendElement(name, 'prefix', contributor.attrs.prefix);
|
|
1169
|
-
}
|
|
1170
|
-
return name;
|
|
1171
|
-
};
|
|
1172
|
-
this.createAuthorNotesElement = (contributors) => {
|
|
1173
|
-
const authorNotes = this.getFirstChildOfType(schema_1.schema.nodes.author_notes);
|
|
1174
|
-
if (!authorNotes || !authorNotes.childCount) {
|
|
1175
|
-
return;
|
|
1226
|
+
this.appendElement($name, 'prefix', contributor.attrs.prefix);
|
|
1176
1227
|
}
|
|
1177
|
-
|
|
1178
|
-
const used = contributors.flatMap((c) => c.attrs.correspIDs);
|
|
1179
|
-
authorNotes.descendants((node) => {
|
|
1180
|
-
switch (node.type) {
|
|
1181
|
-
case schema_1.schema.nodes.paragraph: {
|
|
1182
|
-
const $p = this.writeParagraph(node);
|
|
1183
|
-
$authorNotes.append($p);
|
|
1184
|
-
break;
|
|
1185
|
-
}
|
|
1186
|
-
case schema_1.schema.nodes.footnote: {
|
|
1187
|
-
const $fn = this.writeFootnote(node);
|
|
1188
|
-
$authorNotes.append($fn);
|
|
1189
|
-
break;
|
|
1190
|
-
}
|
|
1191
|
-
case schema_1.schema.nodes.corresp: {
|
|
1192
|
-
if (used.includes(node.attrs.id)) {
|
|
1193
|
-
const $corresp = this.writeCorresp(node);
|
|
1194
|
-
$authorNotes.append($corresp);
|
|
1195
|
-
}
|
|
1196
|
-
break;
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
return false;
|
|
1200
|
-
});
|
|
1201
|
-
return $authorNotes.hasChildNodes() ? $authorNotes : undefined;
|
|
1228
|
+
return $name;
|
|
1202
1229
|
};
|
|
1203
1230
|
this.writeCorresp = (corresp) => {
|
|
1204
1231
|
const $corresp = this.createElement('corresp');
|
|
@@ -1228,222 +1255,120 @@ class JATSExporter {
|
|
|
1228
1255
|
$fn.innerHTML = content;
|
|
1229
1256
|
return $fn;
|
|
1230
1257
|
};
|
|
1231
|
-
this.
|
|
1232
|
-
this.
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
generalTableFootnote.before(cn);
|
|
1239
|
-
});
|
|
1240
|
-
generalTableFootnote.remove();
|
|
1241
|
-
}
|
|
1258
|
+
this.appendAuthorNotes = ($authorNotes, authorNotes) => {
|
|
1259
|
+
const correspIDs = new Set(this.getChildrenOfType(schema_1.schema.nodes.contributor).flatMap((contributor) => contributor.attrs.correspIDs));
|
|
1260
|
+
authorNotes.forEach((node) => {
|
|
1261
|
+
switch (node.type) {
|
|
1262
|
+
case schema_1.schema.nodes.paragraph: {
|
|
1263
|
+
$authorNotes.append(this.writeParagraph(node));
|
|
1264
|
+
break;
|
|
1242
1265
|
}
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
tableElement.insertBefore(childNode, label ? label.nextSibling : tableElement.firstChild);
|
|
1251
|
-
break;
|
|
1252
|
-
}
|
|
1253
|
-
case 'table': {
|
|
1254
|
-
this.fixTable(childNode);
|
|
1255
|
-
break;
|
|
1256
|
-
}
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1266
|
+
case schema_1.schema.nodes.footnote: {
|
|
1267
|
+
$authorNotes.append(this.writeFootnote(node));
|
|
1268
|
+
break;
|
|
1269
|
+
}
|
|
1270
|
+
case schema_1.schema.nodes.corresp: {
|
|
1271
|
+
if (correspIDs.has(node.attrs.id)) {
|
|
1272
|
+
$authorNotes.append(this.writeCorresp(node));
|
|
1259
1273
|
}
|
|
1274
|
+
break;
|
|
1260
1275
|
}
|
|
1261
1276
|
}
|
|
1262
1277
|
});
|
|
1263
1278
|
};
|
|
1264
|
-
this.
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1279
|
+
this.buildKeywords = () => this.getChildrenOfType(schema_1.schema.nodes.keyword_group).map((group) => this.serializeNode(group));
|
|
1280
|
+
this.changeTag = ($node, tag) => {
|
|
1281
|
+
const $clone = this.createElement(tag);
|
|
1282
|
+
for (const attr of $node.attributes) {
|
|
1283
|
+
$clone.setAttributeNS(null, attr.name, attr.value);
|
|
1268
1284
|
}
|
|
1269
|
-
while (node.firstChild) {
|
|
1270
|
-
clone.appendChild(node.firstChild);
|
|
1285
|
+
while ($node.firstChild) {
|
|
1286
|
+
$clone.appendChild($node.firstChild);
|
|
1271
1287
|
}
|
|
1272
|
-
node.replaceWith(clone);
|
|
1273
|
-
return clone;
|
|
1288
|
+
$node.replaceWith($clone);
|
|
1289
|
+
return $clone;
|
|
1274
1290
|
};
|
|
1275
|
-
this.
|
|
1276
|
-
let tbody;
|
|
1277
|
-
Array.from(table.childNodes).forEach((child) => {
|
|
1278
|
-
if (child instanceof Element &&
|
|
1279
|
-
tbody
|
|
1291
|
+
this.normalizeTable = ($table) => {
|
|
1292
|
+
let $tbody;
|
|
1293
|
+
Array.from($table.childNodes).forEach(($child) => {
|
|
1294
|
+
if ($child instanceof Element &&
|
|
1295
|
+
$child.tagName.toLowerCase() === 'tbody') {
|
|
1296
|
+
$tbody = $child;
|
|
1280
1297
|
}
|
|
1281
1298
|
});
|
|
1282
|
-
if (
|
|
1299
|
+
if (!$tbody) {
|
|
1283
1300
|
return;
|
|
1284
1301
|
}
|
|
1285
|
-
const tbodyRows = Array.from(tbody.childNodes);
|
|
1286
|
-
const thead = this.createElement('thead');
|
|
1287
|
-
tbodyRows.forEach((row, i) => {
|
|
1288
|
-
const isRow = row instanceof Element && row.tagName.toLowerCase() === 'tr';
|
|
1302
|
+
const tbodyRows = Array.from($tbody.childNodes);
|
|
1303
|
+
const $thead = this.createElement('thead');
|
|
1304
|
+
tbodyRows.forEach(($row, i) => {
|
|
1305
|
+
const isRow = $row instanceof Element && $row.tagName.toLowerCase() === 'tr';
|
|
1289
1306
|
if (isRow) {
|
|
1290
|
-
const headerCell = row.querySelector('th[scope="col"], th[scope="colgroup"]');
|
|
1291
|
-
if (i === 0 || headerCell) {
|
|
1292
|
-
tbody?.removeChild(row);
|
|
1293
|
-
const tableCells = row.querySelectorAll('td');
|
|
1294
|
-
for (const td of tableCells) {
|
|
1295
|
-
this.changeTag(td, 'th');
|
|
1307
|
+
const $headerCell = $row.querySelector('th[scope="col"], th[scope="colgroup"]');
|
|
1308
|
+
if (i === 0 || $headerCell) {
|
|
1309
|
+
$tbody?.removeChild($row);
|
|
1310
|
+
const $tableCells = $row.querySelectorAll('td');
|
|
1311
|
+
for (const $td of $tableCells) {
|
|
1312
|
+
this.changeTag($td, 'th');
|
|
1296
1313
|
}
|
|
1297
|
-
thead.appendChild(row);
|
|
1314
|
+
$thead.appendChild($row);
|
|
1298
1315
|
}
|
|
1299
1316
|
}
|
|
1300
1317
|
});
|
|
1301
|
-
if (thead.hasChildNodes()) {
|
|
1302
|
-
table.insertBefore(thead, tbody);
|
|
1303
|
-
}
|
|
1304
|
-
};
|
|
1305
|
-
this.unwrapBody = (body) => {
|
|
1306
|
-
const container = body.querySelector(':scope > sec[sec-type="body"]');
|
|
1307
|
-
if (!container) {
|
|
1308
|
-
return;
|
|
1309
|
-
}
|
|
1310
|
-
const sections = container.querySelectorAll(':scope > sec');
|
|
1311
|
-
sections.forEach((section) => {
|
|
1312
|
-
body.appendChild(section.cloneNode(true));
|
|
1313
|
-
});
|
|
1314
|
-
body.removeChild(container);
|
|
1315
|
-
};
|
|
1316
|
-
this.removeBackContainer = (body) => {
|
|
1317
|
-
const container = body.querySelector(':scope > sec[sec-type="backmatter"]');
|
|
1318
|
-
if (!container) {
|
|
1319
|
-
return;
|
|
1320
|
-
}
|
|
1321
|
-
body.removeChild(container);
|
|
1322
|
-
};
|
|
1323
|
-
this.moveAwards = (front, body) => {
|
|
1324
|
-
const awardGroups = body.querySelectorAll(':scope > award-group');
|
|
1325
|
-
if (!awardGroups.length) {
|
|
1326
|
-
return;
|
|
1327
|
-
}
|
|
1328
|
-
const fundingGroup = this.createElement('funding-group');
|
|
1329
|
-
awardGroups.forEach((award) => {
|
|
1330
|
-
fundingGroup.appendChild(award);
|
|
1331
|
-
});
|
|
1332
|
-
const articleMeta = front.querySelector(':scope > article-meta');
|
|
1333
|
-
if (articleMeta) {
|
|
1334
|
-
const insertBeforeElement = articleMeta.querySelector(':scope > support-group, :scope > conference, :scope > counts, :scope > custom-meta-group');
|
|
1335
|
-
insertBeforeElement
|
|
1336
|
-
? articleMeta.insertBefore(fundingGroup, insertBeforeElement)
|
|
1337
|
-
: articleMeta.appendChild(fundingGroup);
|
|
1318
|
+
if ($thead.hasChildNodes()) {
|
|
1319
|
+
$table.insertBefore($thead, $tbody);
|
|
1338
1320
|
}
|
|
1339
1321
|
};
|
|
1340
|
-
this.
|
|
1341
|
-
const
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
};
|
|
1350
|
-
this.moveSectionsToBack = (back, body) => {
|
|
1351
|
-
const availabilitySection = body.querySelector('sec[sec-type="availability"]');
|
|
1352
|
-
if (availabilitySection) {
|
|
1353
|
-
back.insertBefore(availabilitySection, back.firstChild);
|
|
1354
|
-
}
|
|
1355
|
-
const ethicsSection = body.querySelector('sec[sec-type="ethics-statement"]');
|
|
1356
|
-
if (ethicsSection) {
|
|
1357
|
-
back.appendChild(ethicsSection);
|
|
1358
|
-
}
|
|
1359
|
-
const section = body.querySelector('sec[sec-type="acknowledgements"]');
|
|
1360
|
-
if (section) {
|
|
1361
|
-
const ack = this.createElement('ack');
|
|
1362
|
-
while (section.firstChild) {
|
|
1363
|
-
ack.appendChild(section.firstChild);
|
|
1364
|
-
}
|
|
1365
|
-
if (section.parentNode) {
|
|
1366
|
-
section.parentNode.removeChild(section);
|
|
1367
|
-
}
|
|
1368
|
-
back.insertBefore(ack, back.firstChild);
|
|
1369
|
-
}
|
|
1370
|
-
const appendicesSections = body.querySelectorAll('sec[sec-type="appendices"]');
|
|
1371
|
-
if (appendicesSections) {
|
|
1372
|
-
const appGroup = this.createElement('app-group');
|
|
1373
|
-
appendicesSections.forEach((section) => {
|
|
1374
|
-
if (section.parentNode) {
|
|
1375
|
-
section.parentNode.removeChild(section);
|
|
1376
|
-
}
|
|
1377
|
-
const app = this.createElement('app');
|
|
1378
|
-
app.appendChild(section);
|
|
1379
|
-
appGroup.appendChild(app);
|
|
1380
|
-
});
|
|
1381
|
-
back.insertBefore(appGroup, back.firstChild);
|
|
1382
|
-
}
|
|
1383
|
-
const footNotes = [];
|
|
1384
|
-
const footnoteCategories = [
|
|
1385
|
-
'con',
|
|
1386
|
-
'conflict',
|
|
1387
|
-
'deceased',
|
|
1388
|
-
'equal',
|
|
1389
|
-
'present-address',
|
|
1390
|
-
'presented-at',
|
|
1391
|
-
'previously-at',
|
|
1392
|
-
'supplementary-material',
|
|
1393
|
-
'supported-by',
|
|
1394
|
-
'financial-disclosure',
|
|
1395
|
-
'coi-statement',
|
|
1396
|
-
];
|
|
1397
|
-
const sections = body.querySelectorAll('sec');
|
|
1398
|
-
for (const currentSection of sections) {
|
|
1399
|
-
const currentSectionType = currentSection.getAttribute('sec-type');
|
|
1400
|
-
if (currentSectionType &&
|
|
1401
|
-
footnoteCategories.indexOf(currentSectionType) >= 0) {
|
|
1402
|
-
footNotes.push(this.sectionToFootnote(currentSection, currentSectionType));
|
|
1322
|
+
this.buildAbstracts = () => {
|
|
1323
|
+
const $abstracts = [];
|
|
1324
|
+
const abstractsNode = this.getFirstChildOfType(schema_1.schema.nodes.abstracts);
|
|
1325
|
+
abstractsNode?.forEach((child) => {
|
|
1326
|
+
const $abstract = this.serializeNode(child);
|
|
1327
|
+
if ($abstract.nodeName === 'abstract') {
|
|
1328
|
+
$abstract
|
|
1329
|
+
.querySelectorAll(':scope > title')
|
|
1330
|
+
.forEach((title) => title.remove());
|
|
1403
1331
|
}
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
fnGroup.append(...footNotes);
|
|
1408
|
-
back.append(fnGroup);
|
|
1409
|
-
}
|
|
1332
|
+
$abstracts.push($abstract);
|
|
1333
|
+
});
|
|
1334
|
+
return $abstracts;
|
|
1410
1335
|
};
|
|
1411
|
-
this.sectionToFootnote = (section, fnType) => {
|
|
1412
|
-
const
|
|
1413
|
-
|
|
1414
|
-
const title = section.querySelector('title');
|
|
1415
|
-
if (title) {
|
|
1416
|
-
const
|
|
1417
|
-
|
|
1418
|
-
section.removeChild(title);
|
|
1419
|
-
|
|
1336
|
+
this.sectionToFootnote = ($section, fnType) => {
|
|
1337
|
+
const $fn = this.createElement('fn');
|
|
1338
|
+
$fn.setAttribute('fn-type', fnType);
|
|
1339
|
+
const $title = $section.querySelector(':scope > title');
|
|
1340
|
+
if ($title) {
|
|
1341
|
+
const $label = this.createElement('label');
|
|
1342
|
+
$label.textContent = $title.textContent;
|
|
1343
|
+
$section.removeChild($title);
|
|
1344
|
+
$fn.append($label);
|
|
1420
1345
|
}
|
|
1421
|
-
|
|
1422
|
-
if (section.parentNode) {
|
|
1423
|
-
section.parentNode.removeChild(section);
|
|
1346
|
+
$fn.append(...$section.children);
|
|
1347
|
+
if ($section.parentNode) {
|
|
1348
|
+
$section.parentNode.removeChild($section);
|
|
1424
1349
|
}
|
|
1425
|
-
return
|
|
1350
|
+
return $fn;
|
|
1426
1351
|
};
|
|
1427
|
-
this.
|
|
1352
|
+
this.buildFloatsGroup = () => {
|
|
1428
1353
|
const heroImage = this.getFirstChildOfType(schema_1.schema.nodes.hero_image);
|
|
1429
1354
|
if (!heroImage) {
|
|
1430
1355
|
return;
|
|
1431
1356
|
}
|
|
1432
|
-
const floatsGroup = this.createElement('floats-group');
|
|
1433
|
-
let
|
|
1357
|
+
const $floatsGroup = this.createElement('floats-group');
|
|
1358
|
+
let $graphic = null;
|
|
1434
1359
|
heroImage.descendants((node) => {
|
|
1435
1360
|
if (node.type === schema_1.schema.nodes.figure) {
|
|
1436
|
-
|
|
1437
|
-
floatsGroup.appendChild(
|
|
1361
|
+
$graphic = this.serializeNode(node);
|
|
1362
|
+
$floatsGroup.appendChild($graphic);
|
|
1438
1363
|
}
|
|
1439
1364
|
else {
|
|
1440
|
-
const serializedNode = this.serializeNode(node);
|
|
1441
|
-
|
|
1365
|
+
const $serializedNode = this.serializeNode(node);
|
|
1366
|
+
$graphic?.appendChild($serializedNode);
|
|
1442
1367
|
}
|
|
1443
1368
|
return false;
|
|
1444
1369
|
});
|
|
1445
|
-
if (floatsGroup.children.length > 0) {
|
|
1446
|
-
|
|
1370
|
+
if ($floatsGroup.children.length > 0) {
|
|
1371
|
+
return $floatsGroup;
|
|
1447
1372
|
}
|
|
1448
1373
|
};
|
|
1449
1374
|
}
|
|
@@ -1458,168 +1383,58 @@ class JATSExporter {
|
|
|
1458
1383
|
}
|
|
1459
1384
|
createEquation(node, isInline = false) {
|
|
1460
1385
|
if (node.attrs.format === 'tex') {
|
|
1461
|
-
const texMath = this.createElement('tex-math');
|
|
1462
|
-
texMath.setAttribute('notation', 'LaTeX');
|
|
1463
|
-
texMath.setAttribute('version', 'MathJax');
|
|
1386
|
+
const $texMath = this.createElement('tex-math');
|
|
1387
|
+
$texMath.setAttribute('notation', 'LaTeX');
|
|
1388
|
+
$texMath.setAttribute('version', 'MathJax');
|
|
1464
1389
|
if (node.attrs.contents.includes('<![CDATA[')) {
|
|
1465
|
-
texMath.innerHTML = node.attrs.contents;
|
|
1390
|
+
$texMath.innerHTML = node.attrs.contents;
|
|
1466
1391
|
}
|
|
1467
1392
|
else {
|
|
1468
|
-
texMath.innerHTML = `<![CDATA[ ${node.attrs.contents} ]]>`;
|
|
1393
|
+
$texMath.innerHTML = `<![CDATA[ ${node.attrs.contents} ]]>`;
|
|
1469
1394
|
}
|
|
1470
|
-
return texMath;
|
|
1395
|
+
return $texMath;
|
|
1471
1396
|
}
|
|
1472
1397
|
else {
|
|
1473
1398
|
const math = this.nodeFromJATS(node.attrs.contents);
|
|
1474
|
-
const mathml = math;
|
|
1399
|
+
const $mathml = math;
|
|
1475
1400
|
if (!isInline) {
|
|
1476
|
-
mathml.setAttribute('id', normalizeID(node.attrs.id));
|
|
1477
|
-
}
|
|
1478
|
-
return mathml;
|
|
1479
|
-
}
|
|
1480
|
-
}
|
|
1481
|
-
buildKeywords(articleMeta) {
|
|
1482
|
-
const keywordGroups = this.getChildrenOfType(schema_1.schema.nodes.keyword_group);
|
|
1483
|
-
keywordGroups.forEach((group) => {
|
|
1484
|
-
const kwdGroup = this.createElement('kwd-group');
|
|
1485
|
-
if (group.attrs.type) {
|
|
1486
|
-
kwdGroup.setAttribute('kwd-group-type', group.attrs.type);
|
|
1487
|
-
}
|
|
1488
|
-
articleMeta.appendChild(kwdGroup);
|
|
1489
|
-
group.content.forEach((keyword) => {
|
|
1490
|
-
const kwd = this.createElement('kwd');
|
|
1491
|
-
kwd.textContent = keyword.textContent;
|
|
1492
|
-
kwdGroup.appendChild(kwd);
|
|
1493
|
-
});
|
|
1494
|
-
articleMeta.appendChild(kwdGroup);
|
|
1495
|
-
});
|
|
1496
|
-
}
|
|
1497
|
-
getAbstractCategories(abstractsNode) {
|
|
1498
|
-
const categories = [];
|
|
1499
|
-
abstractsNode?.content.descendants((node) => {
|
|
1500
|
-
categories.push(node.attrs.category);
|
|
1501
|
-
return false;
|
|
1502
|
-
});
|
|
1503
|
-
return categories;
|
|
1504
|
-
}
|
|
1505
|
-
getAbstractSections(body) {
|
|
1506
|
-
{
|
|
1507
|
-
const abstractsNode = this.getFirstChildOfType(schema_1.schema.nodes.abstracts);
|
|
1508
|
-
const abstractCategories = this.getAbstractCategories(abstractsNode);
|
|
1509
|
-
const sections = Array.from(body.querySelectorAll(':scope > sec, :scope > trans-abstract'));
|
|
1510
|
-
return sections.filter((section) => this.isAbstractSection(section, abstractCategories));
|
|
1511
|
-
}
|
|
1512
|
-
}
|
|
1513
|
-
isAbstractSection(section, abstractCategories) {
|
|
1514
|
-
const sectionType = section.getAttribute('sec-type');
|
|
1515
|
-
return sectionType ? abstractCategories.includes(sectionType) : false;
|
|
1516
|
-
}
|
|
1517
|
-
createTransAbstractNode(transAbstract) {
|
|
1518
|
-
const transAbstractNode = this.createElement('trans-abstract');
|
|
1519
|
-
transAbstractNode.setAttributeNS(xml_1.XML_NAMESPACE, 'lang', transAbstract.getAttributeNS(xml_1.XML_NAMESPACE, 'lang') ?? '');
|
|
1520
|
-
this.setAbstractType(transAbstractNode, transAbstract);
|
|
1521
|
-
transAbstractNode.append(...transAbstract.childNodes);
|
|
1522
|
-
return transAbstractNode;
|
|
1523
|
-
}
|
|
1524
|
-
createAbstractNode(abstractSection) {
|
|
1525
|
-
const abstractNode = this.createElement('abstract');
|
|
1526
|
-
for (const node of abstractSection.childNodes) {
|
|
1527
|
-
if (node.nodeName !== 'title') {
|
|
1528
|
-
abstractNode.appendChild(node.cloneNode(true));
|
|
1401
|
+
$mathml.setAttribute('id', normalizeID(node.attrs.id));
|
|
1529
1402
|
}
|
|
1403
|
+
return $mathml;
|
|
1530
1404
|
}
|
|
1531
|
-
this.setAbstractType(abstractNode, abstractSection);
|
|
1532
|
-
return abstractNode;
|
|
1533
1405
|
}
|
|
1534
|
-
|
|
1535
|
-
const
|
|
1536
|
-
|
|
1537
|
-
const abstractType = sectionType.replace('abstract-', '');
|
|
1538
|
-
abstractNode.setAttribute('abstract-type', abstractType);
|
|
1539
|
-
}
|
|
1406
|
+
fillEmptyElements($article, selector, tagName = 'p') {
|
|
1407
|
+
const $empty = Array.from($article.querySelectorAll(selector)).filter(($el) => !$el.innerHTML);
|
|
1408
|
+
$empty.forEach(($element) => $element.appendChild(this.createElement(tagName)));
|
|
1540
1409
|
}
|
|
1541
|
-
|
|
1542
|
-
const
|
|
1543
|
-
fnGroups.forEach((fnGroup) => {
|
|
1544
|
-
if (fnGroup) {
|
|
1545
|
-
const coiStatement = fnGroup.querySelector('fn[fn-type="coi-statement"]');
|
|
1546
|
-
if (coiStatement) {
|
|
1547
|
-
const authorNotes = this.createElement('author-notes');
|
|
1548
|
-
authorNotes.append(coiStatement);
|
|
1549
|
-
const articleMeta = front.querySelector('article-meta');
|
|
1550
|
-
if (articleMeta) {
|
|
1551
|
-
const authorNoteEl = articleMeta.querySelector('author-notes');
|
|
1552
|
-
if (authorNoteEl) {
|
|
1553
|
-
authorNoteEl.append(...authorNotes.childNodes);
|
|
1554
|
-
}
|
|
1555
|
-
else {
|
|
1556
|
-
const appendableSelectors = [
|
|
1557
|
-
'contrib-group',
|
|
1558
|
-
'title-group',
|
|
1559
|
-
'article-id',
|
|
1560
|
-
];
|
|
1561
|
-
const appendable = [
|
|
1562
|
-
...articleMeta.querySelectorAll(appendableSelectors.join(', ')),
|
|
1563
|
-
];
|
|
1564
|
-
for (let i = 0; i < appendableSelectors.length; i++) {
|
|
1565
|
-
const sel = appendableSelectors[i];
|
|
1566
|
-
const match = appendable.find((el) => el.matches(sel));
|
|
1567
|
-
if (match) {
|
|
1568
|
-
articleMeta.insertBefore(authorNotes, match.nextSibling);
|
|
1569
|
-
break;
|
|
1570
|
-
}
|
|
1571
|
-
}
|
|
1572
|
-
}
|
|
1573
|
-
}
|
|
1574
|
-
if (!fnGroup.hasChildNodes()) {
|
|
1575
|
-
fnGroup.remove();
|
|
1576
|
-
}
|
|
1577
|
-
}
|
|
1578
|
-
}
|
|
1579
|
-
});
|
|
1580
|
-
}
|
|
1581
|
-
updateFootnoteTypes(front, body) {
|
|
1582
|
-
const footnotes = [...front.querySelectorAll('fn').values()];
|
|
1583
|
-
footnotes.push(...body.querySelectorAll('fn'));
|
|
1584
|
-
footnotes.forEach((fn) => {
|
|
1585
|
-
const fnType = fn.getAttribute('fn-type');
|
|
1586
|
-
if (fnType) {
|
|
1587
|
-
fn.setAttribute('fn-type', fnType);
|
|
1588
|
-
}
|
|
1589
|
-
});
|
|
1590
|
-
}
|
|
1591
|
-
fillEmptyElements(articleElement, selector, tagName = 'p') {
|
|
1592
|
-
const emptyElements = Array.from(articleElement.querySelectorAll(selector)).filter((element) => !element.innerHTML);
|
|
1593
|
-
emptyElements.forEach((element) => element.appendChild(this.createElement(tagName)));
|
|
1594
|
-
}
|
|
1595
|
-
addParagraphsToSections(articleElement) {
|
|
1596
|
-
const sections = articleElement.querySelectorAll('sec');
|
|
1410
|
+
addParagraphsToSections($article) {
|
|
1411
|
+
const $sections = $article.querySelectorAll('sec, abstract');
|
|
1597
1412
|
const TITLE_TAGS = new Set(['title', 'label', 'sec-meta']);
|
|
1598
|
-
for (const section of sections) {
|
|
1599
|
-
const hasContent = Array.from(section.children).some((child) => !TITLE_TAGS.has(child.tagName));
|
|
1413
|
+
for (const $section of $sections) {
|
|
1414
|
+
const hasContent = Array.from($section.children).some(($child) => !TITLE_TAGS.has($child.tagName));
|
|
1600
1415
|
if (hasContent) {
|
|
1601
1416
|
continue;
|
|
1602
1417
|
}
|
|
1603
|
-
const p = this.createElement('p');
|
|
1604
|
-
const
|
|
1605
|
-
section.querySelector(':scope > label') ??
|
|
1606
|
-
section.querySelector(':scope > sec-meta');
|
|
1607
|
-
if (
|
|
1608
|
-
|
|
1418
|
+
const $p = this.createElement('p');
|
|
1419
|
+
const $insertAfter = $section.querySelector(':scope > title') ??
|
|
1420
|
+
$section.querySelector(':scope > label') ??
|
|
1421
|
+
$section.querySelector(':scope > sec-meta');
|
|
1422
|
+
if ($insertAfter) {
|
|
1423
|
+
$insertAfter.insertAdjacentElement('afterend', $p);
|
|
1609
1424
|
}
|
|
1610
1425
|
else {
|
|
1611
|
-
section.prepend(p);
|
|
1426
|
+
$section.prepend($p);
|
|
1612
1427
|
}
|
|
1613
1428
|
}
|
|
1614
1429
|
}
|
|
1615
|
-
fillEmptyFootnotes(
|
|
1616
|
-
this.fillEmptyElements(
|
|
1430
|
+
fillEmptyFootnotes($article) {
|
|
1431
|
+
this.fillEmptyElements($article, 'fn');
|
|
1617
1432
|
}
|
|
1618
|
-
fillEmptyTableFooters(
|
|
1619
|
-
this.fillEmptyElements(
|
|
1433
|
+
fillEmptyTableFooters($article) {
|
|
1434
|
+
this.fillEmptyElements($article, 'table-wrap-foot');
|
|
1620
1435
|
}
|
|
1621
|
-
fillEmptyListItem(
|
|
1622
|
-
this.fillEmptyElements(
|
|
1436
|
+
fillEmptyListItem($article) {
|
|
1437
|
+
this.fillEmptyElements($article, 'list-item');
|
|
1623
1438
|
}
|
|
1624
1439
|
}
|
|
1625
1440
|
exports.JATSExporter = JATSExporter;
|