@fiduswriter/document 0.1.0-alpha.2 → 0.1.0-alpha.4
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/README.md +22 -1
- package/dist/bibliography/common.d.ts +92 -0
- package/dist/bibliography/common.d.ts.map +1 -0
- package/dist/bibliography/common.js +85 -0
- package/dist/bibliography/common.js.map +1 -0
- package/dist/bibliography/csl_bib.d.ts +3 -0
- package/dist/bibliography/csl_bib.d.ts.map +1 -0
- package/dist/bibliography/csl_bib.js +131 -0
- package/dist/bibliography/csl_bib.js.map +1 -0
- package/dist/citations/citeproc_sys.d.ts +13 -0
- package/dist/citations/citeproc_sys.d.ts.map +1 -0
- package/dist/citations/citeproc_sys.js +43 -0
- package/dist/citations/citeproc_sys.js.map +1 -0
- package/dist/citations/format.d.ts +23 -0
- package/dist/citations/format.d.ts.map +1 -0
- package/dist/citations/format.js +161 -0
- package/dist/citations/format.js.map +1 -0
- package/dist/editor/e2ee/encryptor.d.ts +123 -0
- package/dist/editor/e2ee/encryptor.d.ts.map +1 -0
- package/dist/editor/e2ee/encryptor.js +201 -0
- package/dist/editor/e2ee/encryptor.js.map +1 -0
- package/dist/exporter/docx/citations.d.ts +21 -0
- package/dist/exporter/docx/citations.d.ts.map +1 -0
- package/dist/exporter/docx/citations.js +154 -0
- package/dist/exporter/docx/citations.js.map +1 -0
- package/dist/exporter/docx/comments.d.ts +18 -0
- package/dist/exporter/docx/comments.d.ts.map +1 -0
- package/dist/exporter/docx/comments.js +137 -0
- package/dist/exporter/docx/comments.js.map +1 -0
- package/dist/exporter/docx/footnotes.d.ts +42 -0
- package/dist/exporter/docx/footnotes.d.ts.map +1 -0
- package/dist/exporter/docx/footnotes.js +182 -0
- package/dist/exporter/docx/footnotes.js.map +1 -0
- package/dist/exporter/docx/images.d.ts +14 -0
- package/dist/exporter/docx/images.d.ts.map +1 -0
- package/dist/exporter/docx/images.js +86 -0
- package/dist/exporter/docx/images.js.map +1 -0
- package/dist/exporter/docx/index.d.ts +22 -0
- package/dist/exporter/docx/index.d.ts.map +1 -0
- package/dist/exporter/docx/index.js +107 -0
- package/dist/exporter/docx/index.js.map +1 -0
- package/dist/exporter/docx/lists.d.ts +33 -0
- package/dist/exporter/docx/lists.d.ts.map +1 -0
- package/dist/exporter/docx/lists.js +229 -0
- package/dist/exporter/docx/lists.js.map +1 -0
- package/dist/exporter/docx/math.d.ts +13 -0
- package/dist/exporter/docx/math.d.ts.map +1 -0
- package/dist/exporter/docx/math.js +42 -0
- package/dist/exporter/docx/math.js.map +1 -0
- package/dist/exporter/docx/metadata.d.ts +14 -0
- package/dist/exporter/docx/metadata.d.ts.map +1 -0
- package/dist/exporter/docx/metadata.js +239 -0
- package/dist/exporter/docx/metadata.js.map +1 -0
- package/dist/exporter/docx/rels.d.ts +25 -0
- package/dist/exporter/docx/rels.d.ts.map +1 -0
- package/dist/exporter/docx/rels.js +168 -0
- package/dist/exporter/docx/rels.js.map +1 -0
- package/dist/exporter/docx/render.d.ts +20 -0
- package/dist/exporter/docx/render.d.ts.map +1 -0
- package/dist/exporter/docx/render.js +774 -0
- package/dist/exporter/docx/render.js.map +1 -0
- package/dist/exporter/docx/richtext.d.ts +25 -0
- package/dist/exporter/docx/richtext.d.ts.map +1 -0
- package/dist/exporter/docx/richtext.js +1052 -0
- package/dist/exporter/docx/richtext.js.map +1 -0
- package/dist/exporter/docx/tables.d.ts +14 -0
- package/dist/exporter/docx/tables.d.ts.map +1 -0
- package/dist/exporter/docx/tables.js +109 -0
- package/dist/exporter/docx/tables.js.map +1 -0
- package/dist/exporter/docx/tools.d.ts +3 -0
- package/dist/exporter/docx/tools.d.ts.map +1 -0
- package/dist/exporter/docx/tools.js +48 -0
- package/dist/exporter/docx/tools.js.map +1 -0
- package/dist/exporter/epub/index.d.ts +11 -0
- package/dist/exporter/epub/index.d.ts.map +1 -0
- package/dist/exporter/epub/index.js +102 -0
- package/dist/exporter/epub/index.js.map +1 -0
- package/dist/exporter/epub/templates.d.ts +32 -0
- package/dist/exporter/epub/templates.d.ts.map +1 -0
- package/dist/exporter/epub/templates.js +95 -0
- package/dist/exporter/epub/templates.js.map +1 -0
- package/dist/exporter/epub/tools.d.ts +5 -0
- package/dist/exporter/epub/tools.d.ts.map +1 -0
- package/dist/exporter/epub/tools.js +81 -0
- package/dist/exporter/epub/tools.js.map +1 -0
- package/dist/exporter/html/citations.d.ts +27 -0
- package/dist/exporter/html/citations.d.ts.map +1 -0
- package/dist/exporter/html/citations.js +91 -0
- package/dist/exporter/html/citations.js.map +1 -0
- package/dist/exporter/html/convert.d.ts +100 -0
- package/dist/exporter/html/convert.d.ts.map +1 -0
- package/dist/exporter/html/convert.js +718 -0
- package/dist/exporter/html/convert.js.map +1 -0
- package/dist/exporter/html/index.d.ts +61 -0
- package/dist/exporter/html/index.d.ts.map +1 -0
- package/dist/exporter/html/index.js +134 -0
- package/dist/exporter/html/index.js.map +1 -0
- package/dist/exporter/html/templates.d.ts +10 -0
- package/dist/exporter/html/templates.d.ts.map +1 -0
- package/dist/exporter/html/templates.js +21 -0
- package/dist/exporter/html/templates.js.map +1 -0
- package/dist/exporter/html/tools.d.ts +2 -0
- package/dist/exporter/html/tools.d.ts.map +1 -0
- package/dist/exporter/html/tools.js +49 -0
- package/dist/exporter/html/tools.js.map +1 -0
- package/dist/exporter/jats/bibliography.d.ts +2 -0
- package/dist/exporter/jats/bibliography.d.ts.map +1 -0
- package/dist/exporter/jats/bibliography.js +153 -0
- package/dist/exporter/jats/bibliography.js.map +1 -0
- package/dist/exporter/jats/citations.d.ts +14 -0
- package/dist/exporter/jats/citations.d.ts.map +1 -0
- package/dist/exporter/jats/citations.js +83 -0
- package/dist/exporter/jats/citations.js.map +1 -0
- package/dist/exporter/jats/convert.d.ts +45 -0
- package/dist/exporter/jats/convert.d.ts.map +1 -0
- package/dist/exporter/jats/convert.js +799 -0
- package/dist/exporter/jats/convert.js.map +1 -0
- package/dist/exporter/jats/index.d.ts +19 -0
- package/dist/exporter/jats/index.d.ts.map +1 -0
- package/dist/exporter/jats/index.js +66 -0
- package/dist/exporter/jats/index.js.map +1 -0
- package/dist/exporter/jats/templates.d.ts +16 -0
- package/dist/exporter/jats/templates.d.ts.map +1 -0
- package/dist/exporter/jats/templates.js +25 -0
- package/dist/exporter/jats/templates.js.map +1 -0
- package/dist/exporter/jats/text.d.ts +3 -0
- package/dist/exporter/jats/text.d.ts.map +1 -0
- package/dist/exporter/jats/text.js +72 -0
- package/dist/exporter/jats/text.js.map +1 -0
- package/dist/exporter/latex/convert.d.ts +27 -0
- package/dist/exporter/latex/convert.d.ts.map +1 -0
- package/dist/exporter/latex/convert.js +865 -0
- package/dist/exporter/latex/convert.js.map +1 -0
- package/dist/exporter/latex/escape_latex.d.ts +2 -0
- package/dist/exporter/latex/escape_latex.d.ts.map +1 -0
- package/dist/exporter/latex/escape_latex.js +20 -0
- package/dist/exporter/latex/escape_latex.js.map +1 -0
- package/dist/exporter/latex/index.d.ts +23 -0
- package/dist/exporter/latex/index.d.ts.map +1 -0
- package/dist/exporter/latex/index.js +57 -0
- package/dist/exporter/latex/index.js.map +1 -0
- package/dist/exporter/latex/readme.d.ts +2 -0
- package/dist/exporter/latex/readme.d.ts.map +1 -0
- package/dist/exporter/latex/readme.js +23 -0
- package/dist/exporter/latex/readme.js.map +1 -0
- package/dist/exporter/native/shrink.d.ts +21 -0
- package/dist/exporter/native/shrink.d.ts.map +1 -0
- package/dist/exporter/native/shrink.js +115 -0
- package/dist/exporter/native/shrink.js.map +1 -0
- package/dist/exporter/odt/citations.d.ts +18 -0
- package/dist/exporter/odt/citations.d.ts.map +1 -0
- package/dist/exporter/odt/citations.js +87 -0
- package/dist/exporter/odt/citations.js.map +1 -0
- package/dist/exporter/odt/footnotes.d.ts +25 -0
- package/dist/exporter/odt/footnotes.d.ts.map +1 -0
- package/dist/exporter/odt/footnotes.js +112 -0
- package/dist/exporter/odt/footnotes.js.map +1 -0
- package/dist/exporter/odt/images.d.ts +13 -0
- package/dist/exporter/odt/images.d.ts.map +1 -0
- package/dist/exporter/odt/images.js +98 -0
- package/dist/exporter/odt/images.js.map +1 -0
- package/dist/exporter/odt/index.d.ts +23 -0
- package/dist/exporter/odt/index.d.ts.map +1 -0
- package/dist/exporter/odt/index.js +99 -0
- package/dist/exporter/odt/index.js.map +1 -0
- package/dist/exporter/odt/math.d.ts +13 -0
- package/dist/exporter/odt/math.d.ts.map +1 -0
- package/dist/exporter/odt/math.js +48 -0
- package/dist/exporter/odt/math.js.map +1 -0
- package/dist/exporter/odt/metadata.d.ts +14 -0
- package/dist/exporter/odt/metadata.d.ts.map +1 -0
- package/dist/exporter/odt/metadata.js +203 -0
- package/dist/exporter/odt/metadata.js.map +1 -0
- package/dist/exporter/odt/render.d.ts +24 -0
- package/dist/exporter/odt/render.d.ts.map +1 -0
- package/dist/exporter/odt/render.js +644 -0
- package/dist/exporter/odt/render.js.map +1 -0
- package/dist/exporter/odt/richtext.d.ts +22 -0
- package/dist/exporter/odt/richtext.d.ts.map +1 -0
- package/dist/exporter/odt/richtext.js +728 -0
- package/dist/exporter/odt/richtext.js.map +1 -0
- package/dist/exporter/odt/styles.d.ts +33 -0
- package/dist/exporter/odt/styles.d.ts.map +1 -0
- package/dist/exporter/odt/styles.js +348 -0
- package/dist/exporter/odt/styles.js.map +1 -0
- package/dist/exporter/odt/track.d.ts +11 -0
- package/dist/exporter/odt/track.d.ts.map +1 -0
- package/dist/exporter/odt/track.js +59 -0
- package/dist/exporter/odt/track.js.map +1 -0
- package/dist/exporter/pandoc/citations.d.ts +17 -0
- package/dist/exporter/pandoc/citations.d.ts.map +1 -0
- package/dist/exporter/pandoc/citations.js +85 -0
- package/dist/exporter/pandoc/citations.js.map +1 -0
- package/dist/exporter/pandoc/convert.d.ts +38 -0
- package/dist/exporter/pandoc/convert.d.ts.map +1 -0
- package/dist/exporter/pandoc/convert.js +881 -0
- package/dist/exporter/pandoc/convert.js.map +1 -0
- package/dist/exporter/pandoc/index.d.ts +38 -0
- package/dist/exporter/pandoc/index.d.ts.map +1 -0
- package/dist/exporter/pandoc/index.js +67 -0
- package/dist/exporter/pandoc/index.js.map +1 -0
- package/dist/exporter/pandoc/readme.d.ts +2 -0
- package/dist/exporter/pandoc/readme.d.ts.map +1 -0
- package/dist/exporter/pandoc/readme.js +9 -0
- package/dist/exporter/pandoc/readme.js.map +1 -0
- package/dist/exporter/pandoc/tools.d.ts +6 -0
- package/dist/exporter/pandoc/tools.d.ts.map +1 -0
- package/dist/exporter/pandoc/tools.js +52 -0
- package/dist/exporter/pandoc/tools.js.map +1 -0
- package/dist/exporter/print/index.d.ts +9 -0
- package/dist/exporter/print/index.d.ts.map +1 -0
- package/dist/exporter/print/index.js +140 -0
- package/dist/exporter/print/index.js.map +1 -0
- package/dist/exporter/tools/doc_content.d.ts +7 -0
- package/dist/exporter/tools/doc_content.d.ts.map +1 -0
- package/dist/exporter/tools/doc_content.js +129 -0
- package/dist/exporter/tools/doc_content.js.map +1 -0
- package/dist/exporter/tools/file.d.ts +2 -0
- package/dist/exporter/tools/file.d.ts.map +1 -0
- package/dist/exporter/tools/file.js +10 -0
- package/dist/exporter/tools/file.js.map +1 -0
- package/dist/exporter/tools/json.d.ts +7 -0
- package/dist/exporter/tools/json.d.ts.map +1 -0
- package/dist/exporter/tools/json.js +82 -0
- package/dist/exporter/tools/json.js.map +1 -0
- package/dist/exporter/tools/svg.d.ts +2 -0
- package/dist/exporter/tools/svg.d.ts.map +1 -0
- package/dist/exporter/tools/svg.js +26 -0
- package/dist/exporter/tools/svg.js.map +1 -0
- package/dist/exporter/tools/xml.d.ts +41 -0
- package/dist/exporter/tools/xml.d.ts.map +1 -0
- package/dist/exporter/tools/xml.js +440 -0
- package/dist/exporter/tools/xml.js.map +1 -0
- package/dist/exporter/tools/xml_zip.d.ts +20 -0
- package/dist/exporter/tools/xml_zip.d.ts.map +1 -0
- package/dist/exporter/tools/xml_zip.js +86 -0
- package/dist/exporter/tools/xml_zip.js.map +1 -0
- package/dist/exporter/tools/zip.d.ts +21 -0
- package/dist/exporter/tools/zip.d.ts.map +1 -0
- package/dist/exporter/tools/zip.js +71 -0
- package/dist/exporter/tools/zip.js.map +1 -0
- package/dist/exporter/tools/zotero_csl.d.ts +10 -0
- package/dist/exporter/tools/zotero_csl.d.ts.map +1 -0
- package/dist/exporter/tools/zotero_csl.js +78 -0
- package/dist/exporter/tools/zotero_csl.js.map +1 -0
- package/dist/importer/citations.d.ts +25 -0
- package/dist/importer/citations.d.ts.map +1 -0
- package/dist/importer/citations.js +116 -0
- package/dist/importer/citations.js.map +1 -0
- package/dist/importer/docx/citations.d.ts +65 -0
- package/dist/importer/docx/citations.d.ts.map +1 -0
- package/dist/importer/docx/citations.js +106 -0
- package/dist/importer/docx/citations.js.map +1 -0
- package/dist/importer/docx/convert.d.ts +228 -0
- package/dist/importer/docx/convert.d.ts.map +1 -0
- package/dist/importer/docx/convert.js +1226 -0
- package/dist/importer/docx/convert.js.map +1 -0
- package/dist/importer/docx/helpers.d.ts +2 -0
- package/dist/importer/docx/helpers.d.ts.map +1 -0
- package/dist/importer/docx/helpers.js +10 -0
- package/dist/importer/docx/helpers.js.map +1 -0
- package/dist/importer/docx/omml2mathml.d.ts +7 -0
- package/dist/importer/docx/omml2mathml.d.ts.map +1 -0
- package/dist/importer/docx/omml2mathml.js +1239 -0
- package/dist/importer/docx/omml2mathml.js.map +1 -0
- package/dist/importer/docx/parse.d.ts +205 -0
- package/dist/importer/docx/parse.d.ts.map +1 -0
- package/dist/importer/docx/parse.js +663 -0
- package/dist/importer/docx/parse.js.map +1 -0
- package/dist/importer/native/get_images.d.ts +11 -0
- package/dist/importer/native/get_images.d.ts.map +1 -0
- package/dist/importer/native/get_images.js +64 -0
- package/dist/importer/native/get_images.js.map +1 -0
- package/dist/importer/native/update.d.ts +6 -0
- package/dist/importer/native/update.d.ts.map +1 -0
- package/dist/importer/native/update.js +26 -0
- package/dist/importer/native/update.js.map +1 -0
- package/dist/importer/odt/citations.d.ts +47 -0
- package/dist/importer/odt/citations.d.ts.map +1 -0
- package/dist/importer/odt/citations.js +79 -0
- package/dist/importer/odt/citations.js.map +1 -0
- package/dist/importer/odt/convert.d.ts +330 -0
- package/dist/importer/odt/convert.d.ts.map +1 -0
- package/dist/importer/odt/convert.js +1506 -0
- package/dist/importer/odt/convert.js.map +1 -0
- package/dist/importer/pandoc/convert.d.ts +84 -0
- package/dist/importer/pandoc/convert.d.ts.map +1 -0
- package/dist/importer/pandoc/convert.js +777 -0
- package/dist/importer/pandoc/convert.js.map +1 -0
- package/dist/importer/pandoc/helpers.d.ts +4 -0
- package/dist/importer/pandoc/helpers.d.ts.map +1 -0
- package/dist/importer/pandoc/helpers.js +75 -0
- package/dist/importer/pandoc/helpers.js.map +1 -0
- package/dist/importer/zip_analyzer.d.ts +25 -0
- package/dist/importer/zip_analyzer.d.ts.map +1 -0
- package/dist/importer/zip_analyzer.js +84 -0
- package/dist/importer/zip_analyzer.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/mathlive/opf_includes.d.ts +2 -0
- package/dist/mathlive/opf_includes.d.ts.map +1 -0
- package/dist/mathlive/opf_includes.js +25 -0
- package/dist/mathlive/opf_includes.js.map +1 -0
- package/dist/schema/common/annotate.d.ts +59 -0
- package/dist/schema/common/annotate.d.ts.map +1 -0
- package/dist/schema/common/annotate.js +75 -0
- package/dist/schema/common/annotate.js.map +1 -0
- package/dist/schema/common/base.d.ts +109 -0
- package/dist/schema/common/base.d.ts.map +1 -0
- package/dist/schema/common/base.js +109 -0
- package/dist/schema/common/base.js.map +1 -0
- package/dist/schema/common/citation.d.ts +29 -0
- package/dist/schema/common/citation.d.ts.map +1 -0
- package/dist/schema/common/citation.js +62 -0
- package/dist/schema/common/citation.js.map +1 -0
- package/dist/schema/common/equation.d.ts +18 -0
- package/dist/schema/common/equation.d.ts.map +1 -0
- package/dist/schema/common/equation.js +32 -0
- package/dist/schema/common/equation.js.map +1 -0
- package/dist/schema/common/figure.d.ts +108 -0
- package/dist/schema/common/figure.d.ts.map +1 -0
- package/dist/schema/common/figure.js +176 -0
- package/dist/schema/common/figure.js.map +1 -0
- package/dist/schema/common/heading.d.ts +33 -0
- package/dist/schema/common/heading.d.ts.map +1 -0
- package/dist/schema/common/heading.js +41 -0
- package/dist/schema/common/heading.js.map +1 -0
- package/dist/schema/common/index.d.ts +11 -0
- package/dist/schema/common/index.d.ts.map +1 -0
- package/dist/schema/common/index.js +11 -0
- package/dist/schema/common/index.js.map +1 -0
- package/dist/schema/common/list.d.ts +83 -0
- package/dist/schema/common/list.d.ts.map +1 -0
- package/dist/schema/common/list.js +92 -0
- package/dist/schema/common/list.js.map +1 -0
- package/dist/schema/common/reference.d.ts +78 -0
- package/dist/schema/common/reference.d.ts.map +1 -0
- package/dist/schema/common/reference.js +97 -0
- package/dist/schema/common/reference.js.map +1 -0
- package/dist/schema/common/table.d.ts +92 -0
- package/dist/schema/common/table.d.ts.map +1 -0
- package/dist/schema/common/table.js +85 -0
- package/dist/schema/common/table.js.map +1 -0
- package/dist/schema/common/track.d.ts +131 -0
- package/dist/schema/common/track.d.ts.map +1 -0
- package/dist/schema/common/track.js +184 -0
- package/dist/schema/common/track.js.map +1 -0
- package/dist/schema/const.d.ts +3 -0
- package/dist/schema/const.d.ts.map +1 -0
- package/{src → dist}/schema/const.js +3 -3
- package/dist/schema/const.js.map +1 -0
- package/dist/schema/convert.d.ts +3 -0
- package/dist/schema/convert.d.ts.map +1 -0
- package/dist/schema/convert.js +1215 -0
- package/dist/schema/convert.js.map +1 -0
- package/dist/schema/document/content.d.ts +137 -0
- package/dist/schema/document/content.d.ts.map +1 -0
- package/dist/schema/document/content.js +177 -0
- package/dist/schema/document/content.js.map +1 -0
- package/dist/schema/document/index.d.ts +879 -0
- package/dist/schema/document/index.d.ts.map +1 -0
- package/dist/schema/document/index.js +68 -0
- package/dist/schema/document/index.js.map +1 -0
- package/dist/schema/document/structure.d.ts +273 -0
- package/dist/schema/document/structure.d.ts.map +1 -0
- package/dist/schema/document/structure.js +445 -0
- package/dist/schema/document/structure.js.map +1 -0
- package/dist/schema/export.d.ts +880 -0
- package/dist/schema/export.d.ts.map +1 -0
- package/dist/schema/export.js +16 -0
- package/dist/schema/export.js.map +1 -0
- package/dist/schema/footnotes.d.ts +499 -0
- package/dist/schema/footnotes.d.ts.map +1 -0
- package/dist/schema/footnotes.js +88 -0
- package/dist/schema/footnotes.js.map +1 -0
- package/dist/schema/footnotes_convert.d.ts +5 -0
- package/dist/schema/footnotes_convert.d.ts.map +1 -0
- package/dist/schema/footnotes_convert.js +26 -0
- package/dist/schema/footnotes_convert.js.map +1 -0
- package/dist/schema/i18n.d.ts +586 -0
- package/dist/schema/i18n.d.ts.map +1 -0
- package/dist/schema/i18n.js +585 -0
- package/dist/schema/i18n.js.map +1 -0
- package/dist/schema/index.d.ts +6 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +6 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/mini_json.d.ts +5 -0
- package/dist/schema/mini_json.d.ts.map +1 -0
- package/dist/schema/mini_json.js +50 -0
- package/dist/schema/mini_json.js.map +1 -0
- package/dist/schema/text.d.ts +2 -0
- package/dist/schema/text.d.ts.map +1 -0
- package/dist/schema/text.js +23 -0
- package/dist/schema/text.js.map +1 -0
- package/dist/types.d.ts +122 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/package.json +48 -16
- package/scripts/export-schema.js +1 -1
- package/src/exporter/tools/{file.js → file.ts} +1 -1
- package/src/exporter/tools/{json.js → json.ts} +30 -19
- package/src/global.d.ts +11 -0
- package/src/schema/const.ts +58 -0
- package/src/types.ts +136 -0
- package/jest.config.js +0 -24
- /package/src/{index.js → index.ts} +0 -0
|
@@ -0,0 +1,1226 @@
|
|
|
1
|
+
import { MathMLToLaTeX } from "mathml-to-latex";
|
|
2
|
+
import { xmlDOM } from "../../exporter/tools/xml.js";
|
|
3
|
+
import { randomCommentId, randomFigureId, randomHeadingId } from "../../schema/common/index.js";
|
|
4
|
+
import { isDocxBibliographyField, isDocxCitationField, isDocxSdtBibliography, isDocxSdtCitation, parseDocxFieldCitation, parseDocxSdtCitation } from "./citations.js";
|
|
5
|
+
import { normalizeText } from "./helpers.js";
|
|
6
|
+
import { omml2mathml } from "./omml2mathml.js";
|
|
7
|
+
import { DocxParser } from "./parse.js";
|
|
8
|
+
export class DocxConvert {
|
|
9
|
+
constructor(zip, importId, template, bibliography) {
|
|
10
|
+
this.zip = zip;
|
|
11
|
+
this.importId = importId;
|
|
12
|
+
this.template = template;
|
|
13
|
+
this.bibliography = bibliography;
|
|
14
|
+
this.images = {};
|
|
15
|
+
this.parser = new DocxParser(zip);
|
|
16
|
+
this.tracks = {};
|
|
17
|
+
this.currentTracks = [];
|
|
18
|
+
this.currentFields = [];
|
|
19
|
+
this.currentCommentIds = [];
|
|
20
|
+
this.sourcesXml = null;
|
|
21
|
+
}
|
|
22
|
+
async init() {
|
|
23
|
+
await this.parser.init();
|
|
24
|
+
// Load Word-native bibliography sources if present.
|
|
25
|
+
// This file is required by DocxCitationsParser for CITATION field codes.
|
|
26
|
+
this.sourcesXml =
|
|
27
|
+
(await this.zip.file("customXml/item1.xml")?.async("string")) ??
|
|
28
|
+
null;
|
|
29
|
+
const body = this.parser.document.query("w:body");
|
|
30
|
+
if (!body) {
|
|
31
|
+
return {
|
|
32
|
+
content: {
|
|
33
|
+
type: "doc",
|
|
34
|
+
content: []
|
|
35
|
+
},
|
|
36
|
+
settings: {
|
|
37
|
+
import_id: this.importId,
|
|
38
|
+
tracked: false,
|
|
39
|
+
language: "en-US"
|
|
40
|
+
},
|
|
41
|
+
comments: {}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// Find all reference targets in the document for cross-references
|
|
45
|
+
this.referenceTargets = this.findReferenceTargets(this.parser.document);
|
|
46
|
+
const convertedContent = this.convertDocument(body);
|
|
47
|
+
// Convert document
|
|
48
|
+
return {
|
|
49
|
+
content: convertedContent,
|
|
50
|
+
settings: {
|
|
51
|
+
import_id: this.importId,
|
|
52
|
+
tracked: this.hasTrackedChanges(this.parser.document),
|
|
53
|
+
language: this.detectLanguage(this.parser.document)
|
|
54
|
+
},
|
|
55
|
+
comments: this.parser.comments
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
convertDocument(body) {
|
|
59
|
+
const templateParts = this.template.content.content.slice();
|
|
60
|
+
templateParts.shift(); // Remove first element
|
|
61
|
+
const document = {
|
|
62
|
+
type: "doc",
|
|
63
|
+
attrs: {
|
|
64
|
+
import_id: this.importId
|
|
65
|
+
},
|
|
66
|
+
content: []
|
|
67
|
+
};
|
|
68
|
+
// Add title (required first element)
|
|
69
|
+
const title = this.extractTitle(body);
|
|
70
|
+
document.content.push({
|
|
71
|
+
type: "title",
|
|
72
|
+
content: title.content || [
|
|
73
|
+
{ type: "text", text: gettext("Untitled") }
|
|
74
|
+
]
|
|
75
|
+
});
|
|
76
|
+
title.containerNodes.forEach(node => {
|
|
77
|
+
node.parentElement.removeChild(node);
|
|
78
|
+
});
|
|
79
|
+
document.attrs.title =
|
|
80
|
+
title.content.map(node => node.textContent).join("") ||
|
|
81
|
+
gettext("Untitled");
|
|
82
|
+
// Extract metadata sections
|
|
83
|
+
const metadata = this.extractMetadata(body);
|
|
84
|
+
metadata.forEach(({ type, content }) => {
|
|
85
|
+
const templatePart = templateParts.find(part => part.attrs.metadata === type);
|
|
86
|
+
const attrs = {};
|
|
87
|
+
if (templatePart.attrs.hidden) {
|
|
88
|
+
attrs.hidden = false;
|
|
89
|
+
}
|
|
90
|
+
if (templatePart) {
|
|
91
|
+
document.content.push({
|
|
92
|
+
type: templatePart.type,
|
|
93
|
+
attrs: {
|
|
94
|
+
...templatePart.attrs,
|
|
95
|
+
...attrs
|
|
96
|
+
},
|
|
97
|
+
content: content.content
|
|
98
|
+
});
|
|
99
|
+
// Remove paragraphs from content so they are not added to body
|
|
100
|
+
content.containerNodes.forEach(node => {
|
|
101
|
+
node.parentElement?.removeChild(node);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
// Extract main content sections
|
|
106
|
+
const sections = this.groupContentIntoSections(body);
|
|
107
|
+
// Map sections to template parts
|
|
108
|
+
sections.forEach(section => {
|
|
109
|
+
const templatePart = this.findMatchingTemplatePart(section.title, templateParts);
|
|
110
|
+
if (templatePart) {
|
|
111
|
+
document.content.push({
|
|
112
|
+
type: "richtext_part",
|
|
113
|
+
attrs: {
|
|
114
|
+
title: templatePart.attrs.title,
|
|
115
|
+
id: templatePart.attrs.id,
|
|
116
|
+
metadata: templatePart.attrs.metadata || undefined,
|
|
117
|
+
marks: templatePart.attrs.marks || [
|
|
118
|
+
"strong",
|
|
119
|
+
"em",
|
|
120
|
+
"link"
|
|
121
|
+
]
|
|
122
|
+
},
|
|
123
|
+
content: section.content
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
// Add remaining content to body section
|
|
128
|
+
const unassignedContent = sections
|
|
129
|
+
.filter(section => !this.findMatchingTemplatePart(section.title, templateParts))
|
|
130
|
+
.flatMap(section => section.content);
|
|
131
|
+
if (unassignedContent.length) {
|
|
132
|
+
const bodyTemplatePart = templateParts.find(part => !part.attrs.metadata && part.type === "richtext_part");
|
|
133
|
+
document.content.push({
|
|
134
|
+
type: "richtext_part",
|
|
135
|
+
attrs: {
|
|
136
|
+
title: bodyTemplatePart
|
|
137
|
+
? bodyTemplatePart.attrs.title
|
|
138
|
+
: "Body",
|
|
139
|
+
id: bodyTemplatePart ? bodyTemplatePart.attrs.id : "body",
|
|
140
|
+
marks: ["strong", "em", "link"]
|
|
141
|
+
},
|
|
142
|
+
content: unassignedContent
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return document;
|
|
146
|
+
}
|
|
147
|
+
extractMetadata(body) {
|
|
148
|
+
const metadata = [];
|
|
149
|
+
// Try structured contributor data from custom properties first
|
|
150
|
+
const contributorsByRole = this.extractContributorsFromCustomProps();
|
|
151
|
+
if (Object.keys(contributorsByRole).length) {
|
|
152
|
+
Object.entries(contributorsByRole).forEach(([role, contributors]) => {
|
|
153
|
+
metadata.push({
|
|
154
|
+
type: role,
|
|
155
|
+
content: { content: contributors, containerNodes: [] }
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
// Fall back to legacy author extraction
|
|
161
|
+
const authors = this.extractAuthors(body);
|
|
162
|
+
if (authors.content.length) {
|
|
163
|
+
metadata.push({
|
|
164
|
+
type: "authors",
|
|
165
|
+
content: authors
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Extract abstract if present
|
|
170
|
+
const abstract = this.extractAbstract(body);
|
|
171
|
+
if (abstract.content.length) {
|
|
172
|
+
metadata.push({
|
|
173
|
+
type: "abstract",
|
|
174
|
+
content: abstract
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
// Extract keywords if present
|
|
178
|
+
const keywords = this.extractKeywords(body);
|
|
179
|
+
if (keywords.content.length) {
|
|
180
|
+
metadata.push({
|
|
181
|
+
type: "keywords",
|
|
182
|
+
content: keywords
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
return metadata;
|
|
186
|
+
}
|
|
187
|
+
extractContributorsFromCustomProps() {
|
|
188
|
+
if (!this.parser.customDoc) {
|
|
189
|
+
return {};
|
|
190
|
+
}
|
|
191
|
+
const properties = this.parser.customDoc.queryAll("property");
|
|
192
|
+
const contributors = [];
|
|
193
|
+
properties.forEach(prop => {
|
|
194
|
+
const name = prop.getAttribute("name");
|
|
195
|
+
if (!name || !name.startsWith("fidus_contributor_")) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const match = name.match(/^fidus_contributor_(\d+)_(\w+)$/);
|
|
199
|
+
if (!match) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const num = parseInt(match[1]);
|
|
203
|
+
const field = match[2];
|
|
204
|
+
const lpwstr = prop.query("vt:lpwstr");
|
|
205
|
+
const value = lpwstr ? lpwstr.textContent : "";
|
|
206
|
+
if (!contributors[num - 1]) {
|
|
207
|
+
contributors[num - 1] = {
|
|
208
|
+
type: "contributor",
|
|
209
|
+
attrs: {
|
|
210
|
+
firstname: "",
|
|
211
|
+
lastname: "",
|
|
212
|
+
email: "",
|
|
213
|
+
institution: "",
|
|
214
|
+
id_type: "",
|
|
215
|
+
id_value: "",
|
|
216
|
+
role: ""
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
if (field === "role") {
|
|
221
|
+
contributors[num - 1].attrs.role = value;
|
|
222
|
+
}
|
|
223
|
+
else if ([
|
|
224
|
+
"firstname",
|
|
225
|
+
"lastname",
|
|
226
|
+
"email",
|
|
227
|
+
"institution",
|
|
228
|
+
"id_type",
|
|
229
|
+
"id_value"
|
|
230
|
+
].includes(field)) {
|
|
231
|
+
contributors[num - 1].attrs[field] = value;
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
const byRole = {};
|
|
235
|
+
contributors.forEach(contributor => {
|
|
236
|
+
if (!contributor) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const role = contributor.attrs.role || "authors";
|
|
240
|
+
if (!byRole[role]) {
|
|
241
|
+
byRole[role] = [];
|
|
242
|
+
}
|
|
243
|
+
byRole[role].push(contributor);
|
|
244
|
+
});
|
|
245
|
+
return byRole;
|
|
246
|
+
}
|
|
247
|
+
extractAuthors(body) {
|
|
248
|
+
const authors = [];
|
|
249
|
+
// Try to find author information in metadata
|
|
250
|
+
const authorNodes = body
|
|
251
|
+
.queryAll("w:pStyle", { "w:val": "Author" })
|
|
252
|
+
.map(pStyle => pStyle.closest("w:p"))
|
|
253
|
+
.filter(p => p);
|
|
254
|
+
authorNodes.forEach(authorNode => {
|
|
255
|
+
const authorText = this.getTextContent(authorNode);
|
|
256
|
+
const [firstname = "", lastname = ""] = authorText.split(" ", 2);
|
|
257
|
+
authors.push({
|
|
258
|
+
type: "contributor",
|
|
259
|
+
attrs: {
|
|
260
|
+
firstname,
|
|
261
|
+
lastname,
|
|
262
|
+
email: "",
|
|
263
|
+
institution: ""
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
if (authors.length) {
|
|
268
|
+
return {
|
|
269
|
+
content: authors,
|
|
270
|
+
containerNodes: authorNodes
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
// Also check Creator in document properties
|
|
274
|
+
const creator = this.parser.coreDoc.query("dc:creator")?.textContent;
|
|
275
|
+
if (creator) {
|
|
276
|
+
const [firstname = "", lastname = ""] = creator.split(" ", 2);
|
|
277
|
+
return {
|
|
278
|
+
content: [
|
|
279
|
+
{
|
|
280
|
+
type: "contributor",
|
|
281
|
+
attrs: {
|
|
282
|
+
firstname,
|
|
283
|
+
lastname,
|
|
284
|
+
email: "",
|
|
285
|
+
institution: ""
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
],
|
|
289
|
+
containerNodes: []
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
return { content: [], containerNodes: [] };
|
|
293
|
+
}
|
|
294
|
+
extractAbstract(body) {
|
|
295
|
+
// Look for section with Abstract style or heading
|
|
296
|
+
const abstractNodes = body
|
|
297
|
+
.queryAll("w:pStyle", { "w:val": "Abstract" })
|
|
298
|
+
.map(pStyle => pStyle.closest("w:p"))
|
|
299
|
+
.filter(p => p);
|
|
300
|
+
if (abstractNodes.length) {
|
|
301
|
+
return {
|
|
302
|
+
content: abstractNodes.map(abstractNode => this.convertBlock(abstractNode)),
|
|
303
|
+
containerNodes: abstractNodes
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
const extractedPart = this.extractPartOnTitle(body, ["Abstract"]);
|
|
307
|
+
if (extractedPart.content.length) {
|
|
308
|
+
return {
|
|
309
|
+
content: extractedPart.content.map(abstractNode => this.convertBlock(abstractNode)),
|
|
310
|
+
containerNodes: extractedPart.content.concat([
|
|
311
|
+
extractedPart.header
|
|
312
|
+
])
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
return { content: [], containerNodes: [] };
|
|
316
|
+
}
|
|
317
|
+
extractKeywords(body) {
|
|
318
|
+
let extraNodes = [];
|
|
319
|
+
// Look for keywords section or metadata
|
|
320
|
+
let keywordNodes = body
|
|
321
|
+
.queryAll("w:pStyle", { "w:val": "Keywords" })
|
|
322
|
+
.map(pStyle => pStyle.closest("w:p"))
|
|
323
|
+
.filter(p => p);
|
|
324
|
+
if (!keywordNodes.length) {
|
|
325
|
+
// If no keywords section is found, look for a title called "Keywords"
|
|
326
|
+
const extractedPart = this.extractPartOnTitle(body, ["Keywords", "Keywords:", "Keyword"], 1);
|
|
327
|
+
if (extractedPart.content.length) {
|
|
328
|
+
keywordNodes = extractedPart.content;
|
|
329
|
+
extraNodes = extractedPart.header ? [extractedPart.header] : [];
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (keywordNodes) {
|
|
333
|
+
return {
|
|
334
|
+
content: keywordNodes
|
|
335
|
+
.map(keywordsNode => this.getTextContent(keywordsNode))
|
|
336
|
+
.flatMap(str => str.split(/[,;|:]+/)) // Split on multiple separators
|
|
337
|
+
.map(keyword => keyword.trim()) // Trim whitespace
|
|
338
|
+
.filter(keyword => keyword.length > 0)
|
|
339
|
+
.map(keyword => ({
|
|
340
|
+
type: "tag",
|
|
341
|
+
attrs: {
|
|
342
|
+
tag: keyword
|
|
343
|
+
}
|
|
344
|
+
})),
|
|
345
|
+
containerNodes: keywordNodes.concat(extraNodes)
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
return { content: [], containerNodes: [] };
|
|
349
|
+
}
|
|
350
|
+
extractPartOnTitle(body, titleWords, maxPars = false) {
|
|
351
|
+
// Fall back to heading starting with TITLEWORD in text
|
|
352
|
+
if (typeof titleWords === "string") {
|
|
353
|
+
titleWords = [titleWords];
|
|
354
|
+
}
|
|
355
|
+
const headingPars = body
|
|
356
|
+
.queryAll("w:pStyle", {
|
|
357
|
+
"w:val": [
|
|
358
|
+
"Heading1",
|
|
359
|
+
"Heading2",
|
|
360
|
+
"Heading3",
|
|
361
|
+
"Heading4",
|
|
362
|
+
"Heading5",
|
|
363
|
+
"Heading6",
|
|
364
|
+
"Heading7",
|
|
365
|
+
"Heading8",
|
|
366
|
+
"Heading9"
|
|
367
|
+
]
|
|
368
|
+
})
|
|
369
|
+
.map(pStyle => pStyle.closest("w:p"))
|
|
370
|
+
.filter(p => p);
|
|
371
|
+
const header = headingPars.find(p => titleWords.includes(this.getTextContent(p).trim()));
|
|
372
|
+
const content = [];
|
|
373
|
+
if (header && header.nextSibling) {
|
|
374
|
+
//const content = []
|
|
375
|
+
//const containerNodes = [sectionHeader]
|
|
376
|
+
const headerLevel = this.getParaStyle(header).level;
|
|
377
|
+
let searchPar = header;
|
|
378
|
+
// Add everything to abstract until next heading with the same or lower level
|
|
379
|
+
while (searchPar.nextSibling &&
|
|
380
|
+
(!maxPars || content.length < maxPars)) {
|
|
381
|
+
searchPar = searchPar.nextSibling;
|
|
382
|
+
const paraStyle = this.getParaStyle(searchPar);
|
|
383
|
+
if (paraStyle.isHeading && paraStyle.level <= headerLevel) {
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
386
|
+
content.push(searchPar);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return { header, content };
|
|
390
|
+
}
|
|
391
|
+
groupContentIntoSections(body) {
|
|
392
|
+
const sections = [];
|
|
393
|
+
let currentSection = {
|
|
394
|
+
title: null,
|
|
395
|
+
content: []
|
|
396
|
+
};
|
|
397
|
+
const skippedBlocks = [];
|
|
398
|
+
body.children.forEach(node => {
|
|
399
|
+
if (skippedBlocks.includes(node)) {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
if (node.tagName !== "w:p") {
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
const style = this.getParaStyle(node);
|
|
406
|
+
const title = this.getSectionTitle(node, style);
|
|
407
|
+
if (title && style.isHeading) {
|
|
408
|
+
if (currentSection.content.length) {
|
|
409
|
+
sections.push(currentSection);
|
|
410
|
+
}
|
|
411
|
+
currentSection = {
|
|
412
|
+
title,
|
|
413
|
+
content: []
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
const block = this.convertBlock(node, skippedBlocks);
|
|
417
|
+
if (block) {
|
|
418
|
+
currentSection.content.push(block);
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
if (currentSection.content.length) {
|
|
422
|
+
sections.push(currentSection);
|
|
423
|
+
}
|
|
424
|
+
return sections;
|
|
425
|
+
}
|
|
426
|
+
getSectionTitle(node, style) {
|
|
427
|
+
if (!node || !style) {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
// For headings, use text content as section title
|
|
431
|
+
if (style.isHeading && style.level <= 4) {
|
|
432
|
+
return this.getTextContent(node);
|
|
433
|
+
}
|
|
434
|
+
// Check style name for section indicators
|
|
435
|
+
if (style.name) {
|
|
436
|
+
const name = style.name.toLowerCase();
|
|
437
|
+
if (name.includes("section") || name.includes("title")) {
|
|
438
|
+
return this.getTextContent(node);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
findMatchingTemplatePart(sectionTitle, templateParts) {
|
|
444
|
+
if (!sectionTitle) {
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
// Try exact match first
|
|
448
|
+
let matchingPart = templateParts.find(part => part.type === "richtext_part" &&
|
|
449
|
+
!part.attrs.metadata &&
|
|
450
|
+
part.attrs.title.toLowerCase() === sectionTitle.toLowerCase());
|
|
451
|
+
if (!matchingPart) {
|
|
452
|
+
// Try fuzzy matching
|
|
453
|
+
matchingPart = templateParts.find(part => part.type === "richtext_part" &&
|
|
454
|
+
!part.attrs.metadata &&
|
|
455
|
+
this.isSimilarTitle(part.attrs.title, sectionTitle));
|
|
456
|
+
}
|
|
457
|
+
return matchingPart;
|
|
458
|
+
}
|
|
459
|
+
isSimilarTitle(title1, title2) {
|
|
460
|
+
const normalized1 = normalizeText(title1);
|
|
461
|
+
const normalized2 = normalizeText(title2);
|
|
462
|
+
return (normalized1.includes(normalized2) ||
|
|
463
|
+
normalized2.includes(normalized1));
|
|
464
|
+
}
|
|
465
|
+
getTextContent(node) {
|
|
466
|
+
return node
|
|
467
|
+
.queryAll("w:t")
|
|
468
|
+
.map(t => t.textContent)
|
|
469
|
+
.join("");
|
|
470
|
+
}
|
|
471
|
+
extractTitle(body) {
|
|
472
|
+
// First try to find paragraph with Title style
|
|
473
|
+
const titlePars = body
|
|
474
|
+
.queryAll("w:pStyle", { "w:val": "Title" })
|
|
475
|
+
.map(pStyle => pStyle.closest("w:p"))
|
|
476
|
+
.filter(p => p);
|
|
477
|
+
if (titlePars.length) {
|
|
478
|
+
return {
|
|
479
|
+
content: this.convertInline(titlePars[0]),
|
|
480
|
+
containerNodes: [titlePars[0]]
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
// Fall back to first heading
|
|
484
|
+
const headingPars = body
|
|
485
|
+
.queryAll("w:pStyle", {
|
|
486
|
+
"w:val": [
|
|
487
|
+
"Heading1",
|
|
488
|
+
"Heading2",
|
|
489
|
+
"Heading3",
|
|
490
|
+
"Heading4",
|
|
491
|
+
"Heading5",
|
|
492
|
+
"Heading6",
|
|
493
|
+
"Heading7",
|
|
494
|
+
"Heading8",
|
|
495
|
+
"Heading9"
|
|
496
|
+
]
|
|
497
|
+
})
|
|
498
|
+
.map(pStyle => pStyle.closest("w:p"))
|
|
499
|
+
.filter(p => p);
|
|
500
|
+
if (headingPars.length) {
|
|
501
|
+
return {
|
|
502
|
+
content: this.convertInline(headingPars[0]),
|
|
503
|
+
containerNodes: [headingPars[0]]
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
return {
|
|
507
|
+
content: [
|
|
508
|
+
{
|
|
509
|
+
type: "text",
|
|
510
|
+
text: gettext("Untitled")
|
|
511
|
+
}
|
|
512
|
+
],
|
|
513
|
+
containerNodes: []
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
inBibliography(node) {
|
|
517
|
+
// Check if we currently are in a field.
|
|
518
|
+
const currentField = this.currentFields[this.currentFields.length - 1];
|
|
519
|
+
if (currentField &&
|
|
520
|
+
isDocxBibliographyField(currentField.instructions)) {
|
|
521
|
+
return true;
|
|
522
|
+
}
|
|
523
|
+
// Check every SDT block inside this paragraph.
|
|
524
|
+
for (const sdt of node.queryAll("w:sdt")) {
|
|
525
|
+
if (isDocxSdtBibliography(sdt)) {
|
|
526
|
+
return true;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return false;
|
|
530
|
+
}
|
|
531
|
+
convertBlock(node, skippedBlocks = []) {
|
|
532
|
+
if (node.tagName !== "w:p") {
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
const inBibliography = this.inBibliography(node);
|
|
536
|
+
let converted;
|
|
537
|
+
const style = this.getParaStyle(node);
|
|
538
|
+
if (style.isHeading) {
|
|
539
|
+
converted = this.convertHeading(node, style);
|
|
540
|
+
}
|
|
541
|
+
else if (style.numbering) {
|
|
542
|
+
converted = this.convertListItem(node, style);
|
|
543
|
+
}
|
|
544
|
+
else if (style.isCaption &&
|
|
545
|
+
(node.query("w:drawing") || node.query("w:pict"))) {
|
|
546
|
+
converted = this.convertFigure(node, node);
|
|
547
|
+
}
|
|
548
|
+
else if (style.isCaption &&
|
|
549
|
+
(node.nextSibling?.query("w:drawing") ||
|
|
550
|
+
node.nextSibling?.query("w:pict")) &&
|
|
551
|
+
!skippedBlocks.includes(node.nextSibling)) {
|
|
552
|
+
skippedBlocks.push(node.nextSibling);
|
|
553
|
+
converted = this.convertFigure(node.nextSibling, node);
|
|
554
|
+
}
|
|
555
|
+
else if (node.query("w:drawing") || node.query("w:pict")) {
|
|
556
|
+
if (node.nextSibling &&
|
|
557
|
+
this.getParaStyle(node.nextSibling).isCaption) {
|
|
558
|
+
skippedBlocks.push(node.nextSibling);
|
|
559
|
+
converted = this.convertFigure(node, node.nextSibling);
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
converted = this.convertFigure(node);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
else {
|
|
566
|
+
converted = this.convertParagraph(node);
|
|
567
|
+
}
|
|
568
|
+
if (inBibliography || this.inBibliography(node)) {
|
|
569
|
+
// We skip bibliography paragraphs
|
|
570
|
+
return null;
|
|
571
|
+
}
|
|
572
|
+
return this.wrapTrackChanges(node, converted);
|
|
573
|
+
}
|
|
574
|
+
wrapTrackChanges(node, content) {
|
|
575
|
+
if (!content || !node.previousSibling) {
|
|
576
|
+
return content;
|
|
577
|
+
}
|
|
578
|
+
const track = this.getTracksFromNode(node.previousSibling);
|
|
579
|
+
if (!track) {
|
|
580
|
+
return content;
|
|
581
|
+
}
|
|
582
|
+
return {
|
|
583
|
+
...content,
|
|
584
|
+
attrs: Object.assign({}, content.attrs || {}, { track })
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
getTracksFromNode(node) {
|
|
588
|
+
const deletion = node.query("w:pPr")?.query("w:del");
|
|
589
|
+
const insertion = node.query("w:pPr")?.query("w:ins");
|
|
590
|
+
const tracks = [];
|
|
591
|
+
if (insertion) {
|
|
592
|
+
const date = new Date(insertion.getAttribute("w:date"));
|
|
593
|
+
const date10 = Math.floor(date.getTime() / 60000) * 10;
|
|
594
|
+
tracks.push({
|
|
595
|
+
type: "insertion",
|
|
596
|
+
user: 0, // Default user ID
|
|
597
|
+
username: insertion.getAttribute("w:author"),
|
|
598
|
+
date: date10
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
if (deletion) {
|
|
602
|
+
const date = new Date(deletion.getAttribute("w:date"));
|
|
603
|
+
const date10 = Math.floor(date.getTime() / 60000) * 10;
|
|
604
|
+
tracks.push({
|
|
605
|
+
type: "deletion",
|
|
606
|
+
user: 0, // Default user ID
|
|
607
|
+
username: deletion.getAttribute("w:author"),
|
|
608
|
+
date: date10
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
if (tracks.length === 0) {
|
|
612
|
+
return null;
|
|
613
|
+
}
|
|
614
|
+
return tracks;
|
|
615
|
+
}
|
|
616
|
+
getParaStyle(node) {
|
|
617
|
+
const pStyle = node.query("w:pStyle");
|
|
618
|
+
const styleId = pStyle?.getAttribute("w:val");
|
|
619
|
+
const style = this.parser.styles[styleId] || {};
|
|
620
|
+
const numPr = node.query("w:numPr");
|
|
621
|
+
const numId = numPr?.query("w:numId")?.getAttribute("w:val");
|
|
622
|
+
const ilvl = parseInt(numPr?.query("w:ilvl")?.getAttribute("w:val") || "0");
|
|
623
|
+
return {
|
|
624
|
+
...style,
|
|
625
|
+
numbering: numId
|
|
626
|
+
? {
|
|
627
|
+
id: numId,
|
|
628
|
+
level: ilvl,
|
|
629
|
+
definition: this.parser.numbering[numId]
|
|
630
|
+
}
|
|
631
|
+
: null
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
convertParagraph(node) {
|
|
635
|
+
const pStyle = node.query("w:pStyle");
|
|
636
|
+
const styleId = pStyle?.getAttribute("w:val");
|
|
637
|
+
// Check if this is a code block (Code style or inherited from one)
|
|
638
|
+
if (styleId &&
|
|
639
|
+
(this.parser.isCodeStyle?.(styleId) || styleId === "Code")) {
|
|
640
|
+
return {
|
|
641
|
+
type: "code_block",
|
|
642
|
+
attrs: {
|
|
643
|
+
track: [],
|
|
644
|
+
language: "",
|
|
645
|
+
category: "",
|
|
646
|
+
title: "",
|
|
647
|
+
id: ""
|
|
648
|
+
},
|
|
649
|
+
content: this.convertInline(node)
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
return {
|
|
653
|
+
type: "paragraph",
|
|
654
|
+
content: this.convertInline(node)
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
convertHeading(node, style) {
|
|
658
|
+
return {
|
|
659
|
+
type: `heading${style.level}`,
|
|
660
|
+
attrs: {
|
|
661
|
+
id: randomHeadingId(),
|
|
662
|
+
level: style.level
|
|
663
|
+
},
|
|
664
|
+
content: this.convertInline(node)
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
convertListItem(node, style) {
|
|
668
|
+
const numbering = style.numbering;
|
|
669
|
+
const level = numbering.definition?.levels[numbering.level];
|
|
670
|
+
return {
|
|
671
|
+
type: level?.format === "bullet" ? "bullet_list" : "ordered_list",
|
|
672
|
+
attrs: {
|
|
673
|
+
id: `L${Math.random().toString(36).slice(2)}`,
|
|
674
|
+
level: numbering.level,
|
|
675
|
+
start: level?.start || 1
|
|
676
|
+
},
|
|
677
|
+
content: [
|
|
678
|
+
{
|
|
679
|
+
type: "list_item",
|
|
680
|
+
content: [this.convertParagraph(node)]
|
|
681
|
+
}
|
|
682
|
+
]
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
convertFigure(node, captionNode = null) {
|
|
686
|
+
let captionBlock, captionOrder;
|
|
687
|
+
if (captionNode) {
|
|
688
|
+
captionBlock = this.convertParagraph(captionNode);
|
|
689
|
+
captionOrder = node.nextSibling === captionNode ? "after" : "before";
|
|
690
|
+
}
|
|
691
|
+
const drawing = node.query("w:drawing");
|
|
692
|
+
if (!drawing) {
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
const blip = drawing.query("a:blip");
|
|
696
|
+
if (!blip) {
|
|
697
|
+
return null;
|
|
698
|
+
}
|
|
699
|
+
const rId = blip.getAttribute("r:embed");
|
|
700
|
+
const rel = this.parser.relationships[rId];
|
|
701
|
+
if (!rel) {
|
|
702
|
+
return null;
|
|
703
|
+
}
|
|
704
|
+
const imagePath = rel.target.split("/").pop();
|
|
705
|
+
const imageBlob = this.parser.images[imagePath];
|
|
706
|
+
if (!imageBlob) {
|
|
707
|
+
return null;
|
|
708
|
+
}
|
|
709
|
+
// <a:ext cx="5753598" cy="4463556" />
|
|
710
|
+
//
|
|
711
|
+
const size = drawing.query("a:ext");
|
|
712
|
+
const width = parseInt(size.getAttribute("cx") || 0) / 9525; // In EMUs
|
|
713
|
+
const height = parseInt(size.getAttribute("cy") || 0) / 9525; // In EMUs
|
|
714
|
+
const imageId = Math.floor(Math.random() * 1000000);
|
|
715
|
+
this.images[imageId] = {
|
|
716
|
+
id: imageId,
|
|
717
|
+
title: imagePath,
|
|
718
|
+
image: imagePath,
|
|
719
|
+
file: imageBlob,
|
|
720
|
+
copyright: {
|
|
721
|
+
holder: false,
|
|
722
|
+
year: false,
|
|
723
|
+
freeToRead: true,
|
|
724
|
+
licenses: []
|
|
725
|
+
},
|
|
726
|
+
checksum: 0,
|
|
727
|
+
width,
|
|
728
|
+
height
|
|
729
|
+
};
|
|
730
|
+
const image = {
|
|
731
|
+
type: "image",
|
|
732
|
+
attrs: {
|
|
733
|
+
image: imageId
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
const caption = {
|
|
737
|
+
type: "figure_caption",
|
|
738
|
+
content: captionBlock?.content || []
|
|
739
|
+
};
|
|
740
|
+
const content = captionOrder === "before" ? [caption, image] : [image, caption];
|
|
741
|
+
return {
|
|
742
|
+
type: "figure",
|
|
743
|
+
attrs: {
|
|
744
|
+
id: randomFigureId(),
|
|
745
|
+
aligned: "center",
|
|
746
|
+
width: 100,
|
|
747
|
+
caption: !!captionBlock
|
|
748
|
+
},
|
|
749
|
+
content
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
convertInline(node) {
|
|
753
|
+
const content = [];
|
|
754
|
+
// We'll process all inline nodes in document order
|
|
755
|
+
node.children.forEach(child => {
|
|
756
|
+
let contentReceiver = content;
|
|
757
|
+
const currentField = this.currentFields[this.currentFields.length - 1];
|
|
758
|
+
if (currentField) {
|
|
759
|
+
if (currentField.status === "instruction") {
|
|
760
|
+
// We're currently inside the instruction part of a fieldChar
|
|
761
|
+
const instrText = child.query("w:instrText");
|
|
762
|
+
if (instrText) {
|
|
763
|
+
currentField.instructions += instrText.textContent;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
if (currentField.status === "display") {
|
|
767
|
+
// We're currently inside the display part of a fieldChar
|
|
768
|
+
contentReceiver = currentField.display;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
if (child.tagName === "w:r") {
|
|
772
|
+
// A run
|
|
773
|
+
const fieldChar = child.query("w:fldChar");
|
|
774
|
+
if (fieldChar) {
|
|
775
|
+
let currentField;
|
|
776
|
+
let rendercurrentField = false;
|
|
777
|
+
const type = fieldChar.getAttribute("w:fldCharType");
|
|
778
|
+
if (type === "begin") {
|
|
779
|
+
currentField = {
|
|
780
|
+
status: "instruction",
|
|
781
|
+
display: [],
|
|
782
|
+
instructions: "",
|
|
783
|
+
data: null
|
|
784
|
+
};
|
|
785
|
+
this.currentFields.push(currentField);
|
|
786
|
+
}
|
|
787
|
+
else if (type === "separate") {
|
|
788
|
+
currentField =
|
|
789
|
+
this.currentFields[this.currentFields.length - 1];
|
|
790
|
+
currentField.status = "display";
|
|
791
|
+
contentReceiver = currentField.display;
|
|
792
|
+
}
|
|
793
|
+
else if (type === "end") {
|
|
794
|
+
currentField = this.currentFields.pop();
|
|
795
|
+
// If a fieldChar is closed and there was no display part,
|
|
796
|
+
// or it is inside another fieldChar, do nothing
|
|
797
|
+
if (currentField &&
|
|
798
|
+
currentField.status === "display" &&
|
|
799
|
+
this.currentFields.length === 0) {
|
|
800
|
+
rendercurrentField = true;
|
|
801
|
+
contentReceiver = content;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
// Capture base64-encoded field data (used by EndNote)
|
|
805
|
+
const fldDataNode = fieldChar.query("w:fldData");
|
|
806
|
+
if (fldDataNode && currentField) {
|
|
807
|
+
currentField.data = fldDataNode.textContent || null;
|
|
808
|
+
}
|
|
809
|
+
if (rendercurrentField && currentField) {
|
|
810
|
+
this.renderField(currentField).forEach(node => contentReceiver.push(node));
|
|
811
|
+
}
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
// Process footnote references
|
|
815
|
+
const footnoteRef = child.query("w:footnoteReference");
|
|
816
|
+
if (footnoteRef) {
|
|
817
|
+
const footnoteId = footnoteRef.getAttribute("w:id");
|
|
818
|
+
if (this.parser.footnotes[footnoteId]) {
|
|
819
|
+
contentReceiver.push(this.convertFootnote(footnoteId));
|
|
820
|
+
}
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
// Process endnote references
|
|
824
|
+
const endnoteRef = child.query("w:endnoteReference");
|
|
825
|
+
if (endnoteRef) {
|
|
826
|
+
const endnoteId = endnoteRef.getAttribute("w:id");
|
|
827
|
+
if (this.parser.endnotes[endnoteId]) {
|
|
828
|
+
contentReceiver.push(this.convertFootnote(endnoteId, true));
|
|
829
|
+
}
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
// Process text with formatting
|
|
833
|
+
const text = child.query("w:t")?.textContent ||
|
|
834
|
+
child.query("w:delText")?.textContent;
|
|
835
|
+
if (!text) {
|
|
836
|
+
// Process line breaks
|
|
837
|
+
if (child.query("w:br")) {
|
|
838
|
+
contentReceiver.push({ type: "hard_break" });
|
|
839
|
+
}
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
const rPr = child.query("w:rPr");
|
|
843
|
+
const formatting = rPr
|
|
844
|
+
? this.parser.extractRunProperties(rPr)
|
|
845
|
+
: {};
|
|
846
|
+
const insertion = child.closest("w:ins");
|
|
847
|
+
const deletion = child.closest("w:del");
|
|
848
|
+
contentReceiver.push({
|
|
849
|
+
type: "text",
|
|
850
|
+
text,
|
|
851
|
+
marks: this.getCurrentMarks(formatting, insertion, deletion)
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
else if (child.tagName === "w:commentRangeStart") {
|
|
855
|
+
const commentId = child.getAttribute("w:id");
|
|
856
|
+
if (commentId && this.parser.comments[commentId]) {
|
|
857
|
+
this.currentCommentIds.push(commentId);
|
|
858
|
+
}
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
else if (child.tagName === "w:commentRangeEnd") {
|
|
862
|
+
const commentId = child.getAttribute("w:id");
|
|
863
|
+
if (commentId) {
|
|
864
|
+
const index = this.currentCommentIds.indexOf(commentId);
|
|
865
|
+
if (index !== -1) {
|
|
866
|
+
this.currentCommentIds.splice(index, 1);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
else if (child.tagName === "w:r" &&
|
|
872
|
+
child.query("w:commentReference")) {
|
|
873
|
+
// Comment reference - just skip it (we already handle the range)
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
else if (child.tagName === "w:hyperlink") {
|
|
877
|
+
// Process hyperlink
|
|
878
|
+
const rId = child.getAttribute("r:id");
|
|
879
|
+
const anchor = child.getAttribute("w:anchor");
|
|
880
|
+
const relationship = rId ? this.parser.relationships[rId] : null;
|
|
881
|
+
const href = relationship?.target || (anchor ? `#${anchor}` : null);
|
|
882
|
+
if (href) {
|
|
883
|
+
const runs = child.queryAll("w:r");
|
|
884
|
+
const text = runs
|
|
885
|
+
.map(run => run.query("w:t")?.textContent || "")
|
|
886
|
+
.join("");
|
|
887
|
+
if (text) {
|
|
888
|
+
// Check if this is an internal link (bookmark reference) that should be a cross-reference
|
|
889
|
+
if (anchor && this.referenceTargets[anchor]) {
|
|
890
|
+
// If the link text is similar to the target text, treat it as a cross-reference
|
|
891
|
+
const target = this.referenceTargets[anchor];
|
|
892
|
+
const targetText = target.text || anchor;
|
|
893
|
+
// Compare normalized versions to check if text matches target
|
|
894
|
+
if (normalizeText(text) ===
|
|
895
|
+
normalizeText(targetText) ||
|
|
896
|
+
// Also check for "Figure X: " or "Table X: " style references
|
|
897
|
+
text.match(/^(Figure|Table|Equation)\s+\d+(\.\d+)*(\:|\.)?\s*$/i)) {
|
|
898
|
+
contentReceiver.push(this.convertCrossReference(anchor, text));
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
// Otherwise, treat as a normal link
|
|
903
|
+
const rPr = runs[0]?.query("w:rPr");
|
|
904
|
+
const formatting = rPr
|
|
905
|
+
? this.parser.extractRunProperties(rPr)
|
|
906
|
+
: {};
|
|
907
|
+
const marks = this.getCurrentMarks(formatting);
|
|
908
|
+
marks.push({
|
|
909
|
+
type: "link",
|
|
910
|
+
attrs: { href, title: text }
|
|
911
|
+
});
|
|
912
|
+
contentReceiver.push({
|
|
913
|
+
type: "text",
|
|
914
|
+
text,
|
|
915
|
+
marks
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
else if (child.tagName === "m:oMath") {
|
|
921
|
+
const equationNode = this.convertEquation(child);
|
|
922
|
+
if (equationNode) {
|
|
923
|
+
contentReceiver.push(equationNode);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
else if (child.tagName === "w:sdt") {
|
|
927
|
+
if (isDocxSdtCitation(child)) {
|
|
928
|
+
// Used by Mendeley Cite & Citavi
|
|
929
|
+
const citationNode = parseDocxSdtCitation(child, this.bibliography);
|
|
930
|
+
if (citationNode) {
|
|
931
|
+
contentReceiver.push(citationNode);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
else {
|
|
936
|
+
console.warn("unhandled node", child);
|
|
937
|
+
}
|
|
938
|
+
});
|
|
939
|
+
return content;
|
|
940
|
+
}
|
|
941
|
+
// Method to help process cross-references in documents
|
|
942
|
+
findReferenceTargets(document) {
|
|
943
|
+
const targets = {};
|
|
944
|
+
// Find bookmarks
|
|
945
|
+
document.queryAll("w:bookmarkStart").forEach(bookmark => {
|
|
946
|
+
const id = bookmark.getAttribute("w:id");
|
|
947
|
+
const name = bookmark.getAttribute("w:name");
|
|
948
|
+
if (id && name) {
|
|
949
|
+
targets[name] = {
|
|
950
|
+
id: name,
|
|
951
|
+
type: "bookmark"
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
});
|
|
955
|
+
// Find headings (with styles like Heading1, Heading2, etc.)
|
|
956
|
+
document.queryAll("w:pStyle").forEach(pStyle => {
|
|
957
|
+
const val = pStyle.getAttribute("w:val");
|
|
958
|
+
if (val && val.match(/^Heading\d+$/)) {
|
|
959
|
+
const paragraph = pStyle.closest("w:p");
|
|
960
|
+
if (paragraph) {
|
|
961
|
+
const text = this.getTextContent(paragraph);
|
|
962
|
+
// Create an ID from the heading text
|
|
963
|
+
const id = text
|
|
964
|
+
.trim()
|
|
965
|
+
.toLowerCase()
|
|
966
|
+
.replace(/[^\w\s-]/g, "")
|
|
967
|
+
.replace(/\s+/g, "-");
|
|
968
|
+
targets[id] = {
|
|
969
|
+
id: id,
|
|
970
|
+
type: "heading",
|
|
971
|
+
text: text
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
});
|
|
976
|
+
return targets;
|
|
977
|
+
}
|
|
978
|
+
convertFootnote(id, isEndnote = false) {
|
|
979
|
+
const footnoteContent = isEndnote
|
|
980
|
+
? this.parser.endnotes[id].content
|
|
981
|
+
: this.parser.footnotes[id].content;
|
|
982
|
+
// Convert the footnote content to our document model
|
|
983
|
+
const content = [];
|
|
984
|
+
footnoteContent.forEach(block => {
|
|
985
|
+
if (block.type === "paragraph") {
|
|
986
|
+
content.push({
|
|
987
|
+
type: "paragraph",
|
|
988
|
+
content: block.content.map(node => {
|
|
989
|
+
if (node.type === "text") {
|
|
990
|
+
return {
|
|
991
|
+
type: "text",
|
|
992
|
+
text: node.text,
|
|
993
|
+
marks: node.marks || []
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
return node;
|
|
997
|
+
})
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
});
|
|
1001
|
+
return {
|
|
1002
|
+
type: "footnote",
|
|
1003
|
+
attrs: {
|
|
1004
|
+
footnote: content
|
|
1005
|
+
}
|
|
1006
|
+
};
|
|
1007
|
+
}
|
|
1008
|
+
convertEquation(oMathNode) {
|
|
1009
|
+
// Extract OMML content and convert to MathML
|
|
1010
|
+
const mmlNode = omml2mathml(oMathNode);
|
|
1011
|
+
const latex = MathMLToLaTeX.convert(mmlNode.outerXML);
|
|
1012
|
+
return {
|
|
1013
|
+
type: "equation",
|
|
1014
|
+
attrs: {
|
|
1015
|
+
equation: latex
|
|
1016
|
+
}
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
simplifiedOmmlToLatex(omml) {
|
|
1020
|
+
// This is a very basic conversion - in a real implementation you would
|
|
1021
|
+
// use a library like MathML-to-LaTeX or implement a more complete converter
|
|
1022
|
+
// Extract text content as a fallback
|
|
1023
|
+
const textContent = omml
|
|
1024
|
+
.replace(/<[^>]+>/g, " ")
|
|
1025
|
+
.replace(/\s+/g, " ")
|
|
1026
|
+
.trim();
|
|
1027
|
+
// If the OMML contains a fraction
|
|
1028
|
+
if (omml.includes("<m:f>")) {
|
|
1029
|
+
const numMatch = omml.match(/<m:num>(.*?)<\/m:num>/s);
|
|
1030
|
+
const denMatch = omml.match(/<m:den>(.*?)<\/m:den>/s);
|
|
1031
|
+
if (numMatch && denMatch) {
|
|
1032
|
+
const num = numMatch[1].replace(/<[^>]+>/g, "").trim();
|
|
1033
|
+
const den = denMatch[1].replace(/<[^>]+>/g, "").trim();
|
|
1034
|
+
return `\\frac{${num}}{${den}}`;
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
// If it contains a superscript
|
|
1038
|
+
if (omml.includes("<m:sup>")) {
|
|
1039
|
+
const baseMatch = omml.match(/<m:e>(.*?)<\/m:e>/s);
|
|
1040
|
+
const supMatch = omml.match(/<m:sup>(.*?)<\/m:sup>/s);
|
|
1041
|
+
if (baseMatch && supMatch) {
|
|
1042
|
+
const base = baseMatch[1].replace(/<[^>]+>/g, "").trim();
|
|
1043
|
+
const sup = supMatch[1].replace(/<[^>]+>/g, "").trim();
|
|
1044
|
+
return `${base}^{${sup}}`;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
// If it contains a subscript
|
|
1048
|
+
if (omml.includes("<m:sub>")) {
|
|
1049
|
+
const baseMatch = omml.match(/<m:e>(.*?)<\/m:e>/s);
|
|
1050
|
+
const subMatch = omml.match(/<m:sub>(.*?)<\/m:sub>/s);
|
|
1051
|
+
if (baseMatch && subMatch) {
|
|
1052
|
+
const base = baseMatch[1].replace(/<[^>]+>/g, "").trim();
|
|
1053
|
+
const sub = subMatch[1].replace(/<[^>]+>/g, "").trim();
|
|
1054
|
+
return `${base}_{${sub}}`;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
// Return a simplified representation with the text content
|
|
1058
|
+
return textContent || "x^2"; // Default fallback
|
|
1059
|
+
}
|
|
1060
|
+
renderField(field) {
|
|
1061
|
+
const instr = field.instructions.trim();
|
|
1062
|
+
// Handle REF fields (cross-references)
|
|
1063
|
+
if (instr.startsWith("REF ")) {
|
|
1064
|
+
// Extract the target bookmark/heading ID
|
|
1065
|
+
const parts = instr.substring(4).trim().split(/\s+/);
|
|
1066
|
+
if (parts.length > 0) {
|
|
1067
|
+
const target = parts[0];
|
|
1068
|
+
const text = field.display.reduce((accumulator, currentValue) => {
|
|
1069
|
+
if (currentValue.type === "text") {
|
|
1070
|
+
return accumulator + currentValue.text;
|
|
1071
|
+
}
|
|
1072
|
+
return accumulator;
|
|
1073
|
+
}, "");
|
|
1074
|
+
return [this.convertCrossReference(target, text)];
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
// Handle SEQ fields (figure/table/equation number cross-references)
|
|
1078
|
+
else if (instr.startsWith("SEQ ")) {
|
|
1079
|
+
// This is a sequence field that generates numbers for figures/tables/equations.
|
|
1080
|
+
// For cross-references, we look for the text in the display part.
|
|
1081
|
+
const seqMatch = instr.match(/^SEQ\s+(\S+)/);
|
|
1082
|
+
if (seqMatch) {
|
|
1083
|
+
const _seqName = seqMatch[1];
|
|
1084
|
+
const text = field.display.reduce((acc, curr) => {
|
|
1085
|
+
if (curr.type === "text") {
|
|
1086
|
+
return acc + curr.text;
|
|
1087
|
+
}
|
|
1088
|
+
return acc;
|
|
1089
|
+
}, "");
|
|
1090
|
+
if (text) {
|
|
1091
|
+
// Return as a plain text node since we can't resolve SEQ references easily
|
|
1092
|
+
return [
|
|
1093
|
+
{
|
|
1094
|
+
type: "text",
|
|
1095
|
+
text,
|
|
1096
|
+
marks: []
|
|
1097
|
+
}
|
|
1098
|
+
];
|
|
1099
|
+
}
|
|
1100
|
+
return [];
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
// Handle citation fields
|
|
1104
|
+
else if (isDocxCitationField(instr)) {
|
|
1105
|
+
return [
|
|
1106
|
+
parseDocxFieldCitation(instr, field.data, this.sourcesXml, this.bibliography)
|
|
1107
|
+
];
|
|
1108
|
+
}
|
|
1109
|
+
else if (isDocxBibliographyField(instr)) {
|
|
1110
|
+
// We don't render the contents of bibliography fields
|
|
1111
|
+
return [];
|
|
1112
|
+
}
|
|
1113
|
+
else {
|
|
1114
|
+
// We do not support this field type, so instead we return the display content.
|
|
1115
|
+
return field.display || [];
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
convertCrossReference(targetId, displayText) {
|
|
1119
|
+
// Look up the target in our reference targets
|
|
1120
|
+
const target = this.referenceTargets[targetId];
|
|
1121
|
+
// If we found the target, use its information
|
|
1122
|
+
if (target) {
|
|
1123
|
+
return {
|
|
1124
|
+
type: "cross_reference",
|
|
1125
|
+
attrs: {
|
|
1126
|
+
id: targetId,
|
|
1127
|
+
title: displayText || target.text || targetId
|
|
1128
|
+
}
|
|
1129
|
+
};
|
|
1130
|
+
}
|
|
1131
|
+
// If target not found, create a reference with the display text or target ID
|
|
1132
|
+
return {
|
|
1133
|
+
type: "cross_reference",
|
|
1134
|
+
attrs: {
|
|
1135
|
+
id: targetId,
|
|
1136
|
+
title: displayText || targetId
|
|
1137
|
+
}
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
createMarksFromFormatting(formatting, insertion = null, deletion = null) {
|
|
1141
|
+
const marks = [];
|
|
1142
|
+
if (formatting.bold) {
|
|
1143
|
+
marks.push({ type: "strong" });
|
|
1144
|
+
}
|
|
1145
|
+
if (formatting.italic) {
|
|
1146
|
+
marks.push({ type: "em" });
|
|
1147
|
+
}
|
|
1148
|
+
if (formatting.underline) {
|
|
1149
|
+
marks.push({ type: "underline" });
|
|
1150
|
+
}
|
|
1151
|
+
// Handle superscript and subscript
|
|
1152
|
+
if (formatting.vertAlign === "superscript") {
|
|
1153
|
+
marks.push({ type: "sup" });
|
|
1154
|
+
}
|
|
1155
|
+
if (formatting.vertAlign === "subscript") {
|
|
1156
|
+
marks.push({ type: "sub" });
|
|
1157
|
+
}
|
|
1158
|
+
// Handle inline code (monospace fonts)
|
|
1159
|
+
if (formatting.fontFamily) {
|
|
1160
|
+
const monospacePatterns = [
|
|
1161
|
+
/^courier/i,
|
|
1162
|
+
/^consolas/i,
|
|
1163
|
+
/^monaco/i,
|
|
1164
|
+
/^menlo/i,
|
|
1165
|
+
/^lucida console/i,
|
|
1166
|
+
/^liberation mono/i,
|
|
1167
|
+
/^dejavu sans mono/i,
|
|
1168
|
+
/^bitstream vera sans mono/i,
|
|
1169
|
+
/^source code pro/i,
|
|
1170
|
+
/^fira code/i,
|
|
1171
|
+
/^ubuntu mono/i,
|
|
1172
|
+
/^droid sans mono/i
|
|
1173
|
+
];
|
|
1174
|
+
const isMonospace = monospacePatterns.some(pattern => pattern.test(formatting.fontFamily));
|
|
1175
|
+
if (isMonospace) {
|
|
1176
|
+
marks.push({ type: "code" });
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
if (insertion) {
|
|
1180
|
+
const date = new Date(insertion.getAttribute("w:date"));
|
|
1181
|
+
const date10 = Math.floor(date.getTime() / 600000) * 10;
|
|
1182
|
+
marks.push({
|
|
1183
|
+
type: "insertion",
|
|
1184
|
+
attrs: {
|
|
1185
|
+
user: 0,
|
|
1186
|
+
username: insertion.getAttribute("w:author"),
|
|
1187
|
+
date: date10,
|
|
1188
|
+
approved: false
|
|
1189
|
+
}
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
if (deletion) {
|
|
1193
|
+
const date = new Date(deletion.getAttribute("w:date"));
|
|
1194
|
+
const date10 = Math.floor(date.getTime() / 600000) * 10;
|
|
1195
|
+
marks.push({
|
|
1196
|
+
type: "deletion",
|
|
1197
|
+
attrs: {
|
|
1198
|
+
user: 0,
|
|
1199
|
+
username: deletion.getAttribute("w:author"),
|
|
1200
|
+
date: date10
|
|
1201
|
+
}
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
return marks;
|
|
1205
|
+
}
|
|
1206
|
+
getCurrentMarks(formatting, insertion, deletion) {
|
|
1207
|
+
const marks = this.createMarksFromFormatting(formatting, insertion, deletion);
|
|
1208
|
+
// Add comment marks for any active comment IDs
|
|
1209
|
+
this.currentCommentIds.forEach(commentId => {
|
|
1210
|
+
marks.push({
|
|
1211
|
+
type: "comment",
|
|
1212
|
+
attrs: {
|
|
1213
|
+
id: Number.parseInt(commentId)
|
|
1214
|
+
}
|
|
1215
|
+
});
|
|
1216
|
+
});
|
|
1217
|
+
return marks;
|
|
1218
|
+
}
|
|
1219
|
+
hasTrackedChanges(doc) {
|
|
1220
|
+
return Boolean(doc.query("w:ins") || doc.query("w:del"));
|
|
1221
|
+
}
|
|
1222
|
+
detectLanguage(doc) {
|
|
1223
|
+
return doc.query("w:lang")?.getAttribute("w:val") || "en-US";
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
//# sourceMappingURL=convert.js.map
|