@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.
Files changed (166) hide show
  1. package/CHANGELOG.md +1414 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +5 -0
  4. package/README.md +16 -0
  5. package/examples/cli.js +6 -0
  6. package/ldom.js +6 -0
  7. package/lib/doms.js +30 -0
  8. package/lib/elements/abstract.js +34 -0
  9. package/lib/elements/algorithm.js +78 -0
  10. package/lib/elements/app.js +35 -0
  11. package/lib/elements/article-metadata-json.js +167 -0
  12. package/lib/elements/article-title.js +26 -0
  13. package/lib/elements/article.js +28 -0
  14. package/lib/elements/attrib.js +41 -0
  15. package/lib/elements/bold.js +32 -0
  16. package/lib/elements/book-meta-json.js +134 -0
  17. package/lib/elements/book-meta.js +33 -0
  18. package/lib/elements/book-title.js +26 -0
  19. package/lib/elements/boxed-text.js +31 -0
  20. package/lib/elements/break.js +25 -0
  21. package/lib/elements/caption.js +52 -0
  22. package/lib/elements/compound-kwd.js +27 -0
  23. package/lib/elements/def-item.js +26 -0
  24. package/lib/elements/def-list.js +30 -0
  25. package/lib/elements/def.js +29 -0
  26. package/lib/elements/disp-formula-group.js +30 -0
  27. package/lib/elements/disp-quote.js +33 -0
  28. package/lib/elements/email.js +28 -0
  29. package/lib/elements/ext-link.js +38 -0
  30. package/lib/elements/fig.js +32 -0
  31. package/lib/elements/fn.js +42 -0
  32. package/lib/elements/formula.js +51 -0
  33. package/lib/elements/front.js +64 -0
  34. package/lib/elements/funding-group.js +26 -0
  35. package/lib/elements/graphic.js +49 -0
  36. package/lib/elements/img.js +28 -0
  37. package/lib/elements/italic.js +33 -0
  38. package/lib/elements/kwd-group.js +29 -0
  39. package/lib/elements/kwd.js +26 -0
  40. package/lib/elements/label.js +101 -0
  41. package/lib/elements/line.js +31 -0
  42. package/lib/elements/meta-name.js +29 -0
  43. package/lib/elements/meta-value.js +27 -0
  44. package/lib/elements/mixed-citation.js +35 -0
  45. package/lib/elements/monospace.js +35 -0
  46. package/lib/elements/notes.js +36 -0
  47. package/lib/elements/p.js +29 -0
  48. package/lib/elements/preface.js +33 -0
  49. package/lib/elements/ref-list.js +50 -0
  50. package/lib/elements/ref.js +28 -0
  51. package/lib/elements/roman.js +34 -0
  52. package/lib/elements/sans-serif.js +34 -0
  53. package/lib/elements/sc.js +35 -0
  54. package/lib/elements/sec-meta.js +35 -0
  55. package/lib/elements/sec.js +89 -0
  56. package/lib/elements/secheading.js +43 -0
  57. package/lib/elements/simpletabbing.js +29 -0
  58. package/lib/elements/statement.js +31 -0
  59. package/lib/elements/string-name.js +28 -0
  60. package/lib/elements/styled-content.js +32 -0
  61. package/lib/elements/subj-group.js +29 -0
  62. package/lib/elements/subject.js +26 -0
  63. package/lib/elements/subtitle.js +29 -0
  64. package/lib/elements/table.js +28 -0
  65. package/lib/elements/tag.js +50 -0
  66. package/lib/elements/target.js +39 -0
  67. package/lib/elements/term.js +31 -0
  68. package/lib/elements/tex-math.js +34 -0
  69. package/lib/elements/text.js +29 -0
  70. package/lib/elements/toc-entry.js +63 -0
  71. package/lib/elements/toc.js +35 -0
  72. package/lib/elements/underline.js +26 -0
  73. package/lib/elements/x.js +27 -0
  74. package/lib/elements/xref-group.js +36 -0
  75. package/lib/elements/xref.js +89 -0
  76. package/lib/hacks.js +43 -0
  77. package/lib/head.js +38 -0
  78. package/lib/helpers/copyElement.js +29 -0
  79. package/lib/helpers/extractContribGroups.js +94 -0
  80. package/lib/helpers/generateByline.js +35 -0
  81. package/lib/helpers/getParentLevel.js +24 -0
  82. package/lib/helpers/helpers-tex.js +54 -0
  83. package/lib/helpers/mapAttributes.js +54 -0
  84. package/lib/helpers/mapColorAttributes.js +36 -0
  85. package/lib/helpers/unnest.js +34 -0
  86. package/lib/transformer.js +311 -0
  87. package/out.html +550 -0
  88. package/package.json +39 -0
  89. package/test/article--alttitle.xml +146 -0
  90. package/test/article--nometa.xml +40 -0
  91. package/test/article-alttitle-meta-snapshot.json +94 -0
  92. package/test/article-meta-snapshot.json +129 -0
  93. package/test/article-nometa-meta-snapshot.json +46 -0
  94. package/test/article.xml +593 -0
  95. package/test/attribute-content-type.js +26 -0
  96. package/test/attribute-has-qed-box.js +28 -0
  97. package/test/attribute-hidden.js +27 -0
  98. package/test/attribute-rowspan-colspan.js +27 -0
  99. package/test/attribute-specific-use.js +27 -0
  100. package/test/attribute-style.js +27 -0
  101. package/test/book-meta-snapshot.json +78 -0
  102. package/test/book.xml +292 -0
  103. package/test/copyElement.js +38 -0
  104. package/test/element-abstract-title.js +27 -0
  105. package/test/element-algorithm.js +56 -0
  106. package/test/element-article.js +24 -0
  107. package/test/element-attrib.js +27 -0
  108. package/test/element-back-app-group-app.js +28 -0
  109. package/test/element-bold.js +26 -0
  110. package/test/element-book-meta.js +37 -0
  111. package/test/element-book-preface.js +29 -0
  112. package/test/element-book-ref-list.js +32 -0
  113. package/test/element-book.js +33 -0
  114. package/test/element-boxed-text.js +28 -0
  115. package/test/element-break.js +27 -0
  116. package/test/element-citegroup.js +25 -0
  117. package/test/element-compound-kwd.js +24 -0
  118. package/test/element-def-list-def-item-def-term.js +43 -0
  119. package/test/element-disp-formula-group.js +27 -0
  120. package/test/element-disp-quote.js +31 -0
  121. package/test/element-email.js +26 -0
  122. package/test/element-ext-link.js +30 -0
  123. package/test/element-fig-subfig-label.js +38 -0
  124. package/test/element-fn.js +40 -0
  125. package/test/element-front.js +45 -0
  126. package/test/element-funding-group.js +29 -0
  127. package/test/element-graphic-inline-graphic.js +40 -0
  128. package/test/element-img.js +30 -0
  129. package/test/element-inline-formula-disp-formula-tex-math.js +91 -0
  130. package/test/element-italic.js +28 -0
  131. package/test/element-kwd-group.js +28 -0
  132. package/test/element-kwd.js +27 -0
  133. package/test/element-mixed-citation.js +32 -0
  134. package/test/element-monospace.js +27 -0
  135. package/test/element-notes.js +42 -0
  136. package/test/element-p-p.js +27 -0
  137. package/test/element-ref-list-ref-label.js +40 -0
  138. package/test/element-roman.js +27 -0
  139. package/test/element-sans-serif.js +27 -0
  140. package/test/element-sc.js +27 -0
  141. package/test/element-sec-app-front-matter-part-dedication-title-label.js +87 -0
  142. package/test/element-sec-meta.js +43 -0
  143. package/test/element-secheading.js +28 -0
  144. package/test/element-simpletabbing-line.js +31 -0
  145. package/test/element-statement-label-title.js +120 -0
  146. package/test/element-string-name.js +27 -0
  147. package/test/element-stripEmptyLabel.js +26 -0
  148. package/test/element-styled-content.js +28 -0
  149. package/test/element-subtitle.js +36 -0
  150. package/test/element-table-wrap-group.js +30 -0
  151. package/test/element-table-wrap.js +51 -0
  152. package/test/element-table.js +34 -0
  153. package/test/element-tag.js +38 -0
  154. package/test/element-target.js +33 -0
  155. package/test/element-toc-toc-entry.js +77 -0
  156. package/test/element-underline.js +27 -0
  157. package/test/element-verse-group.js +28 -0
  158. package/test/element-x.js +30 -0
  159. package/test/element-xref-group.js +26 -0
  160. package/test/element-xref.js +32 -0
  161. package/test/hacks.js +37 -0
  162. package/test/helper-mapColorAttributes.js +27 -0
  163. package/test/helper.js +26 -0
  164. package/test/setHead.js +32 -0
  165. package/test/unit/abstract.js +35 -0
  166. 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
+ }