@amermathsoc/texml-to-html 15.0.0
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/CHANGELOG.md +1414 -0
- package/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.md +16 -0
- package/examples/cli.js +6 -0
- package/ldom.js +6 -0
- package/lib/doms.js +30 -0
- package/lib/elements/abstract.js +34 -0
- package/lib/elements/algorithm.js +78 -0
- package/lib/elements/app.js +35 -0
- package/lib/elements/article-metadata-json.js +167 -0
- package/lib/elements/article-title.js +26 -0
- package/lib/elements/article.js +28 -0
- package/lib/elements/attrib.js +41 -0
- package/lib/elements/bold.js +32 -0
- package/lib/elements/book-meta-json.js +134 -0
- package/lib/elements/book-meta.js +33 -0
- package/lib/elements/book-title.js +26 -0
- package/lib/elements/boxed-text.js +31 -0
- package/lib/elements/break.js +25 -0
- package/lib/elements/caption.js +52 -0
- package/lib/elements/compound-kwd.js +27 -0
- package/lib/elements/def-item.js +26 -0
- package/lib/elements/def-list.js +30 -0
- package/lib/elements/def.js +29 -0
- package/lib/elements/disp-formula-group.js +30 -0
- package/lib/elements/disp-quote.js +33 -0
- package/lib/elements/email.js +28 -0
- package/lib/elements/ext-link.js +38 -0
- package/lib/elements/fig.js +32 -0
- package/lib/elements/fn.js +42 -0
- package/lib/elements/formula.js +51 -0
- package/lib/elements/front.js +64 -0
- package/lib/elements/funding-group.js +26 -0
- package/lib/elements/graphic.js +49 -0
- package/lib/elements/img.js +28 -0
- package/lib/elements/italic.js +33 -0
- package/lib/elements/kwd-group.js +29 -0
- package/lib/elements/kwd.js +26 -0
- package/lib/elements/label.js +101 -0
- package/lib/elements/line.js +31 -0
- package/lib/elements/meta-name.js +29 -0
- package/lib/elements/meta-value.js +27 -0
- package/lib/elements/mixed-citation.js +35 -0
- package/lib/elements/monospace.js +35 -0
- package/lib/elements/notes.js +36 -0
- package/lib/elements/p.js +29 -0
- package/lib/elements/preface.js +33 -0
- package/lib/elements/ref-list.js +50 -0
- package/lib/elements/ref.js +28 -0
- package/lib/elements/roman.js +34 -0
- package/lib/elements/sans-serif.js +34 -0
- package/lib/elements/sc.js +35 -0
- package/lib/elements/sec-meta.js +35 -0
- package/lib/elements/sec.js +89 -0
- package/lib/elements/secheading.js +43 -0
- package/lib/elements/simpletabbing.js +29 -0
- package/lib/elements/statement.js +31 -0
- package/lib/elements/string-name.js +28 -0
- package/lib/elements/styled-content.js +32 -0
- package/lib/elements/subj-group.js +29 -0
- package/lib/elements/subject.js +26 -0
- package/lib/elements/subtitle.js +29 -0
- package/lib/elements/table.js +28 -0
- package/lib/elements/tag.js +50 -0
- package/lib/elements/target.js +39 -0
- package/lib/elements/term.js +31 -0
- package/lib/elements/tex-math.js +34 -0
- package/lib/elements/text.js +29 -0
- package/lib/elements/toc-entry.js +63 -0
- package/lib/elements/toc.js +35 -0
- package/lib/elements/underline.js +26 -0
- package/lib/elements/x.js +27 -0
- package/lib/elements/xref-group.js +36 -0
- package/lib/elements/xref.js +89 -0
- package/lib/hacks.js +43 -0
- package/lib/head.js +38 -0
- package/lib/helpers/copyElement.js +29 -0
- package/lib/helpers/extractContribGroups.js +94 -0
- package/lib/helpers/generateByline.js +35 -0
- package/lib/helpers/getParentLevel.js +24 -0
- package/lib/helpers/helpers-tex.js +54 -0
- package/lib/helpers/mapAttributes.js +54 -0
- package/lib/helpers/mapColorAttributes.js +36 -0
- package/lib/helpers/unnest.js +34 -0
- package/lib/transformer.js +311 -0
- package/out.html +550 -0
- package/package.json +39 -0
- package/test/article--alttitle.xml +146 -0
- package/test/article--nometa.xml +40 -0
- package/test/article-alttitle-meta-snapshot.json +94 -0
- package/test/article-meta-snapshot.json +129 -0
- package/test/article-nometa-meta-snapshot.json +46 -0
- package/test/article.xml +593 -0
- package/test/attribute-content-type.js +26 -0
- package/test/attribute-has-qed-box.js +28 -0
- package/test/attribute-hidden.js +27 -0
- package/test/attribute-rowspan-colspan.js +27 -0
- package/test/attribute-specific-use.js +27 -0
- package/test/attribute-style.js +27 -0
- package/test/book-meta-snapshot.json +78 -0
- package/test/book.xml +292 -0
- package/test/copyElement.js +38 -0
- package/test/element-abstract-title.js +27 -0
- package/test/element-algorithm.js +56 -0
- package/test/element-article.js +24 -0
- package/test/element-attrib.js +27 -0
- package/test/element-back-app-group-app.js +28 -0
- package/test/element-bold.js +26 -0
- package/test/element-book-meta.js +37 -0
- package/test/element-book-preface.js +29 -0
- package/test/element-book-ref-list.js +32 -0
- package/test/element-book.js +33 -0
- package/test/element-boxed-text.js +28 -0
- package/test/element-break.js +27 -0
- package/test/element-citegroup.js +25 -0
- package/test/element-compound-kwd.js +24 -0
- package/test/element-def-list-def-item-def-term.js +43 -0
- package/test/element-disp-formula-group.js +27 -0
- package/test/element-disp-quote.js +31 -0
- package/test/element-email.js +26 -0
- package/test/element-ext-link.js +30 -0
- package/test/element-fig-subfig-label.js +38 -0
- package/test/element-fn.js +40 -0
- package/test/element-front.js +45 -0
- package/test/element-funding-group.js +29 -0
- package/test/element-graphic-inline-graphic.js +40 -0
- package/test/element-img.js +30 -0
- package/test/element-inline-formula-disp-formula-tex-math.js +91 -0
- package/test/element-italic.js +28 -0
- package/test/element-kwd-group.js +28 -0
- package/test/element-kwd.js +27 -0
- package/test/element-mixed-citation.js +32 -0
- package/test/element-monospace.js +27 -0
- package/test/element-notes.js +42 -0
- package/test/element-p-p.js +27 -0
- package/test/element-ref-list-ref-label.js +40 -0
- package/test/element-roman.js +27 -0
- package/test/element-sans-serif.js +27 -0
- package/test/element-sc.js +27 -0
- package/test/element-sec-app-front-matter-part-dedication-title-label.js +87 -0
- package/test/element-sec-meta.js +43 -0
- package/test/element-secheading.js +28 -0
- package/test/element-simpletabbing-line.js +31 -0
- package/test/element-statement-label-title.js +120 -0
- package/test/element-string-name.js +27 -0
- package/test/element-stripEmptyLabel.js +26 -0
- package/test/element-styled-content.js +28 -0
- package/test/element-subtitle.js +36 -0
- package/test/element-table-wrap-group.js +30 -0
- package/test/element-table-wrap.js +51 -0
- package/test/element-table.js +34 -0
- package/test/element-tag.js +38 -0
- package/test/element-target.js +33 -0
- package/test/element-toc-toc-entry.js +77 -0
- package/test/element-underline.js +27 -0
- package/test/element-verse-group.js +28 -0
- package/test/element-x.js +30 -0
- package/test/element-xref-group.js +26 -0
- package/test/element-xref.js +32 -0
- package/test/hacks.js +37 -0
- package/test/helper-mapColorAttributes.js +27 -0
- package/test/helper.js +26 -0
- package/test/setHead.js +32 -0
- package/test/unit/abstract.js +35 -0
- package/texml-to-html.js +32 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2023 American Mathematical Society
|
|
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
|
+
|
|
17
|
+
/**
|
|
18
|
+
*
|
|
19
|
+
* @param {node} contrib - contrib element node
|
|
20
|
+
* @returns {String}
|
|
21
|
+
*/
|
|
22
|
+
const extractContribName = (contrib) => {
|
|
23
|
+
let fullName = ''
|
|
24
|
+
// NAME
|
|
25
|
+
const maybeGivenNames = contrib.querySelector('name>given-names');
|
|
26
|
+
const maybeSurname = contrib.querySelector('name>surname');
|
|
27
|
+
const maybeSuffix = contrib.querySelector('name > suffix');
|
|
28
|
+
const maybeStringname = contrib.querySelector('string-name');
|
|
29
|
+
// NOTE we prefer stringname, cf. AmerMathSoc/texml#69
|
|
30
|
+
if (maybeStringname) {
|
|
31
|
+
fullName = maybeStringname.textContent;
|
|
32
|
+
}
|
|
33
|
+
else if (maybeSurname) { // NOTE: given-names are optional
|
|
34
|
+
fullName = `${maybeGivenNames ? maybeGivenNames?.textContent + '\u00A0' : ''}${maybeSurname.textContent}`;
|
|
35
|
+
}
|
|
36
|
+
if (maybeSuffix) fullName = fullName + (maybeSuffix.textContent[0] === ',' ? '' : '\u00A0') + maybeSuffix.textContent;
|
|
37
|
+
return fullName;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
*
|
|
42
|
+
* @param {Node} articleMetaNode - a node with contrib-group descendants
|
|
43
|
+
* @returns {Object}
|
|
44
|
+
*/
|
|
45
|
+
export function extractContribGroups(articleMetaNode) {
|
|
46
|
+
|
|
47
|
+
// TODO: move out of scope // fix `this`
|
|
48
|
+
const extractContribAffiliation = (contrib, xref) => {
|
|
49
|
+
const aff = contrib.ownerDocument.querySelector(`#${xref.getAttribute('rid')}`);
|
|
50
|
+
let prefix = '';
|
|
51
|
+
if (aff.getAttribute('specific-use') === 'current') prefix = '<span>Address at time of publication:</span> '; //NOTE: whitespace at end is intentional.
|
|
52
|
+
return prefix + this.passthroughIntoHTMLString(aff);
|
|
53
|
+
}
|
|
54
|
+
const extractContribAffiliations = (contrib) => {
|
|
55
|
+
return [...contrib
|
|
56
|
+
.querySelectorAll('xref[ref-type="aff"]')].map(extractContribAffiliation.bind(null, contrib))
|
|
57
|
+
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const extractContrib = function (contributorsArray, contrib, index) {
|
|
61
|
+
const contributor = {};
|
|
62
|
+
|
|
63
|
+
contributor.name = extractContribName(contrib);
|
|
64
|
+
contributor.bio = this.passthroughIntoHTMLString(contrib.querySelector('bio'));
|
|
65
|
+
|
|
66
|
+
// AFFs
|
|
67
|
+
contributor.affiliations = extractContribAffiliations(contrib);
|
|
68
|
+
// EMAILS
|
|
69
|
+
|
|
70
|
+
const emailChildren = contrib.querySelectorAll(':scope>email');
|
|
71
|
+
// NOTE: specific-use="current" is not used downstream
|
|
72
|
+
contributor.emails = emailChildren.map(email => email.textContent);
|
|
73
|
+
|
|
74
|
+
contributor.mrauth = contrib.querySelector('contrib-id[contrib-id-type="mrauth"]')?.textContent;
|
|
75
|
+
contributor.orcid = contrib.querySelector('contrib-id[contrib-id-type="orcid"]')?.textContent;
|
|
76
|
+
|
|
77
|
+
contributor.uri = contrib.querySelector('uri')?.textContent;
|
|
78
|
+
// author-comment (NOTE: child of contrib-group but it's easier if we copy it to each contributor)
|
|
79
|
+
const authorComment = contrib.parentNode.querySelector('author-comment')?.textContent;
|
|
80
|
+
if (index === 0 && authorComment) contributor.byline = authorComment;
|
|
81
|
+
contributorsArray.push(contributor);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const extractContribGroup = function (contributors, contribGroup) {
|
|
85
|
+
contributors[contribGroup.getAttribute('content-type')] ??= []; // NOTE: jams410 has 2 contrib-groups with content-type=contributors (but different author-comments); cf. #408
|
|
86
|
+
contribGroup.querySelectorAll('contrib').forEach(extractContrib.bind(this, contributors[contribGroup.getAttribute('content-type')]));
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
let contributors = {};
|
|
92
|
+
articleMetaNode.querySelectorAll('contrib-group').forEach(extractContribGroup.bind(this, contributors));
|
|
93
|
+
return contributors;
|
|
94
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2023 American Mathematical Society
|
|
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
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Turn author metadata into parts of a sentence.
|
|
19
|
+
* @param {Object} contributors - contributors metadata object (from article- or section-metadata)
|
|
20
|
+
* @returns {String}
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const createPartialByline = (contributors) => {
|
|
24
|
+
const formatter = new Intl.ListFormat('en', { style: 'long', type: 'conjunction' });
|
|
25
|
+
return formatter.format(Object.values(contributors).map(contributor => `${contributor.byline ? contributor.byline + ' ' : ''}${contributor.name}`));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Generates Byline from contributor information.
|
|
31
|
+
* NOTE: tested via article-metadata-json.js and sec-meta.js
|
|
32
|
+
* @param {Object} contributors
|
|
33
|
+
* @returns {String}
|
|
34
|
+
*/
|
|
35
|
+
export const generateByline = (contributors) => Object.values(contributors).map(contributorGroup => createPartialByline(contributorGroup)).join(', ');
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2023 American Mathematical Society
|
|
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
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get parent level.
|
|
19
|
+
* @param {HTMLElement} htmlParentNode
|
|
20
|
+
*/
|
|
21
|
+
const getParentLevel = htmlParentNode =>
|
|
22
|
+
parseInt(htmlParentNode.getAttribute('data-ams-doc-level'));
|
|
23
|
+
|
|
24
|
+
export default getParentLevel;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2023 American Mathematical Society
|
|
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
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Re-escape active TeX characters inside text node (since we create TeX input for mathjax from <text> elements)
|
|
19
|
+
* @param {Text} textNode
|
|
20
|
+
*/
|
|
21
|
+
const replaceTeXCharactersInNode = textNode => {
|
|
22
|
+
const regExp = /([#$_&])/g;
|
|
23
|
+
textNode.textContent = textNode.textContent.replace(regExp, '\\$1').replace('~','\\unicode{x7E}');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Runs replaceTeXCharactersInNode on all text node (direct) children
|
|
28
|
+
* @param {Node} xmlnode
|
|
29
|
+
*/
|
|
30
|
+
export const replaceTeXCharactersInNodes = (xmlnode) => {
|
|
31
|
+
const textChildren = [...xmlnode.childNodes].filter(node => node.nodeType === 3);
|
|
32
|
+
textChildren.forEach(replaceTeXCharactersInNode)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Common pattern for handling most xml nodes when inside tex-math:
|
|
38
|
+
* - create provided TeX macro
|
|
39
|
+
* - maybe replaces active characters in xmlnode
|
|
40
|
+
* - maybe wraps in $...$
|
|
41
|
+
* - runs pass through
|
|
42
|
+
* @param {HTMLElement} htmlParentNode - html container for resulting output
|
|
43
|
+
* @param {Node} xmlnode - an xml node inside tex-math
|
|
44
|
+
* @param {String} macroName - name of TeX macro
|
|
45
|
+
* @param {Boolean} needsEscaping - decide if active TeX characters need escaping
|
|
46
|
+
* @param {Boolean} needsDollars - decide if active TeX characters need escaping
|
|
47
|
+
*/
|
|
48
|
+
export function node2macro(htmlParentNode, xmlnode, macroName, needsEscaping, needsDollars) {
|
|
49
|
+
const maybeDollar = needsDollars ? '$' : '';
|
|
50
|
+
htmlParentNode.insertAdjacentText('beforeend', `${maybeDollar}\\${macroName}{`);
|
|
51
|
+
if (needsEscaping) replaceTeXCharactersInNodes(xmlnode);
|
|
52
|
+
this.passThrough(htmlParentNode, xmlnode);
|
|
53
|
+
htmlParentNode.insertAdjacentText('beforeend', `}${maybeDollar}`);
|
|
54
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2023 American Mathematical Society
|
|
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
|
+
|
|
17
|
+
const attributeDictionary = {
|
|
18
|
+
class: 'class', // NOTE should only appear on table elements
|
|
19
|
+
id: 'id',
|
|
20
|
+
rowspan: 'rowspan',
|
|
21
|
+
colspan: 'colspan',
|
|
22
|
+
'content-type': 'data-ams-content-type',
|
|
23
|
+
'has-qed-box': 'data-ams-qed-box',
|
|
24
|
+
hidden: 'hidden',
|
|
25
|
+
style: 'data-ams-style',
|
|
26
|
+
'specific-use': 'data-ams-specific-use' // NOTE generic fallback; elementProcessors who do something different should remove the attribute from the xmlnode before calling mapAttributes
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Map attribute from XML to HTML element.
|
|
31
|
+
* @param {HTMLElement} htmlParentNode
|
|
32
|
+
* @param {Element} xmlnode
|
|
33
|
+
* @param {String} attributeName
|
|
34
|
+
* @returns {undefined}
|
|
35
|
+
*/
|
|
36
|
+
const mapAttribute = (htmlNode, xmlNode, attributeName) => {
|
|
37
|
+
const attributeValue = xmlNode.getAttribute(attributeName);
|
|
38
|
+
if (!attributeValue) return;
|
|
39
|
+
htmlNode.setAttribute(attributeDictionary[attributeName], attributeValue);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Map admissible attributes from XML to HTML element.
|
|
44
|
+
* @param {HTMLElement} htmlNode
|
|
45
|
+
* @param {Element} xmlNode
|
|
46
|
+
* @returns {undefined}
|
|
47
|
+
*/
|
|
48
|
+
const mapAttributes = (htmlNode, xmlNode) => {
|
|
49
|
+
Object.keys(attributeDictionary).forEach(
|
|
50
|
+
mapAttribute.bind(null, htmlNode, xmlNode)
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export default mapAttributes;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2023 American Mathematical Society
|
|
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
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Maps color attributes on XML element to (combined) style declaration on HTML element
|
|
19
|
+
* @param {HTMLElement} htmlParentNode
|
|
20
|
+
* @param {Element} xmlnode
|
|
21
|
+
*/
|
|
22
|
+
export const mapColorAttributes = (htmlnode, xmlnode) => {
|
|
23
|
+
const colors = [];
|
|
24
|
+
if (xmlnode.hasAttribute('text-color')) colors.push(`color:${xmlnode.getAttribute('text-color')};`);
|
|
25
|
+
if (xmlnode.hasAttribute('background-color')) colors.push(`background-color:${xmlnode.getAttribute('background-color')};`);
|
|
26
|
+
if (xmlnode.hasAttribute('border-color')) {
|
|
27
|
+
colors.push(`border-color:${xmlnode.getAttribute('border-color')};`);
|
|
28
|
+
}
|
|
29
|
+
if (xmlnode.hasAttribute('border-width')) {
|
|
30
|
+
colors.push(`border-width:${xmlnode.getAttribute('border-width')};`);
|
|
31
|
+
}
|
|
32
|
+
if (xmlnode.hasAttribute('border-style')) {
|
|
33
|
+
colors.push(`border-style:${xmlnode.getAttribute('border-style')};`);
|
|
34
|
+
}
|
|
35
|
+
if (colors.length) htmlnode.setAttribute('data-ams-style-color', colors.join(''));
|
|
36
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2023 American Mathematical Society
|
|
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
|
+
|
|
17
|
+
/**
|
|
18
|
+
* moves links into subsequent span
|
|
19
|
+
* @param {Function} recurseTheDom
|
|
20
|
+
* @param {Function} createNode
|
|
21
|
+
* @param {Node} xmlnode XML DOM node
|
|
22
|
+
* @param {Node} htmlnode HTML Dom Node
|
|
23
|
+
* @param {Node} linkChild XML Dom Node, child of xmlnode
|
|
24
|
+
* @returns {Boolean}
|
|
25
|
+
*/
|
|
26
|
+
export const unnestLinks = (recurseTheDom, createNode, xmlnode, htmlnode, linkChild) => {
|
|
27
|
+
const siblings = [...xmlnode.childNodes];
|
|
28
|
+
const precedingSiblings = siblings.slice(0, siblings.indexOf(linkChild));
|
|
29
|
+
const followingSiblings = siblings.slice(siblings.indexOf(linkChild));
|
|
30
|
+
const span = createNode('span');
|
|
31
|
+
htmlnode.insertAdjacentElement('afterend', span);
|
|
32
|
+
precedingSiblings.forEach(recurseTheDom.bind(null, htmlnode));
|
|
33
|
+
followingSiblings.forEach(recurseTheDom.bind(null, span));
|
|
34
|
+
}
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2023 American Mathematical Society
|
|
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
|
+
|
|
17
|
+
import Front from './elements/front.js';
|
|
18
|
+
import Preface from './elements/preface.js';
|
|
19
|
+
import BookMeta from './elements/book-meta.js';
|
|
20
|
+
import BookTitle from './elements/book-title.js';
|
|
21
|
+
import Subtitle from './elements/subtitle.js';
|
|
22
|
+
import Email from './elements/email.js';
|
|
23
|
+
import Xref from './elements/xref.js';
|
|
24
|
+
import X from './elements/x.js';
|
|
25
|
+
import RefList from './elements/ref-list.js';
|
|
26
|
+
import Ref from './elements/ref.js';
|
|
27
|
+
import MixedCitation from './elements/mixed-citation.js';
|
|
28
|
+
import Label from './elements/label.js';
|
|
29
|
+
import StringName from './elements/string-name.js';
|
|
30
|
+
import Article from './elements/article.js';
|
|
31
|
+
import ArticleTitle from './elements/article-title.js';
|
|
32
|
+
import KwdGroup from './elements/kwd-group.js';
|
|
33
|
+
import Kwd from './elements/kwd.js';
|
|
34
|
+
import CompoundKwd from './elements/compound-kwd.js';
|
|
35
|
+
import FundingGroup from './elements/funding-group.js';
|
|
36
|
+
import MetaName from './elements/meta-name.js';
|
|
37
|
+
import MetaValue from './elements/meta-value.js';
|
|
38
|
+
import Notes from './elements/notes.js';
|
|
39
|
+
import Abstract from './elements/abstract.js';
|
|
40
|
+
import Sec from './elements/sec.js';
|
|
41
|
+
import StyledContent from './elements/styled-content.js';
|
|
42
|
+
import Italic from './elements/italic.js';
|
|
43
|
+
import Bold from './elements/bold.js';
|
|
44
|
+
import DispQuote from './elements/disp-quote.js';
|
|
45
|
+
import Attrib from './elements/attrib.js';
|
|
46
|
+
import Fn from './elements/fn.js';
|
|
47
|
+
import P from './elements/p.js';
|
|
48
|
+
import DefList from './elements/def-list.js';
|
|
49
|
+
import DefItem from './elements/def-item.js';
|
|
50
|
+
import Term from './elements/term.js';
|
|
51
|
+
import Def from './elements/def.js';
|
|
52
|
+
import App from './elements/app.js';
|
|
53
|
+
import Statement from './elements/statement.js';
|
|
54
|
+
import SecHeading from './elements/secheading.js';
|
|
55
|
+
import SecMeta from './elements/sec-meta.js';
|
|
56
|
+
import Graphic from './elements/graphic.js';
|
|
57
|
+
import Img from './elements/img.js';
|
|
58
|
+
import Fig from './elements/fig.js';
|
|
59
|
+
import Caption from './elements/caption.js';
|
|
60
|
+
import Toc from './elements/toc.js';
|
|
61
|
+
import TocEntry from './elements/toc-entry.js';
|
|
62
|
+
import Formula from './elements/formula.js';
|
|
63
|
+
import Text from './elements/text.js';
|
|
64
|
+
import ExtLink from './elements/ext-link.js';
|
|
65
|
+
import Break from './elements/break.js';
|
|
66
|
+
import Target from './elements/target.js';
|
|
67
|
+
import BoxedText from './elements/boxed-text.js';
|
|
68
|
+
import Table from './elements/table.js';
|
|
69
|
+
import Underline from './elements/underline.js';
|
|
70
|
+
import DispFormulaGroup from './elements/disp-formula-group.js';
|
|
71
|
+
import SimpleTabbing from './elements/simpletabbing.js';
|
|
72
|
+
import Line from './elements/line.js';
|
|
73
|
+
import SubjGroup from './elements/subj-group.js';
|
|
74
|
+
import Subject from './elements/subject.js';
|
|
75
|
+
import Monospace from './elements/monospace.js';
|
|
76
|
+
import Roman from './elements/roman.js';
|
|
77
|
+
import SansSerif from './elements/sans-serif.js';
|
|
78
|
+
import Sc from './elements/sc.js';
|
|
79
|
+
import * as algorithm from './elements/algorithm.js';
|
|
80
|
+
import Tag from './elements/tag.js';
|
|
81
|
+
import Xrefgroup from './elements/xref-group.js';
|
|
82
|
+
import TexMath from './elements/tex-math.js';
|
|
83
|
+
|
|
84
|
+
import copyElement from './helpers/copyElement.js';
|
|
85
|
+
import { extractContribGroups } from './helpers/extractContribGroups.js';
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The Transformer class
|
|
89
|
+
*/
|
|
90
|
+
export class Transformer {
|
|
91
|
+
/**
|
|
92
|
+
*
|
|
93
|
+
* @param {Document} htmldoc - HTML document
|
|
94
|
+
* @param {Object} imageAltDictionary - Key value store with file names and alt text strings
|
|
95
|
+
* @param {Boolean} isBook - Boolean to indicate if we are transforming a book
|
|
96
|
+
*/
|
|
97
|
+
constructor(htmldoc, imageAltDictionary, isBook) {
|
|
98
|
+
// the HTML document
|
|
99
|
+
this.htmldoc = htmldoc;
|
|
100
|
+
|
|
101
|
+
// the image alt lookup table
|
|
102
|
+
this.imageAltDictionary = imageAltDictionary;
|
|
103
|
+
|
|
104
|
+
// book check
|
|
105
|
+
this.isBook = isBook;
|
|
106
|
+
|
|
107
|
+
// helper mapping elements to existing methods
|
|
108
|
+
const mapTag = (func, newtag) => (this[newtag] = func);
|
|
109
|
+
|
|
110
|
+
// sec-like elements
|
|
111
|
+
['ack', 'front-matter-part', 'dedication', 'book-app-group', 'book-app'].forEach(
|
|
112
|
+
mapTag.bind(null, this['sec'])
|
|
113
|
+
);
|
|
114
|
+
// fig-like elements
|
|
115
|
+
['fig-group', 'verse-group', 'table-wrap', 'table-wrap-group'].forEach(
|
|
116
|
+
mapTag.bind(null, this['fig'])
|
|
117
|
+
);
|
|
118
|
+
// copyable elements
|
|
119
|
+
[
|
|
120
|
+
'sup',
|
|
121
|
+
'sub',
|
|
122
|
+
'tbody',
|
|
123
|
+
'thead',
|
|
124
|
+
'th',
|
|
125
|
+
'tr',
|
|
126
|
+
'td',
|
|
127
|
+
'pre',
|
|
128
|
+
'hr',
|
|
129
|
+
].forEach(mapTag.bind(null, this.copyElement));
|
|
130
|
+
// passThrough elements
|
|
131
|
+
[
|
|
132
|
+
'book',
|
|
133
|
+
'front-matter',
|
|
134
|
+
'book-body',
|
|
135
|
+
'book-back',
|
|
136
|
+
'book-part',
|
|
137
|
+
'named-book-part-body',
|
|
138
|
+
'book-part-meta',
|
|
139
|
+
'body',
|
|
140
|
+
'description',
|
|
141
|
+
'custom-meta-group',
|
|
142
|
+
'custom-meta',
|
|
143
|
+
'permissions',
|
|
144
|
+
'back',
|
|
145
|
+
'alternatives',
|
|
146
|
+
'title-group',
|
|
147
|
+
'cite-group',
|
|
148
|
+
'app-group',
|
|
149
|
+
'book-title-group',
|
|
150
|
+
'private-char',
|
|
151
|
+
].forEach(mapTag.bind(null, this.passThrough));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
*
|
|
156
|
+
* @param {String} tagname - a tag name to create node with
|
|
157
|
+
* @param {String} content - content added to the tag's innerHTML
|
|
158
|
+
* @param {Object} properties - Object of attribute / value keys
|
|
159
|
+
* @returns {HTMLElement} - node with tagname, content and attributes
|
|
160
|
+
*/
|
|
161
|
+
createNode = (tagname, content, properties = {}) => {
|
|
162
|
+
const node = this.htmldoc.createElement(tagname);
|
|
163
|
+
if (content) node.innerHTML = content;
|
|
164
|
+
for (let prop of Object.keys(properties))
|
|
165
|
+
node.setAttribute(prop, properties[prop]);
|
|
166
|
+
return node;
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Main (recursive) step - adds cloned text node or recurses into children
|
|
170
|
+
* @param {Node} htmlParentNode - HTML "parent" for xmlnode content
|
|
171
|
+
* @param {Node} xmlnode - XML node (to possibly recurse into)
|
|
172
|
+
* @returns {undefined}
|
|
173
|
+
*/
|
|
174
|
+
recurseTheDom = (htmlParentNode, xmlnode) => {
|
|
175
|
+
if (!xmlnode) return;
|
|
176
|
+
if (xmlnode.nodeType === 3)
|
|
177
|
+
htmlParentNode.appendChild(this.htmldoc.importNode(xmlnode, false));
|
|
178
|
+
if (xmlnode.nodeType !== 1) return;
|
|
179
|
+
if (this[xmlnode.tagName]) this[xmlnode.tagName](htmlParentNode, xmlnode);
|
|
180
|
+
// else we drop/ignore the node
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Pass-through function (for xmlnode that are we "unwrap")
|
|
185
|
+
* @param {Node} htmlParentNode - HTML "parent" for xmlnode content
|
|
186
|
+
* @param {Node} xmlnode - XML node to unwrap
|
|
187
|
+
* @returns {undefined}
|
|
188
|
+
*/
|
|
189
|
+
passThrough = (htmlParentNode, xmlnode) => {
|
|
190
|
+
if (!xmlnode) return;
|
|
191
|
+
xmlnode.childNodes.forEach(this.recurseTheDom.bind(null, htmlParentNode));
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Pass through hack for metadata generation
|
|
196
|
+
* @param {Node} xmlnode
|
|
197
|
+
* @returns {String}
|
|
198
|
+
*/
|
|
199
|
+
passthroughIntoHTMLString = xmlnode => {
|
|
200
|
+
const span = this.createNode('span');
|
|
201
|
+
this.passThrough(span, xmlnode);
|
|
202
|
+
return span.innerHTML.trim();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// extract contrib-groups into json data
|
|
206
|
+
extractContribGroups = extractContribGroups.bind(this);
|
|
207
|
+
|
|
208
|
+
// copy elements helper
|
|
209
|
+
copyElement = copyElement.bind(this)
|
|
210
|
+
|
|
211
|
+
// imported elements
|
|
212
|
+
front = Front.bind(this)
|
|
213
|
+
preface = Preface.bind(this)
|
|
214
|
+
'book-meta' = BookMeta.bind(this)
|
|
215
|
+
'book-title' = BookTitle.bind(this)
|
|
216
|
+
subtitle = Subtitle.bind(this)
|
|
217
|
+
email = Email.bind(this)
|
|
218
|
+
xref = Xref.bind(this)
|
|
219
|
+
x = X.bind(this)
|
|
220
|
+
'ref-list' = RefList.bind(this)
|
|
221
|
+
ref = Ref.bind(this)
|
|
222
|
+
'mixed-citation' = MixedCitation.bind(this)
|
|
223
|
+
label = Label.bind(this)
|
|
224
|
+
'string-name' = StringName.bind(this)
|
|
225
|
+
article = Article.bind(this)
|
|
226
|
+
'article-title' = ArticleTitle.bind(this)
|
|
227
|
+
'kwd-group' = KwdGroup.bind(this)
|
|
228
|
+
kwd = Kwd.bind(this)
|
|
229
|
+
'compound-kwd' = CompoundKwd.bind(this)
|
|
230
|
+
'funding-group' = FundingGroup.bind(this)
|
|
231
|
+
'meta-name' = MetaName.bind(this)
|
|
232
|
+
'meta-value' = MetaValue.bind(this)
|
|
233
|
+
notes = Notes.bind(this)
|
|
234
|
+
abstract = Abstract.bind(this)
|
|
235
|
+
sec = Sec.bind(this)
|
|
236
|
+
'styled-content' = StyledContent.bind(this)
|
|
237
|
+
italic = Italic.bind(this)
|
|
238
|
+
bold = Bold.bind(this)
|
|
239
|
+
'disp-quote' = DispQuote.bind(this)
|
|
240
|
+
attrib = Attrib.bind(this)
|
|
241
|
+
fn = Fn.bind(this)
|
|
242
|
+
p = P.bind(this)
|
|
243
|
+
'def-list' = DefList.bind(this)
|
|
244
|
+
'def-item' = DefItem.bind(this)
|
|
245
|
+
term = Term.bind(this)
|
|
246
|
+
def = Def.bind(this)
|
|
247
|
+
app = App.bind(this)
|
|
248
|
+
statement = Statement.bind(this)
|
|
249
|
+
secheading = SecHeading.bind(this)
|
|
250
|
+
'sec-meta' = SecMeta.bind(this)
|
|
251
|
+
graphic = Graphic.bind(this)
|
|
252
|
+
img = Img.bind(this)
|
|
253
|
+
fig = Fig.bind(this)
|
|
254
|
+
caption = Caption.bind(this)
|
|
255
|
+
toc = Toc.bind(this)
|
|
256
|
+
'toc-entry' = TocEntry.bind(this)
|
|
257
|
+
'inline-formula' = Formula.bind(this)
|
|
258
|
+
text = Text.bind(this)
|
|
259
|
+
'ext-link' = ExtLink.bind(this)
|
|
260
|
+
break = Break.bind(this)
|
|
261
|
+
target = Target.bind(this)
|
|
262
|
+
'boxed-text' = BoxedText.bind(this)
|
|
263
|
+
table = Table.bind(this)
|
|
264
|
+
underline = Underline.bind(this)
|
|
265
|
+
'disp-formula-group' = DispFormulaGroup.bind(this)
|
|
266
|
+
simpletabbing = SimpleTabbing.bind(this)
|
|
267
|
+
line = Line.bind(this)
|
|
268
|
+
'subj-group' = SubjGroup.bind(this)
|
|
269
|
+
subject = Subject.bind(this)
|
|
270
|
+
monospace = Monospace.bind(this)
|
|
271
|
+
roman = Roman.bind(this)
|
|
272
|
+
'sans-serif' = SansSerif.bind(this)
|
|
273
|
+
sc = Sc.bind(this)
|
|
274
|
+
tag = Tag.bind(this)
|
|
275
|
+
'xref-group' = Xrefgroup.bind(this)
|
|
276
|
+
'tex-math' = TexMath.bind(this)
|
|
277
|
+
|
|
278
|
+
// one-off reuse of imported elements
|
|
279
|
+
// NOTE if RHS gets re-used more than once, use mapTag in the constructor
|
|
280
|
+
'funding-statement' = this['p']
|
|
281
|
+
'inline-graphic' = this['graphic']
|
|
282
|
+
'disp-formula' = this['inline-formula']
|
|
283
|
+
title = this['label']
|
|
284
|
+
|
|
285
|
+
// algorithm layout
|
|
286
|
+
'alg:algorithm' = algorithm.alg;
|
|
287
|
+
'alg:line' = algorithm.algLine;
|
|
288
|
+
'alg:block' = algorithm.algBlock;
|
|
289
|
+
'alg:statement' = algorithm.algStatement;
|
|
290
|
+
'alg:comment' = algorithm.algComment;
|
|
291
|
+
// remapped alg:* elements
|
|
292
|
+
'alg:require' = algorithm.algStatement;
|
|
293
|
+
'alg:ensure' = algorithm.algStatement;
|
|
294
|
+
'alg:globals' = algorithm.algStatement;
|
|
295
|
+
// pass-through alg:* elements
|
|
296
|
+
'alg:body' = this.passThrough; // NOTE no test (case)
|
|
297
|
+
'alg:outputs' = this.passThrough; // NOTE no test (case)
|
|
298
|
+
'alg:inputs' = this.passThrough; // NOTE no test (case)
|
|
299
|
+
'alg:condition' = this.passThrough;
|
|
300
|
+
'alg:if' = this.passThrough;
|
|
301
|
+
'alg:elsif' = this.passThrough; // NOTE no test (case)
|
|
302
|
+
'alg:else' = this.passThrough;
|
|
303
|
+
'alg:for' = this.passThrough;
|
|
304
|
+
'alg:forall' = this.passThrough; // NOTE no test (case)
|
|
305
|
+
'alg:while' = this.passThrough; // NOTE no test (case)
|
|
306
|
+
'alg:repeat' = this.passThrough; // NOTE no test (case)
|
|
307
|
+
'alg:until' = this.passThrough; // NOTE no test (case)
|
|
308
|
+
'alg:loop' = this.passThrough; // NOTE no test (case)
|
|
309
|
+
'alg:function' = this.passThrough;
|
|
310
|
+
'alg:procedure' = this.passThrough;
|
|
311
|
+
}
|