@manuscripts/transform 1.2.3 → 1.2.4-LEAN-2066
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/importer/jats-body-dom-parser.js +33 -1
- package/dist/cjs/jats/importer/jats-body-transformations.js +14 -0
- package/dist/cjs/jats/importer/jats-comments.js +24 -0
- package/dist/cjs/jats/importer/jats-front-parser.js +0 -25
- package/dist/cjs/jats/importer/parse-jats-article.js +2 -6
- package/dist/cjs/jats/jats-exporter.js +5 -7
- package/dist/cjs/lib/utils.js +12 -1
- package/dist/cjs/schema/index.js +2 -0
- package/dist/cjs/schema/nodes/keyword.js +1 -2
- package/dist/cjs/schema/nodes/keywords_element.js +2 -1
- package/dist/cjs/schema/nodes/keywords_group.js +48 -0
- package/dist/cjs/schema/nodes/keywords_section.js +1 -1
- package/dist/cjs/transformer/decode.js +29 -23
- package/dist/cjs/transformer/encode.js +6 -3
- package/dist/cjs/transformer/node-types.js +1 -0
- package/dist/cjs/transformer/object-types.js +2 -1
- package/dist/es/jats/importer/jats-body-dom-parser.js +33 -1
- package/dist/es/jats/importer/jats-body-transformations.js +14 -0
- package/dist/es/jats/importer/jats-comments.js +25 -1
- package/dist/es/jats/importer/jats-front-parser.js +1 -26
- package/dist/es/jats/importer/parse-jats-article.js +2 -6
- package/dist/es/jats/jats-exporter.js +5 -7
- package/dist/es/lib/utils.js +10 -0
- package/dist/es/schema/index.js +2 -0
- package/dist/es/schema/nodes/keyword.js +1 -2
- package/dist/es/schema/nodes/keywords_element.js +2 -1
- package/dist/es/schema/nodes/keywords_group.js +44 -0
- package/dist/es/schema/nodes/keywords_section.js +1 -1
- package/dist/es/transformer/decode.js +29 -23
- package/dist/es/transformer/encode.js +6 -3
- package/dist/es/transformer/node-types.js +1 -0
- package/dist/es/transformer/object-types.js +1 -0
- package/dist/types/jats/importer/jats-body-transformations.d.ts +1 -0
- package/dist/types/jats/importer/jats-front-parser.d.ts +6 -11
- package/dist/types/lib/utils.d.ts +1 -0
- package/dist/types/schema/nodes/keywords_group.d.ts +26 -0
- package/dist/types/schema/types.d.ts +1 -1
- package/dist/types/transformer/decode.d.ts +1 -0
- package/dist/types/transformer/object-types.d.ts +2 -1
- package/package.json +1 -1
|
@@ -505,6 +505,22 @@ const nodes = [
|
|
|
505
505
|
};
|
|
506
506
|
},
|
|
507
507
|
},
|
|
508
|
+
{
|
|
509
|
+
tag: 'sec[sec-type="keywords"]',
|
|
510
|
+
node: 'keywords_section',
|
|
511
|
+
getAttrs: (node) => {
|
|
512
|
+
const element = node;
|
|
513
|
+
return {
|
|
514
|
+
id: element.getAttribute('id'),
|
|
515
|
+
category: (0, transformer_1.chooseSectionCategory)(element),
|
|
516
|
+
};
|
|
517
|
+
},
|
|
518
|
+
},
|
|
519
|
+
{
|
|
520
|
+
tag: 'kwd-group-list',
|
|
521
|
+
context: 'keywords_section/',
|
|
522
|
+
node: 'keywords_element',
|
|
523
|
+
},
|
|
508
524
|
{
|
|
509
525
|
tag: 'sec',
|
|
510
526
|
node: 'section',
|
|
@@ -516,6 +532,22 @@ const nodes = [
|
|
|
516
532
|
};
|
|
517
533
|
},
|
|
518
534
|
},
|
|
535
|
+
{
|
|
536
|
+
tag: 'kwd-group',
|
|
537
|
+
context: 'keywords_element/',
|
|
538
|
+
node: 'keywords_group',
|
|
539
|
+
getAttrs: (node) => {
|
|
540
|
+
const element = node;
|
|
541
|
+
return {
|
|
542
|
+
type: element.getAttribute('kwd-group-type'),
|
|
543
|
+
};
|
|
544
|
+
},
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
tag: 'kwd',
|
|
548
|
+
context: 'keywords_group//',
|
|
549
|
+
node: 'keyword',
|
|
550
|
+
},
|
|
519
551
|
{
|
|
520
552
|
tag: 'label',
|
|
521
553
|
context: 'section/',
|
|
@@ -568,7 +600,7 @@ const nodes = [
|
|
|
568
600
|
{
|
|
569
601
|
tag: 'title',
|
|
570
602
|
node: 'section_title',
|
|
571
|
-
context: 'section/|footnotes_section/|bibliography_section/',
|
|
603
|
+
context: 'section/|footnotes_section/|bibliography_section/|keywords_section/',
|
|
572
604
|
},
|
|
573
605
|
{
|
|
574
606
|
tag: 'title',
|
|
@@ -266,4 +266,18 @@ exports.jatsBodyTransformations = {
|
|
|
266
266
|
paragraph === null || paragraph === void 0 ? void 0 : paragraph.replaceWith(parent);
|
|
267
267
|
});
|
|
268
268
|
},
|
|
269
|
+
moveKeywordsToBody(document, body, createElement) {
|
|
270
|
+
const keywordGroups = [...document.querySelectorAll('kwd-group')];
|
|
271
|
+
if (keywordGroups.length > 0) {
|
|
272
|
+
const section = createElement('sec');
|
|
273
|
+
section.setAttribute('sec-type', 'keywords');
|
|
274
|
+
const title = createElement('title');
|
|
275
|
+
title.textContent = 'Keywords';
|
|
276
|
+
section.append(title);
|
|
277
|
+
const kwdGroupsEl = createElement('kwd-group-list');
|
|
278
|
+
kwdGroupsEl.append(keywordGroups[0]);
|
|
279
|
+
section.append(kwdGroupsEl);
|
|
280
|
+
body.prepend(section);
|
|
281
|
+
}
|
|
282
|
+
},
|
|
269
283
|
};
|
|
@@ -63,6 +63,21 @@ const insertToken = (doc, processingInstructionNode, authorQueriesMap) => {
|
|
|
63
63
|
return parentElement.insertBefore(tokenNode, processingInstructionNode);
|
|
64
64
|
}
|
|
65
65
|
};
|
|
66
|
+
const extractCommentsFromKeywords = (tokens, model, authorQueriesMap) => {
|
|
67
|
+
var _a;
|
|
68
|
+
const commentAnnotations = [];
|
|
69
|
+
const name = model.name;
|
|
70
|
+
const filteredTokens = filterAndSortTokens(tokens, name);
|
|
71
|
+
let content = name;
|
|
72
|
+
for (const token of filteredTokens) {
|
|
73
|
+
content = name.replace(token, '');
|
|
74
|
+
const query = authorQueriesMap.get(token);
|
|
75
|
+
const commentAnnotation = (0, transformer_1.buildComment)((_a = model.containedGroup) !== null && _a !== void 0 ? _a : (0, uuid_1.v4)(), `${query}`, undefined, [(0, transformer_1.buildContribution)(DEFAULT_PROFILE_ID)], DEFAULT_ANNOTATION_COLOR);
|
|
76
|
+
model['name'] = content;
|
|
77
|
+
commentAnnotations.push(commentAnnotation);
|
|
78
|
+
}
|
|
79
|
+
return commentAnnotations;
|
|
80
|
+
};
|
|
66
81
|
const createComments = (authorQueriesMap, manuscriptModels) => {
|
|
67
82
|
const tokens = [...authorQueriesMap.keys()];
|
|
68
83
|
const commentAnnotations = [];
|
|
@@ -71,10 +86,19 @@ const createComments = (authorQueriesMap, manuscriptModels) => {
|
|
|
71
86
|
const comments = addCommentsFromMarkedProcessingInstructions(tokens, model, authorQueriesMap);
|
|
72
87
|
commentAnnotations.push(...comments);
|
|
73
88
|
}
|
|
89
|
+
else if ((0, transformer_1.isKeyword)(model)) {
|
|
90
|
+
const comments = extractCommentsFromKeywords(tokens, model, authorQueriesMap);
|
|
91
|
+
commentAnnotations.push(...comments);
|
|
92
|
+
}
|
|
74
93
|
}
|
|
75
94
|
return commentAnnotations;
|
|
76
95
|
};
|
|
77
96
|
exports.createComments = createComments;
|
|
97
|
+
function filterAndSortTokens(tokens, content) {
|
|
98
|
+
return tokens
|
|
99
|
+
.filter((token) => content.indexOf(token) >= 0)
|
|
100
|
+
.sort((a, b) => content.indexOf(a) - content.indexOf(b));
|
|
101
|
+
}
|
|
78
102
|
const addCommentsFromMarkedProcessingInstructions = (tokens, model, authorQueriesMap) => {
|
|
79
103
|
const commentAnnotations = [];
|
|
80
104
|
for (const field of ['contents', 'caption', 'title']) {
|
|
@@ -68,31 +68,6 @@ exports.jatsFrontParser = {
|
|
|
68
68
|
}
|
|
69
69
|
return (0, jats_journal_meta_parser_1.parseJournalMeta)(journalMeta);
|
|
70
70
|
},
|
|
71
|
-
parseKeywords(keywordGroupNodes) {
|
|
72
|
-
var _a, _b;
|
|
73
|
-
if (!keywordGroupNodes) {
|
|
74
|
-
return { groups: [], keywords: [] };
|
|
75
|
-
}
|
|
76
|
-
let keywordPriority = 1;
|
|
77
|
-
const keywordGroups = { groups: [], keywords: [] };
|
|
78
|
-
for (const keywordGroupNode of keywordGroupNodes) {
|
|
79
|
-
const manuscriptKeywordGroup = (0, builders_1.buildKeywordGroup)({
|
|
80
|
-
title: ((_a = keywordGroupNode.querySelector('title')) === null || _a === void 0 ? void 0 : _a.textContent) || undefined,
|
|
81
|
-
label: ((_b = keywordGroupNode.querySelector('label')) === null || _b === void 0 ? void 0 : _b.textContent) || undefined,
|
|
82
|
-
type: keywordGroupNode.getAttribute('kwd-group-type') || undefined,
|
|
83
|
-
});
|
|
84
|
-
keywordGroups.groups.push(manuscriptKeywordGroup);
|
|
85
|
-
for (const keywordNode of keywordGroupNode.querySelectorAll('kwd')) {
|
|
86
|
-
if (keywordNode.textContent) {
|
|
87
|
-
const keyword = (0, builders_1.buildKeyword)(keywordNode.textContent);
|
|
88
|
-
keyword.priority = keywordPriority++;
|
|
89
|
-
keyword.containedGroup = manuscriptKeywordGroup._id;
|
|
90
|
-
keywordGroups.keywords.push(keyword);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return keywordGroups;
|
|
95
|
-
},
|
|
96
71
|
parseDates(historyNode) {
|
|
97
72
|
if (!historyNode) {
|
|
98
73
|
return undefined;
|
|
@@ -54,9 +54,6 @@ const parseJATSFront = async (front) => {
|
|
|
54
54
|
const manuscriptMeta = Object.assign({ title: title ? inlineContentsFromJATSTitle(title) : undefined, subtitle: subtitle ? inlineContentsFromJATSTitle(subtitle) : undefined, runningTitle: runningTitle
|
|
55
55
|
? inlineContentsFromJATSTitle(runningTitle)
|
|
56
56
|
: undefined }, jats_front_parser_1.jatsFrontParser.parseCounts(articleMeta === null || articleMeta === void 0 ? void 0 : articleMeta.querySelector('counts')));
|
|
57
|
-
const keywordGroupNodes = articleMeta === null || articleMeta === void 0 ? void 0 : articleMeta.querySelectorAll('kwd-group');
|
|
58
|
-
const { keywords, groups: keywordGroups } = jats_front_parser_1.jatsFrontParser.parseKeywords(keywordGroupNodes);
|
|
59
|
-
const manuscript_keywordIDs = keywords.length > 0 ? keywords.map((k) => k._id) : undefined;
|
|
60
57
|
const { affiliations, affiliationIDs } = jats_front_parser_1.jatsFrontParser.parseAffiliationNodes([
|
|
61
58
|
...front.querySelectorAll('article-meta > contrib-group > aff'),
|
|
62
59
|
]);
|
|
@@ -73,14 +70,12 @@ const parseJATSFront = async (front) => {
|
|
|
73
70
|
const supplements = jats_front_parser_1.jatsFrontParser.parseSupplements([
|
|
74
71
|
...front.querySelectorAll('article-meta > supplementary-material'),
|
|
75
72
|
]);
|
|
76
|
-
const manuscript = Object.assign(Object.assign(Object.assign(
|
|
73
|
+
const manuscript = Object.assign(Object.assign(Object.assign({}, (0, builders_1.buildManuscript)()), manuscriptMeta), history);
|
|
77
74
|
return {
|
|
78
75
|
models: generateModelIDs([
|
|
79
76
|
manuscript,
|
|
80
|
-
...keywords,
|
|
81
77
|
...affiliations,
|
|
82
78
|
...authors,
|
|
83
|
-
...keywordGroups,
|
|
84
79
|
...footnotes,
|
|
85
80
|
...correspondingList,
|
|
86
81
|
journal,
|
|
@@ -121,6 +116,7 @@ const parseJATSBody = (document, body, bibliographyItems, refModels, referenceId
|
|
|
121
116
|
jats_body_transformations_1.jatsBodyTransformations.moveCaptionsToEnd(body);
|
|
122
117
|
jats_body_transformations_1.jatsBodyTransformations.moveTableFooterToEnd(body);
|
|
123
118
|
jats_body_transformations_1.jatsBodyTransformations.moveBlockNodesFromParagraph(document, body, createElement);
|
|
119
|
+
jats_body_transformations_1.jatsBodyTransformations.moveKeywordsToBody(document, body, createElement);
|
|
124
120
|
const node = jats_body_dom_parser_1.jatsBodyDOMParser.parse(body);
|
|
125
121
|
if (!node.firstChild) {
|
|
126
122
|
throw new Error('No content was parsed from the JATS article body');
|
|
@@ -398,9 +398,7 @@ class JATSExporter {
|
|
|
398
398
|
if (history.childElementCount) {
|
|
399
399
|
articleMeta.appendChild(history);
|
|
400
400
|
}
|
|
401
|
-
|
|
402
|
-
this.buildKeywords(articleMeta, manuscript.keywordIDs);
|
|
403
|
-
}
|
|
401
|
+
this.buildKeywords(articleMeta);
|
|
404
402
|
let countingElements = [];
|
|
405
403
|
if (manuscript.genericCounts) {
|
|
406
404
|
const elements = manuscript.genericCounts.map((el) => {
|
|
@@ -624,6 +622,7 @@ class JATSExporter {
|
|
|
624
622
|
bibliography_element: () => '',
|
|
625
623
|
bibliography_item: () => '',
|
|
626
624
|
comment_list: () => '',
|
|
625
|
+
keywords_group: () => '',
|
|
627
626
|
bibliography_section: (node) => [
|
|
628
627
|
'ref-list',
|
|
629
628
|
{ id: normalizeID(node.attrs.id) },
|
|
@@ -1529,10 +1528,8 @@ class JATSExporter {
|
|
|
1529
1528
|
return name;
|
|
1530
1529
|
};
|
|
1531
1530
|
}
|
|
1532
|
-
buildKeywords(articleMeta
|
|
1533
|
-
const keywords =
|
|
1534
|
-
.map((id) => this.modelMap.get(id))
|
|
1535
|
-
.filter((model) => model && model.name);
|
|
1531
|
+
buildKeywords(articleMeta) {
|
|
1532
|
+
const keywords = [...this.modelMap.values()].filter((model) => model.objectType === json_schema_1.ObjectTypes.Keyword);
|
|
1536
1533
|
const keywordGroups = new Map();
|
|
1537
1534
|
keywords.forEach((keyword) => {
|
|
1538
1535
|
const containedGroup = keyword.containedGroup || '';
|
|
@@ -1566,6 +1563,7 @@ class JATSExporter {
|
|
|
1566
1563
|
kwd.textContent = keyword.name;
|
|
1567
1564
|
kwdGroup.appendChild(kwd);
|
|
1568
1565
|
}
|
|
1566
|
+
articleMeta.appendChild(kwdGroup);
|
|
1569
1567
|
}
|
|
1570
1568
|
}
|
|
1571
1569
|
}
|
package/dist/cjs/lib/utils.js
CHANGED
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.findParentNodeClosestToPos = exports.isInGraphicalAbstractSection = exports.findNodePositions = exports.iterateChildren = void 0;
|
|
18
|
+
exports.findParentNodeClosestToPos = exports.isInBibliographySection = exports.isInGraphicalAbstractSection = exports.findNodePositions = exports.iterateChildren = void 0;
|
|
19
|
+
const bibliography_section_1 = require("../schema/nodes/bibliography_section");
|
|
19
20
|
const graphical_abstract_section_1 = require("../schema/nodes/graphical_abstract_section");
|
|
20
21
|
function* iterateChildren(node, recurse = false) {
|
|
21
22
|
for (let i = 0; i < node.childCount; i++) {
|
|
@@ -50,6 +51,16 @@ const isInGraphicalAbstractSection = ($pos) => {
|
|
|
50
51
|
return false;
|
|
51
52
|
};
|
|
52
53
|
exports.isInGraphicalAbstractSection = isInGraphicalAbstractSection;
|
|
54
|
+
const isInBibliographySection = ($pos) => {
|
|
55
|
+
for (let i = $pos.depth; i > 0; i--) {
|
|
56
|
+
const node = $pos.node(i);
|
|
57
|
+
if ((0, bibliography_section_1.isBibliographySectionNode)(node)) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
};
|
|
63
|
+
exports.isInBibliographySection = isInBibliographySection;
|
|
53
64
|
const findParentNodeClosestToPos = ($pos, predicate) => {
|
|
54
65
|
for (let i = $pos.depth; i > 0; i--) {
|
|
55
66
|
const node = $pos.node(i);
|
package/dist/cjs/schema/index.js
CHANGED
|
@@ -59,6 +59,7 @@ const inline_equation_1 = require("./nodes/inline_equation");
|
|
|
59
59
|
const inline_footnote_1 = require("./nodes/inline_footnote");
|
|
60
60
|
const keyword_1 = require("./nodes/keyword");
|
|
61
61
|
const keywords_element_1 = require("./nodes/keywords_element");
|
|
62
|
+
const keywords_group_1 = require("./nodes/keywords_group");
|
|
62
63
|
const keywords_section_1 = require("./nodes/keywords_section");
|
|
63
64
|
const link_1 = require("./nodes/link");
|
|
64
65
|
const list_1 = require("./nodes/list");
|
|
@@ -173,6 +174,7 @@ exports.schema = new prosemirror_model_1.Schema({
|
|
|
173
174
|
keyword: keyword_1.keyword,
|
|
174
175
|
keywords_element: keywords_element_1.keywordsElement,
|
|
175
176
|
keywords_section: keywords_section_1.keywordsSection,
|
|
177
|
+
keywords_group: keywords_group_1.keywordsGroup,
|
|
176
178
|
link: link_1.link,
|
|
177
179
|
list_item: list_1.listItem,
|
|
178
180
|
listing: listing_1.listing,
|
|
@@ -18,11 +18,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
18
18
|
exports.keywordsElement = void 0;
|
|
19
19
|
exports.keywordsElement = {
|
|
20
20
|
atom: true,
|
|
21
|
-
content: '
|
|
21
|
+
content: 'keywords_group*',
|
|
22
22
|
attrs: {
|
|
23
23
|
id: { default: '' },
|
|
24
24
|
contents: { default: '' },
|
|
25
25
|
paragraphStyle: { default: '' },
|
|
26
|
+
type: { default: '' },
|
|
26
27
|
dataTracked: { default: null },
|
|
27
28
|
},
|
|
28
29
|
group: 'block element',
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* © 2019 Atypon Systems LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.isKeywordsGroupNode = exports.keywordsGroup = void 0;
|
|
19
|
+
exports.keywordsGroup = {
|
|
20
|
+
content: 'keyword*',
|
|
21
|
+
attrs: {
|
|
22
|
+
id: { default: '' },
|
|
23
|
+
type: { default: '' },
|
|
24
|
+
dataTracked: { default: null },
|
|
25
|
+
},
|
|
26
|
+
group: 'block',
|
|
27
|
+
selectable: false,
|
|
28
|
+
parseDOM: [
|
|
29
|
+
{
|
|
30
|
+
tag: 'div.keywords',
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
toDOM: (node) => {
|
|
34
|
+
const keywordsGroupNode = node;
|
|
35
|
+
return [
|
|
36
|
+
'div',
|
|
37
|
+
{
|
|
38
|
+
id: keywordsGroupNode.attrs.id,
|
|
39
|
+
class: 'keywords',
|
|
40
|
+
spellcheck: 'false',
|
|
41
|
+
contenteditable: false,
|
|
42
|
+
},
|
|
43
|
+
0,
|
|
44
|
+
];
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
const isKeywordsGroupNode = (node) => node.type === node.type.schema.nodes.keywords_group;
|
|
48
|
+
exports.isKeywordsGroupNode = isKeywordsGroupNode;
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.isKeywordsSectionNode = exports.keywordsSection = void 0;
|
|
19
19
|
exports.keywordsSection = {
|
|
20
|
-
content: '
|
|
20
|
+
content: 'section_title (keywords_element | placeholder_element)',
|
|
21
21
|
attrs: {
|
|
22
22
|
id: { default: '' },
|
|
23
23
|
dataTracked: { default: null },
|
|
@@ -275,11 +275,11 @@ class Decoder {
|
|
|
275
275
|
},
|
|
276
276
|
[json_schema_1.ObjectTypes.KeywordsElement]: (data) => {
|
|
277
277
|
const model = data;
|
|
278
|
-
const
|
|
278
|
+
const keywordGroups = this.getKeywordGroups();
|
|
279
279
|
return schema_1.schema.nodes.keywords_element.create({
|
|
280
280
|
id: model._id,
|
|
281
281
|
paragraphStyle: model.paragraphStyle,
|
|
282
|
-
},
|
|
282
|
+
}, keywordGroups);
|
|
283
283
|
},
|
|
284
284
|
[json_schema_1.ObjectTypes.Keyword]: (data) => {
|
|
285
285
|
const model = data;
|
|
@@ -426,9 +426,7 @@ class Decoder {
|
|
|
426
426
|
const elementNodes = elements
|
|
427
427
|
.map(this.decode)
|
|
428
428
|
.filter(exports.isManuscriptNode);
|
|
429
|
-
const sectionTitle =
|
|
430
|
-
? 'section_title_plain'
|
|
431
|
-
: 'section_title';
|
|
429
|
+
const sectionTitle = 'section_title';
|
|
432
430
|
const sectionTitleNode = model.title
|
|
433
431
|
? this.parseContents(model.title, 'h1', this.getComments(model), {
|
|
434
432
|
topNode: schema_1.schema.nodes[sectionTitle].create(),
|
|
@@ -572,19 +570,6 @@ class Decoder {
|
|
|
572
570
|
id: (0, id_1.generateNodeID)(schema_1.schema.nodes.section),
|
|
573
571
|
}));
|
|
574
572
|
}
|
|
575
|
-
const keywordsSection = getSections(this.modelMap).filter((section) => section.category === 'MPSectionCategory:keywords');
|
|
576
|
-
const keywords = this.getKeywords();
|
|
577
|
-
if (keywordsSection.length === 0 && keywords.length > 0) {
|
|
578
|
-
const keywordsSection = schema_1.schema.nodes.keywords_section.createAndFill({
|
|
579
|
-
id: (0, id_1.generateNodeID)(schema_1.schema.nodes.keywords_section),
|
|
580
|
-
}, [
|
|
581
|
-
schema_1.schema.nodes.section_title_plain.create({}, schema_1.schema.text('Keywords')),
|
|
582
|
-
schema_1.schema.nodes.keywords_element.create({
|
|
583
|
-
id: (0, id_1.generateNodeID)(schema_1.schema.nodes.keywords_element),
|
|
584
|
-
}, keywords),
|
|
585
|
-
]);
|
|
586
|
-
rootSectionNodes.unshift(keywordsSection);
|
|
587
|
-
}
|
|
588
573
|
const contents = rootSectionNodes;
|
|
589
574
|
if (this.comments.size) {
|
|
590
575
|
const comments = schema_1.schema.nodes.comment_list.createAndFill({
|
|
@@ -632,17 +617,16 @@ class Decoder {
|
|
|
632
617
|
}
|
|
633
618
|
return parser.parse(template.content.firstElementChild, options);
|
|
634
619
|
};
|
|
635
|
-
this.getKeywords = () => {
|
|
620
|
+
this.getKeywords = (id) => {
|
|
636
621
|
const keywordsOfKind = [];
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
622
|
+
const keywordsByGroup = [...this.modelMap.values()].filter((m) => m.objectType === json_schema_1.ObjectTypes.Keyword &&
|
|
623
|
+
m.containedGroup === id);
|
|
624
|
+
for (const model of keywordsByGroup) {
|
|
640
625
|
if (isKeyword(model)) {
|
|
641
626
|
const keyword = this.parseContents(model.name || '', 'div', this.getComments(model), {
|
|
642
627
|
topNode: schema_1.schema.nodes.keyword.create({
|
|
643
628
|
id: model._id,
|
|
644
629
|
contents: model.name,
|
|
645
|
-
comments: commentNodes.map((c) => c.attrs.id),
|
|
646
630
|
}),
|
|
647
631
|
});
|
|
648
632
|
keywordsOfKind.push(keyword);
|
|
@@ -689,5 +673,27 @@ class Decoder {
|
|
|
689
673
|
this.modelMap = modelMap;
|
|
690
674
|
this.allowMissingElements = allowMissingElements;
|
|
691
675
|
}
|
|
676
|
+
getKeywordGroups() {
|
|
677
|
+
const kwdGroupNodes = [];
|
|
678
|
+
const kwdGroupsModels = [
|
|
679
|
+
...this.modelMap.values(),
|
|
680
|
+
].filter((model) => model.objectType === json_schema_1.ObjectTypes.KeywordGroup);
|
|
681
|
+
if (kwdGroupsModels.length > 0) {
|
|
682
|
+
for (const kwdGroupModel of kwdGroupsModels) {
|
|
683
|
+
const keywords = this.getKeywords(kwdGroupModel._id);
|
|
684
|
+
const commentNodes = this.createCommentsNode(kwdGroupModel);
|
|
685
|
+
commentNodes.forEach((c) => this.comments.set(c.attrs.id, c));
|
|
686
|
+
const contents = [];
|
|
687
|
+
contents.push(...keywords);
|
|
688
|
+
const kwdGroupNode = schema_1.schema.nodes.keywords_group.create({
|
|
689
|
+
id: kwdGroupModel._id,
|
|
690
|
+
type: kwdGroupModel.type,
|
|
691
|
+
comments: commentNodes.map((c) => c.attrs.id),
|
|
692
|
+
}, contents);
|
|
693
|
+
kwdGroupNodes.push(kwdGroupNode);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
return kwdGroupNodes;
|
|
697
|
+
}
|
|
692
698
|
}
|
|
693
699
|
exports.Decoder = Decoder;
|
|
@@ -401,18 +401,21 @@ const encoders = {
|
|
|
401
401
|
SVGGlyphs: svgDefs(node.attrs.SVGRepresentation),
|
|
402
402
|
}),
|
|
403
403
|
keyword: (node, parent) => ({
|
|
404
|
-
|
|
404
|
+
containedGroup: parent.attrs.id,
|
|
405
405
|
name: keywordContents(node),
|
|
406
406
|
}),
|
|
407
407
|
keywords_element: (node) => ({
|
|
408
|
-
contents:
|
|
408
|
+
contents: '<div></div>',
|
|
409
409
|
elementType: 'div',
|
|
410
410
|
paragraphStyle: node.attrs.paragraphStyle || undefined,
|
|
411
411
|
}),
|
|
412
|
+
keywords_group: (node) => ({
|
|
413
|
+
type: node.attrs.type,
|
|
414
|
+
}),
|
|
412
415
|
keywords_section: (node, parent, path, priority) => ({
|
|
413
416
|
category: (0, section_category_1.buildSectionCategory)(node),
|
|
414
417
|
priority: priority.value++,
|
|
415
|
-
title: inlineContentsOfNodeType(node, node.type.schema.nodes.
|
|
418
|
+
title: inlineContentsOfNodeType(node, node.type.schema.nodes.section_title),
|
|
416
419
|
path: path.concat([node.attrs.id]),
|
|
417
420
|
elementIDs: childElements(node)
|
|
418
421
|
.map((childNode) => childNode.attrs.id)
|
|
@@ -41,6 +41,7 @@ exports.nodeTypesMap = new Map([
|
|
|
41
41
|
[schema_1.schema.nodes.keyword, json_schema_1.ObjectTypes.Keyword],
|
|
42
42
|
[schema_1.schema.nodes.keywords_element, json_schema_1.ObjectTypes.KeywordsElement],
|
|
43
43
|
[schema_1.schema.nodes.keywords_section, json_schema_1.ObjectTypes.Section],
|
|
44
|
+
[schema_1.schema.nodes.keywords_group, json_schema_1.ObjectTypes.KeywordGroup],
|
|
44
45
|
[schema_1.schema.nodes.listing, json_schema_1.ObjectTypes.Listing],
|
|
45
46
|
[schema_1.schema.nodes.listing_element, json_schema_1.ObjectTypes.ListingElement],
|
|
46
47
|
[schema_1.schema.nodes.manuscript, json_schema_1.ObjectTypes.Manuscript],
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.isCommentAnnotation = exports.isUserProfile = exports.isTable = exports.isManuscript = exports.isFigure = exports.hasObjectType = exports.isManuscriptModel = exports.manuscriptObjects = exports.elementObjects = exports.ExtraObjectTypes = void 0;
|
|
18
|
+
exports.isKeyword = exports.isCommentAnnotation = exports.isUserProfile = exports.isTable = exports.isManuscript = exports.isFigure = exports.hasObjectType = exports.isManuscriptModel = exports.manuscriptObjects = exports.elementObjects = exports.ExtraObjectTypes = void 0;
|
|
19
19
|
const json_schema_1 = require("@manuscripts/json-schema");
|
|
20
20
|
var ExtraObjectTypes;
|
|
21
21
|
(function (ExtraObjectTypes) {
|
|
@@ -55,3 +55,4 @@ exports.isManuscript = (0, exports.hasObjectType)(json_schema_1.ObjectTypes.Manu
|
|
|
55
55
|
exports.isTable = (0, exports.hasObjectType)(json_schema_1.ObjectTypes.Table);
|
|
56
56
|
exports.isUserProfile = (0, exports.hasObjectType)(json_schema_1.ObjectTypes.UserProfile);
|
|
57
57
|
exports.isCommentAnnotation = (0, exports.hasObjectType)(json_schema_1.ObjectTypes.CommentAnnotation);
|
|
58
|
+
exports.isKeyword = (0, exports.hasObjectType)(json_schema_1.ObjectTypes.Keyword);
|
|
@@ -499,6 +499,22 @@ const nodes = [
|
|
|
499
499
|
};
|
|
500
500
|
},
|
|
501
501
|
},
|
|
502
|
+
{
|
|
503
|
+
tag: 'sec[sec-type="keywords"]',
|
|
504
|
+
node: 'keywords_section',
|
|
505
|
+
getAttrs: (node) => {
|
|
506
|
+
const element = node;
|
|
507
|
+
return {
|
|
508
|
+
id: element.getAttribute('id'),
|
|
509
|
+
category: chooseSectionCategory(element),
|
|
510
|
+
};
|
|
511
|
+
},
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
tag: 'kwd-group-list',
|
|
515
|
+
context: 'keywords_section/',
|
|
516
|
+
node: 'keywords_element',
|
|
517
|
+
},
|
|
502
518
|
{
|
|
503
519
|
tag: 'sec',
|
|
504
520
|
node: 'section',
|
|
@@ -510,6 +526,22 @@ const nodes = [
|
|
|
510
526
|
};
|
|
511
527
|
},
|
|
512
528
|
},
|
|
529
|
+
{
|
|
530
|
+
tag: 'kwd-group',
|
|
531
|
+
context: 'keywords_element/',
|
|
532
|
+
node: 'keywords_group',
|
|
533
|
+
getAttrs: (node) => {
|
|
534
|
+
const element = node;
|
|
535
|
+
return {
|
|
536
|
+
type: element.getAttribute('kwd-group-type'),
|
|
537
|
+
};
|
|
538
|
+
},
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
tag: 'kwd',
|
|
542
|
+
context: 'keywords_group//',
|
|
543
|
+
node: 'keyword',
|
|
544
|
+
},
|
|
513
545
|
{
|
|
514
546
|
tag: 'label',
|
|
515
547
|
context: 'section/',
|
|
@@ -562,7 +594,7 @@ const nodes = [
|
|
|
562
594
|
{
|
|
563
595
|
tag: 'title',
|
|
564
596
|
node: 'section_title',
|
|
565
|
-
context: 'section/|footnotes_section/|bibliography_section/',
|
|
597
|
+
context: 'section/|footnotes_section/|bibliography_section/|keywords_section/',
|
|
566
598
|
},
|
|
567
599
|
{
|
|
568
600
|
tag: 'title',
|
|
@@ -263,4 +263,18 @@ export const jatsBodyTransformations = {
|
|
|
263
263
|
paragraph === null || paragraph === void 0 ? void 0 : paragraph.replaceWith(parent);
|
|
264
264
|
});
|
|
265
265
|
},
|
|
266
|
+
moveKeywordsToBody(document, body, createElement) {
|
|
267
|
+
const keywordGroups = [...document.querySelectorAll('kwd-group')];
|
|
268
|
+
if (keywordGroups.length > 0) {
|
|
269
|
+
const section = createElement('sec');
|
|
270
|
+
section.setAttribute('sec-type', 'keywords');
|
|
271
|
+
const title = createElement('title');
|
|
272
|
+
title.textContent = 'Keywords';
|
|
273
|
+
section.append(title);
|
|
274
|
+
const kwdGroupsEl = createElement('kwd-group-list');
|
|
275
|
+
kwdGroupsEl.append(keywordGroups[0]);
|
|
276
|
+
section.append(kwdGroupsEl);
|
|
277
|
+
body.prepend(section);
|
|
278
|
+
}
|
|
279
|
+
},
|
|
266
280
|
};
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
import { v4 as uuidv4 } from 'uuid';
|
|
17
|
-
import { buildComment, buildContribution, isCommentAnnotation, isHighlightableModel, } from '../../transformer';
|
|
17
|
+
import { buildComment, buildContribution, isCommentAnnotation, isHighlightableModel, isKeyword, } from '../../transformer';
|
|
18
18
|
const DEFAULT_ANNOTATION_COLOR = 'rgb(250, 224, 150)';
|
|
19
19
|
const DEFAULT_PROFILE_ID = 'MPUserProfile:0000000000000000000000000000000000000001';
|
|
20
20
|
export const parseProcessingInstruction = (node) => {
|
|
@@ -58,6 +58,21 @@ const insertToken = (doc, processingInstructionNode, authorQueriesMap) => {
|
|
|
58
58
|
return parentElement.insertBefore(tokenNode, processingInstructionNode);
|
|
59
59
|
}
|
|
60
60
|
};
|
|
61
|
+
const extractCommentsFromKeywords = (tokens, model, authorQueriesMap) => {
|
|
62
|
+
var _a;
|
|
63
|
+
const commentAnnotations = [];
|
|
64
|
+
const name = model.name;
|
|
65
|
+
const filteredTokens = filterAndSortTokens(tokens, name);
|
|
66
|
+
let content = name;
|
|
67
|
+
for (const token of filteredTokens) {
|
|
68
|
+
content = name.replace(token, '');
|
|
69
|
+
const query = authorQueriesMap.get(token);
|
|
70
|
+
const commentAnnotation = buildComment((_a = model.containedGroup) !== null && _a !== void 0 ? _a : uuidv4(), `${query}`, undefined, [buildContribution(DEFAULT_PROFILE_ID)], DEFAULT_ANNOTATION_COLOR);
|
|
71
|
+
model['name'] = content;
|
|
72
|
+
commentAnnotations.push(commentAnnotation);
|
|
73
|
+
}
|
|
74
|
+
return commentAnnotations;
|
|
75
|
+
};
|
|
61
76
|
export const createComments = (authorQueriesMap, manuscriptModels) => {
|
|
62
77
|
const tokens = [...authorQueriesMap.keys()];
|
|
63
78
|
const commentAnnotations = [];
|
|
@@ -66,9 +81,18 @@ export const createComments = (authorQueriesMap, manuscriptModels) => {
|
|
|
66
81
|
const comments = addCommentsFromMarkedProcessingInstructions(tokens, model, authorQueriesMap);
|
|
67
82
|
commentAnnotations.push(...comments);
|
|
68
83
|
}
|
|
84
|
+
else if (isKeyword(model)) {
|
|
85
|
+
const comments = extractCommentsFromKeywords(tokens, model, authorQueriesMap);
|
|
86
|
+
commentAnnotations.push(...comments);
|
|
87
|
+
}
|
|
69
88
|
}
|
|
70
89
|
return commentAnnotations;
|
|
71
90
|
};
|
|
91
|
+
function filterAndSortTokens(tokens, content) {
|
|
92
|
+
return tokens
|
|
93
|
+
.filter((token) => content.indexOf(token) >= 0)
|
|
94
|
+
.sort((a, b) => content.indexOf(a) - content.indexOf(b));
|
|
95
|
+
}
|
|
72
96
|
const addCommentsFromMarkedProcessingInstructions = (tokens, model, authorQueriesMap) => {
|
|
73
97
|
const commentAnnotations = [];
|
|
74
98
|
for (const field of ['contents', 'caption', 'title']) {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
import debug from 'debug';
|
|
17
|
-
import { buildAffiliation, buildBibliographicName, buildContributor, buildCorresp, buildFootnote,
|
|
17
|
+
import { buildAffiliation, buildBibliographicName, buildContributor, buildCorresp, buildFootnote, buildSupplementaryMaterial, } from '../../transformer/builders';
|
|
18
18
|
import { parseJournalMeta } from './jats-journal-meta-parser';
|
|
19
19
|
const warn = debug('manuscripts-transform');
|
|
20
20
|
const XLINK_NAMESPACE = 'http://www.w3.org/1999/xlink';
|
|
@@ -62,31 +62,6 @@ export const jatsFrontParser = {
|
|
|
62
62
|
}
|
|
63
63
|
return parseJournalMeta(journalMeta);
|
|
64
64
|
},
|
|
65
|
-
parseKeywords(keywordGroupNodes) {
|
|
66
|
-
var _a, _b;
|
|
67
|
-
if (!keywordGroupNodes) {
|
|
68
|
-
return { groups: [], keywords: [] };
|
|
69
|
-
}
|
|
70
|
-
let keywordPriority = 1;
|
|
71
|
-
const keywordGroups = { groups: [], keywords: [] };
|
|
72
|
-
for (const keywordGroupNode of keywordGroupNodes) {
|
|
73
|
-
const manuscriptKeywordGroup = buildKeywordGroup({
|
|
74
|
-
title: ((_a = keywordGroupNode.querySelector('title')) === null || _a === void 0 ? void 0 : _a.textContent) || undefined,
|
|
75
|
-
label: ((_b = keywordGroupNode.querySelector('label')) === null || _b === void 0 ? void 0 : _b.textContent) || undefined,
|
|
76
|
-
type: keywordGroupNode.getAttribute('kwd-group-type') || undefined,
|
|
77
|
-
});
|
|
78
|
-
keywordGroups.groups.push(manuscriptKeywordGroup);
|
|
79
|
-
for (const keywordNode of keywordGroupNode.querySelectorAll('kwd')) {
|
|
80
|
-
if (keywordNode.textContent) {
|
|
81
|
-
const keyword = buildKeyword(keywordNode.textContent);
|
|
82
|
-
keyword.priority = keywordPriority++;
|
|
83
|
-
keyword.containedGroup = manuscriptKeywordGroup._id;
|
|
84
|
-
keywordGroups.keywords.push(keyword);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
return keywordGroups;
|
|
89
|
-
},
|
|
90
65
|
parseDates(historyNode) {
|
|
91
66
|
if (!historyNode) {
|
|
92
67
|
return undefined;
|
|
@@ -51,9 +51,6 @@ export const parseJATSFront = async (front) => {
|
|
|
51
51
|
const manuscriptMeta = Object.assign({ title: title ? inlineContentsFromJATSTitle(title) : undefined, subtitle: subtitle ? inlineContentsFromJATSTitle(subtitle) : undefined, runningTitle: runningTitle
|
|
52
52
|
? inlineContentsFromJATSTitle(runningTitle)
|
|
53
53
|
: undefined }, jatsFrontParser.parseCounts(articleMeta === null || articleMeta === void 0 ? void 0 : articleMeta.querySelector('counts')));
|
|
54
|
-
const keywordGroupNodes = articleMeta === null || articleMeta === void 0 ? void 0 : articleMeta.querySelectorAll('kwd-group');
|
|
55
|
-
const { keywords, groups: keywordGroups } = jatsFrontParser.parseKeywords(keywordGroupNodes);
|
|
56
|
-
const manuscript_keywordIDs = keywords.length > 0 ? keywords.map((k) => k._id) : undefined;
|
|
57
54
|
const { affiliations, affiliationIDs } = jatsFrontParser.parseAffiliationNodes([
|
|
58
55
|
...front.querySelectorAll('article-meta > contrib-group > aff'),
|
|
59
56
|
]);
|
|
@@ -70,14 +67,12 @@ export const parseJATSFront = async (front) => {
|
|
|
70
67
|
const supplements = jatsFrontParser.parseSupplements([
|
|
71
68
|
...front.querySelectorAll('article-meta > supplementary-material'),
|
|
72
69
|
]);
|
|
73
|
-
const manuscript = Object.assign(Object.assign(Object.assign(
|
|
70
|
+
const manuscript = Object.assign(Object.assign(Object.assign({}, buildManuscript()), manuscriptMeta), history);
|
|
74
71
|
return {
|
|
75
72
|
models: generateModelIDs([
|
|
76
73
|
manuscript,
|
|
77
|
-
...keywords,
|
|
78
74
|
...affiliations,
|
|
79
75
|
...authors,
|
|
80
|
-
...keywordGroups,
|
|
81
76
|
...footnotes,
|
|
82
77
|
...correspondingList,
|
|
83
78
|
journal,
|
|
@@ -116,6 +111,7 @@ export const parseJATSBody = (document, body, bibliographyItems, refModels, refe
|
|
|
116
111
|
jatsBodyTransformations.moveCaptionsToEnd(body);
|
|
117
112
|
jatsBodyTransformations.moveTableFooterToEnd(body);
|
|
118
113
|
jatsBodyTransformations.moveBlockNodesFromParagraph(document, body, createElement);
|
|
114
|
+
jatsBodyTransformations.moveKeywordsToBody(document, body, createElement);
|
|
119
115
|
const node = jatsBodyDOMParser.parse(body);
|
|
120
116
|
if (!node.firstChild) {
|
|
121
117
|
throw new Error('No content was parsed from the JATS article body');
|
|
@@ -391,9 +391,7 @@ export class JATSExporter {
|
|
|
391
391
|
if (history.childElementCount) {
|
|
392
392
|
articleMeta.appendChild(history);
|
|
393
393
|
}
|
|
394
|
-
|
|
395
|
-
this.buildKeywords(articleMeta, manuscript.keywordIDs);
|
|
396
|
-
}
|
|
394
|
+
this.buildKeywords(articleMeta);
|
|
397
395
|
let countingElements = [];
|
|
398
396
|
if (manuscript.genericCounts) {
|
|
399
397
|
const elements = manuscript.genericCounts.map((el) => {
|
|
@@ -617,6 +615,7 @@ export class JATSExporter {
|
|
|
617
615
|
bibliography_element: () => '',
|
|
618
616
|
bibliography_item: () => '',
|
|
619
617
|
comment_list: () => '',
|
|
618
|
+
keywords_group: () => '',
|
|
620
619
|
bibliography_section: (node) => [
|
|
621
620
|
'ref-list',
|
|
622
621
|
{ id: normalizeID(node.attrs.id) },
|
|
@@ -1522,10 +1521,8 @@ export class JATSExporter {
|
|
|
1522
1521
|
return name;
|
|
1523
1522
|
};
|
|
1524
1523
|
}
|
|
1525
|
-
buildKeywords(articleMeta
|
|
1526
|
-
const keywords =
|
|
1527
|
-
.map((id) => this.modelMap.get(id))
|
|
1528
|
-
.filter((model) => model && model.name);
|
|
1524
|
+
buildKeywords(articleMeta) {
|
|
1525
|
+
const keywords = [...this.modelMap.values()].filter((model) => model.objectType === ObjectTypes.Keyword);
|
|
1529
1526
|
const keywordGroups = new Map();
|
|
1530
1527
|
keywords.forEach((keyword) => {
|
|
1531
1528
|
const containedGroup = keyword.containedGroup || '';
|
|
@@ -1559,6 +1556,7 @@ export class JATSExporter {
|
|
|
1559
1556
|
kwd.textContent = keyword.name;
|
|
1560
1557
|
kwdGroup.appendChild(kwd);
|
|
1561
1558
|
}
|
|
1559
|
+
articleMeta.appendChild(kwdGroup);
|
|
1562
1560
|
}
|
|
1563
1561
|
}
|
|
1564
1562
|
}
|
package/dist/es/lib/utils.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
import { isBibliographySectionNode } from '../schema/nodes/bibliography_section';
|
|
16
17
|
import { isGraphicalAbstractSectionNode } from '../schema/nodes/graphical_abstract_section';
|
|
17
18
|
export function* iterateChildren(node, recurse = false) {
|
|
18
19
|
for (let i = 0; i < node.childCount; i++) {
|
|
@@ -44,6 +45,15 @@ export const isInGraphicalAbstractSection = ($pos) => {
|
|
|
44
45
|
}
|
|
45
46
|
return false;
|
|
46
47
|
};
|
|
48
|
+
export const isInBibliographySection = ($pos) => {
|
|
49
|
+
for (let i = $pos.depth; i > 0; i--) {
|
|
50
|
+
const node = $pos.node(i);
|
|
51
|
+
if (isBibliographySectionNode(node)) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
};
|
|
47
57
|
export const findParentNodeClosestToPos = ($pos, predicate) => {
|
|
48
58
|
for (let i = $pos.depth; i > 0; i--) {
|
|
49
59
|
const node = $pos.node(i);
|
package/dist/es/schema/index.js
CHANGED
|
@@ -42,6 +42,7 @@ import { inlineEquation } from './nodes/inline_equation';
|
|
|
42
42
|
import { inlineFootnote } from './nodes/inline_footnote';
|
|
43
43
|
import { keyword } from './nodes/keyword';
|
|
44
44
|
import { keywordsElement } from './nodes/keywords_element';
|
|
45
|
+
import { keywordsGroup } from './nodes/keywords_group';
|
|
45
46
|
import { keywordsSection } from './nodes/keywords_section';
|
|
46
47
|
import { link } from './nodes/link';
|
|
47
48
|
import { bulletList, listItem, orderedList } from './nodes/list';
|
|
@@ -156,6 +157,7 @@ export const schema = new Schema({
|
|
|
156
157
|
keyword,
|
|
157
158
|
keywords_element: keywordsElement,
|
|
158
159
|
keywords_section: keywordsSection,
|
|
160
|
+
keywords_group: keywordsGroup,
|
|
159
161
|
link,
|
|
160
162
|
list_item: listItem,
|
|
161
163
|
listing,
|
|
@@ -15,11 +15,12 @@
|
|
|
15
15
|
*/
|
|
16
16
|
export const keywordsElement = {
|
|
17
17
|
atom: true,
|
|
18
|
-
content: '
|
|
18
|
+
content: 'keywords_group*',
|
|
19
19
|
attrs: {
|
|
20
20
|
id: { default: '' },
|
|
21
21
|
contents: { default: '' },
|
|
22
22
|
paragraphStyle: { default: '' },
|
|
23
|
+
type: { default: '' },
|
|
23
24
|
dataTracked: { default: null },
|
|
24
25
|
},
|
|
25
26
|
group: 'block element',
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* © 2019 Atypon Systems LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
export const keywordsGroup = {
|
|
17
|
+
content: 'keyword*',
|
|
18
|
+
attrs: {
|
|
19
|
+
id: { default: '' },
|
|
20
|
+
type: { default: '' },
|
|
21
|
+
dataTracked: { default: null },
|
|
22
|
+
},
|
|
23
|
+
group: 'block',
|
|
24
|
+
selectable: false,
|
|
25
|
+
parseDOM: [
|
|
26
|
+
{
|
|
27
|
+
tag: 'div.keywords',
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
toDOM: (node) => {
|
|
31
|
+
const keywordsGroupNode = node;
|
|
32
|
+
return [
|
|
33
|
+
'div',
|
|
34
|
+
{
|
|
35
|
+
id: keywordsGroupNode.attrs.id,
|
|
36
|
+
class: 'keywords',
|
|
37
|
+
spellcheck: 'false',
|
|
38
|
+
contenteditable: false,
|
|
39
|
+
},
|
|
40
|
+
0,
|
|
41
|
+
];
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
export const isKeywordsGroupNode = (node) => node.type === node.type.schema.nodes.keywords_group;
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
export const keywordsSection = {
|
|
17
|
-
content: '
|
|
17
|
+
content: 'section_title (keywords_element | placeholder_element)',
|
|
18
18
|
attrs: {
|
|
19
19
|
id: { default: '' },
|
|
20
20
|
dataTracked: { default: null },
|
|
@@ -265,11 +265,11 @@ export class Decoder {
|
|
|
265
265
|
},
|
|
266
266
|
[ObjectTypes.KeywordsElement]: (data) => {
|
|
267
267
|
const model = data;
|
|
268
|
-
const
|
|
268
|
+
const keywordGroups = this.getKeywordGroups();
|
|
269
269
|
return schema.nodes.keywords_element.create({
|
|
270
270
|
id: model._id,
|
|
271
271
|
paragraphStyle: model.paragraphStyle,
|
|
272
|
-
},
|
|
272
|
+
}, keywordGroups);
|
|
273
273
|
},
|
|
274
274
|
[ObjectTypes.Keyword]: (data) => {
|
|
275
275
|
const model = data;
|
|
@@ -416,9 +416,7 @@ export class Decoder {
|
|
|
416
416
|
const elementNodes = elements
|
|
417
417
|
.map(this.decode)
|
|
418
418
|
.filter(isManuscriptNode);
|
|
419
|
-
const sectionTitle =
|
|
420
|
-
? 'section_title_plain'
|
|
421
|
-
: 'section_title';
|
|
419
|
+
const sectionTitle = 'section_title';
|
|
422
420
|
const sectionTitleNode = model.title
|
|
423
421
|
? this.parseContents(model.title, 'h1', this.getComments(model), {
|
|
424
422
|
topNode: schema.nodes[sectionTitle].create(),
|
|
@@ -562,19 +560,6 @@ export class Decoder {
|
|
|
562
560
|
id: generateNodeID(schema.nodes.section),
|
|
563
561
|
}));
|
|
564
562
|
}
|
|
565
|
-
const keywordsSection = getSections(this.modelMap).filter((section) => section.category === 'MPSectionCategory:keywords');
|
|
566
|
-
const keywords = this.getKeywords();
|
|
567
|
-
if (keywordsSection.length === 0 && keywords.length > 0) {
|
|
568
|
-
const keywordsSection = schema.nodes.keywords_section.createAndFill({
|
|
569
|
-
id: generateNodeID(schema.nodes.keywords_section),
|
|
570
|
-
}, [
|
|
571
|
-
schema.nodes.section_title_plain.create({}, schema.text('Keywords')),
|
|
572
|
-
schema.nodes.keywords_element.create({
|
|
573
|
-
id: generateNodeID(schema.nodes.keywords_element),
|
|
574
|
-
}, keywords),
|
|
575
|
-
]);
|
|
576
|
-
rootSectionNodes.unshift(keywordsSection);
|
|
577
|
-
}
|
|
578
563
|
const contents = rootSectionNodes;
|
|
579
564
|
if (this.comments.size) {
|
|
580
565
|
const comments = schema.nodes.comment_list.createAndFill({
|
|
@@ -622,17 +607,16 @@ export class Decoder {
|
|
|
622
607
|
}
|
|
623
608
|
return parser.parse(template.content.firstElementChild, options);
|
|
624
609
|
};
|
|
625
|
-
this.getKeywords = () => {
|
|
610
|
+
this.getKeywords = (id) => {
|
|
626
611
|
const keywordsOfKind = [];
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
612
|
+
const keywordsByGroup = [...this.modelMap.values()].filter((m) => m.objectType === ObjectTypes.Keyword &&
|
|
613
|
+
m.containedGroup === id);
|
|
614
|
+
for (const model of keywordsByGroup) {
|
|
630
615
|
if (isKeyword(model)) {
|
|
631
616
|
const keyword = this.parseContents(model.name || '', 'div', this.getComments(model), {
|
|
632
617
|
topNode: schema.nodes.keyword.create({
|
|
633
618
|
id: model._id,
|
|
634
619
|
contents: model.name,
|
|
635
|
-
comments: commentNodes.map((c) => c.attrs.id),
|
|
636
620
|
}),
|
|
637
621
|
});
|
|
638
622
|
keywordsOfKind.push(keyword);
|
|
@@ -679,4 +663,26 @@ export class Decoder {
|
|
|
679
663
|
this.modelMap = modelMap;
|
|
680
664
|
this.allowMissingElements = allowMissingElements;
|
|
681
665
|
}
|
|
666
|
+
getKeywordGroups() {
|
|
667
|
+
const kwdGroupNodes = [];
|
|
668
|
+
const kwdGroupsModels = [
|
|
669
|
+
...this.modelMap.values(),
|
|
670
|
+
].filter((model) => model.objectType === ObjectTypes.KeywordGroup);
|
|
671
|
+
if (kwdGroupsModels.length > 0) {
|
|
672
|
+
for (const kwdGroupModel of kwdGroupsModels) {
|
|
673
|
+
const keywords = this.getKeywords(kwdGroupModel._id);
|
|
674
|
+
const commentNodes = this.createCommentsNode(kwdGroupModel);
|
|
675
|
+
commentNodes.forEach((c) => this.comments.set(c.attrs.id, c));
|
|
676
|
+
const contents = [];
|
|
677
|
+
contents.push(...keywords);
|
|
678
|
+
const kwdGroupNode = schema.nodes.keywords_group.create({
|
|
679
|
+
id: kwdGroupModel._id,
|
|
680
|
+
type: kwdGroupModel.type,
|
|
681
|
+
comments: commentNodes.map((c) => c.attrs.id),
|
|
682
|
+
}, contents);
|
|
683
|
+
kwdGroupNodes.push(kwdGroupNode);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
return kwdGroupNodes;
|
|
687
|
+
}
|
|
682
688
|
}
|
|
@@ -393,18 +393,21 @@ const encoders = {
|
|
|
393
393
|
SVGGlyphs: svgDefs(node.attrs.SVGRepresentation),
|
|
394
394
|
}),
|
|
395
395
|
keyword: (node, parent) => ({
|
|
396
|
-
|
|
396
|
+
containedGroup: parent.attrs.id,
|
|
397
397
|
name: keywordContents(node),
|
|
398
398
|
}),
|
|
399
399
|
keywords_element: (node) => ({
|
|
400
|
-
contents:
|
|
400
|
+
contents: '<div></div>',
|
|
401
401
|
elementType: 'div',
|
|
402
402
|
paragraphStyle: node.attrs.paragraphStyle || undefined,
|
|
403
403
|
}),
|
|
404
|
+
keywords_group: (node) => ({
|
|
405
|
+
type: node.attrs.type,
|
|
406
|
+
}),
|
|
404
407
|
keywords_section: (node, parent, path, priority) => ({
|
|
405
408
|
category: buildSectionCategory(node),
|
|
406
409
|
priority: priority.value++,
|
|
407
|
-
title: inlineContentsOfNodeType(node, node.type.schema.nodes.
|
|
410
|
+
title: inlineContentsOfNodeType(node, node.type.schema.nodes.section_title),
|
|
408
411
|
path: path.concat([node.attrs.id]),
|
|
409
412
|
elementIDs: childElements(node)
|
|
410
413
|
.map((childNode) => childNode.attrs.id)
|
|
@@ -38,6 +38,7 @@ export const nodeTypesMap = new Map([
|
|
|
38
38
|
[schema.nodes.keyword, ObjectTypes.Keyword],
|
|
39
39
|
[schema.nodes.keywords_element, ObjectTypes.KeywordsElement],
|
|
40
40
|
[schema.nodes.keywords_section, ObjectTypes.Section],
|
|
41
|
+
[schema.nodes.keywords_group, ObjectTypes.KeywordGroup],
|
|
41
42
|
[schema.nodes.listing, ObjectTypes.Listing],
|
|
42
43
|
[schema.nodes.listing_element, ObjectTypes.ListingElement],
|
|
43
44
|
[schema.nodes.manuscript, ObjectTypes.Manuscript],
|
|
@@ -50,3 +50,4 @@ export const isManuscript = hasObjectType(ObjectTypes.Manuscript);
|
|
|
50
50
|
export const isTable = hasObjectType(ObjectTypes.Table);
|
|
51
51
|
export const isUserProfile = hasObjectType(ObjectTypes.UserProfile);
|
|
52
52
|
export const isCommentAnnotation = hasObjectType(ObjectTypes.CommentAnnotation);
|
|
53
|
+
export const isKeyword = hasObjectType(ObjectTypes.Keyword);
|
|
@@ -28,4 +28,5 @@ export declare const jatsBodyTransformations: {
|
|
|
28
28
|
moveTableFooterToEnd(body: Element): void;
|
|
29
29
|
moveFloatsGroupToBody(doc: Document, body: Element, createElement: (tagName: string) => HTMLElement): void;
|
|
30
30
|
moveBlockNodesFromParagraph(doc: Document, body: Element, createElement: (tagName: string) => HTMLElement): void;
|
|
31
|
+
moveKeywordsToBody(document: Document, body: Element, createElement: (tagName: string) => HTMLElement): void;
|
|
31
32
|
};
|
|
@@ -13,8 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import { Journal
|
|
17
|
-
import { Build } from '../../transformer/builders';
|
|
16
|
+
import { Journal } from '@manuscripts/json-schema';
|
|
18
17
|
export declare const jatsFrontParser: {
|
|
19
18
|
parseCounts(counts: Element | null | undefined): {
|
|
20
19
|
wordCount: number | undefined;
|
|
@@ -28,10 +27,6 @@ export declare const jatsFrontParser: {
|
|
|
28
27
|
}[] | undefined;
|
|
29
28
|
} | undefined;
|
|
30
29
|
parseJournal(journalMeta: Element | null): Partial<Journal>;
|
|
31
|
-
parseKeywords(keywordGroupNodes?: NodeListOf<Element> | null): {
|
|
32
|
-
groups: Build<KeywordGroup>[];
|
|
33
|
-
keywords: Build<Keyword>[];
|
|
34
|
-
};
|
|
35
30
|
parseDates(historyNode: Element | null): {
|
|
36
31
|
acceptanceDate?: number | undefined;
|
|
37
32
|
correctionDate?: number | undefined;
|
|
@@ -40,18 +35,18 @@ export declare const jatsFrontParser: {
|
|
|
40
35
|
revisionReceiveDate?: number | undefined;
|
|
41
36
|
receiveDate?: number | undefined;
|
|
42
37
|
} | undefined;
|
|
43
|
-
parseSupplements(supplementNodes: Element[] | null): Build<import("@manuscripts/json-schema").Supplement>[];
|
|
38
|
+
parseSupplements(supplementNodes: Element[] | null): import("../../transformer/builders").Build<import("@manuscripts/json-schema").Supplement>[];
|
|
44
39
|
parseAffiliationNodes(affiliationNodes: Element[]): {
|
|
45
|
-
affiliations: Build<import("@manuscripts/json-schema").Affiliation>[];
|
|
40
|
+
affiliations: import("../../transformer/builders").Build<import("@manuscripts/json-schema").Affiliation>[];
|
|
46
41
|
affiliationIDs: Map<string, string>;
|
|
47
42
|
};
|
|
48
43
|
parseFootnoteNodes(footnoteNodes: Element[]): {
|
|
49
|
-
footnotes: Build<import("@manuscripts/json-schema").Footnote>[];
|
|
44
|
+
footnotes: import("../../transformer/builders").Build<import("@manuscripts/json-schema").Footnote>[];
|
|
50
45
|
footnoteIDs: Map<string, string>;
|
|
51
46
|
};
|
|
52
47
|
parseCorrespNodes(correspNodes: Element[]): {
|
|
53
|
-
correspondingList: Build<import("@manuscripts/json-schema").Corresponding>[];
|
|
48
|
+
correspondingList: import("../../transformer/builders").Build<import("@manuscripts/json-schema").Corresponding>[];
|
|
54
49
|
correspondingIDs: Map<string, string>;
|
|
55
50
|
};
|
|
56
|
-
parseAuthorNodes(authorNodes: Element[], affiliationIDs: Map<string, string>, footnoteIDs: Map<string, string>, correspondingIDs: Map<string, string>): Build<import("@manuscripts/json-schema").Contributor>[];
|
|
51
|
+
parseAuthorNodes(authorNodes: Element[], affiliationIDs: Map<string, string>, footnoteIDs: Map<string, string>, correspondingIDs: Map<string, string>): import("../../transformer/builders").Build<import("@manuscripts/json-schema").Contributor>[];
|
|
57
52
|
};
|
|
@@ -18,6 +18,7 @@ import { ManuscriptEditorState, ManuscriptNode } from '../schema';
|
|
|
18
18
|
export declare function iterateChildren(node: ManuscriptNode, recurse?: boolean): Iterable<ManuscriptNode>;
|
|
19
19
|
export declare const findNodePositions: (state: ManuscriptEditorState, predicate: (node: ManuscriptNode) => boolean) => number[];
|
|
20
20
|
export declare const isInGraphicalAbstractSection: ($pos: ResolvedPos) => boolean;
|
|
21
|
+
export declare const isInBibliographySection: ($pos: ResolvedPos) => boolean;
|
|
21
22
|
export declare const findParentNodeClosestToPos: ($pos: ResolvedPos, predicate: (node: ProsemirrorNode) => boolean) => {
|
|
22
23
|
pos: number;
|
|
23
24
|
start: number;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* © 2019 Atypon Systems LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { NodeSpec } from 'prosemirror-model';
|
|
17
|
+
import { ManuscriptNode } from '../types';
|
|
18
|
+
interface Attrs {
|
|
19
|
+
id: string;
|
|
20
|
+
}
|
|
21
|
+
export interface KeywordsGroupNode extends ManuscriptNode {
|
|
22
|
+
attrs: Attrs;
|
|
23
|
+
}
|
|
24
|
+
export declare const keywordsGroup: NodeSpec;
|
|
25
|
+
export declare const isKeywordsGroupNode: (node: ManuscriptNode) => node is KeywordsGroupNode;
|
|
26
|
+
export {};
|
|
@@ -17,7 +17,7 @@ import { Fragment, Mark as ProsemirrorMark, MarkType, Node as ProsemirrorNode, N
|
|
|
17
17
|
import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from 'prosemirror-state';
|
|
18
18
|
import { EditorView, NodeView } from 'prosemirror-view';
|
|
19
19
|
export type Marks = 'bold' | 'code' | 'italic' | 'smallcaps' | 'strikethrough' | 'styled' | 'subscript' | 'superscript' | 'underline' | 'tracked_insert' | 'tracked_delete';
|
|
20
|
-
export type Nodes = 'attribution' | 'bibliography_item' | 'bibliography_element' | 'bibliography_section' | 'blockquote_element' | 'bullet_list' | 'caption' | 'caption_title' | 'comment' | 'comment_list' | 'citation' | 'cross_reference' | 'doc' | 'equation' | 'equation_element' | 'figcaption' | 'figure' | 'graphical_abstract_section' | 'figure_element' | 'footnote' | 'footnotes_element' | 'footnotes_section' | 'hard_break' | 'highlight_marker' | 'inline_equation' | 'inline_footnote' | 'keyword' | 'keywords_element' | 'keywords_section' | 'link' | 'list_item' | 'listing' | 'listing_element' | 'manuscript' | 'missing_figure' | 'ordered_list' | 'paragraph' | 'placeholder' | 'placeholder_element' | 'pullquote_element' | 'section' | 'section_label' | 'section_title' | 'section_title_plain' | 'table' | 'table_body' | 'table_cell' | 'table_element' | 'table_row' | 'table_colgroup' | 'table_col' | 'text' | 'toc_element' | 'toc_section';
|
|
20
|
+
export type Nodes = 'attribution' | 'bibliography_item' | 'bibliography_element' | 'bibliography_section' | 'blockquote_element' | 'bullet_list' | 'caption' | 'caption_title' | 'comment' | 'comment_list' | 'citation' | 'cross_reference' | 'doc' | 'equation' | 'equation_element' | 'figcaption' | 'figure' | 'graphical_abstract_section' | 'figure_element' | 'footnote' | 'footnotes_element' | 'footnotes_section' | 'hard_break' | 'highlight_marker' | 'inline_equation' | 'inline_footnote' | 'keyword' | 'keywords_element' | 'keywords_group' | 'keywords_section' | 'link' | 'list_item' | 'listing' | 'listing_element' | 'manuscript' | 'missing_figure' | 'ordered_list' | 'paragraph' | 'placeholder' | 'placeholder_element' | 'pullquote_element' | 'section' | 'section_label' | 'section_title' | 'section_title_plain' | 'table' | 'table_body' | 'table_cell' | 'table_element' | 'table_row' | 'table_colgroup' | 'table_col' | 'text' | 'toc_element' | 'toc_section';
|
|
21
21
|
export type ManuscriptSchema = Schema<Nodes, Marks>;
|
|
22
22
|
export type ManuscriptEditorState = EditorState;
|
|
23
23
|
export type ManuscriptEditorView = EditorView;
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import { CommentAnnotation, Figure, Manuscript, Model, ObjectTypes, Table } from '@manuscripts/json-schema';
|
|
16
|
+
import { CommentAnnotation, Figure, Keyword, Manuscript, Model, ObjectTypes, Table } from '@manuscripts/json-schema';
|
|
17
17
|
import { ManuscriptModel, UserProfileWithAvatar } from './models';
|
|
18
18
|
export declare enum ExtraObjectTypes {
|
|
19
19
|
PlaceholderElement = "MPPlaceholderElement"
|
|
@@ -27,3 +27,4 @@ export declare const isManuscript: (model: Model) => model is Manuscript;
|
|
|
27
27
|
export declare const isTable: (model: Model) => model is Table;
|
|
28
28
|
export declare const isUserProfile: (model: Model) => model is UserProfileWithAvatar;
|
|
29
29
|
export declare const isCommentAnnotation: (model: Model) => model is CommentAnnotation;
|
|
30
|
+
export declare const isKeyword: (model: Model) => model is Keyword;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@manuscripts/transform",
|
|
3
3
|
"description": "ProseMirror transformer for Manuscripts applications",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.4-LEAN-2066",
|
|
5
5
|
"repository": "github:Atypon-OpenSource/manuscripts-transform",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"main": "dist/cjs",
|