fhirsmith 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/FHIRsmith.png +0 -0
- package/README.md +277 -0
- package/config-template.json +144 -0
- package/library/folder-setup.js +58 -0
- package/library/html-server.js +166 -0
- package/library/html.js +835 -0
- package/library/i18nsupport.js +259 -0
- package/library/languages.js +779 -0
- package/library/logger-telnet.js +205 -0
- package/library/logger.js +279 -0
- package/library/package-manager.js +876 -0
- package/library/utilities.js +196 -0
- package/library/version-utilities.js +1056 -0
- package/npmprojector/config-example.json +13 -0
- package/npmprojector/indexer.js +394 -0
- package/npmprojector/npmprojector.js +395 -0
- package/npmprojector/readme.md +174 -0
- package/npmprojector/watcher.js +335 -0
- package/package.json +119 -0
- package/packages/package-crawler.js +846 -0
- package/packages/packages-template.html +126 -0
- package/packages/packages.js +2838 -0
- package/passwords.ini +2 -0
- package/publisher/publisher-template.html +208 -0
- package/publisher/publisher.js +2167 -0
- package/publisher/task-draft.js +458 -0
- package/registry/api.js +735 -0
- package/registry/crawler.js +637 -0
- package/registry/model.js +513 -0
- package/registry/readme.md +243 -0
- package/registry/registry-data.json +121015 -0
- package/registry/registry-template.html +126 -0
- package/registry/registry.js +1395 -0
- package/registry/test-runner.js +237 -0
- package/root-template.html +124 -0
- package/server.js +524 -0
- package/shl/private-key.pem +5 -0
- package/shl/public-key.pem +18 -0
- package/shl/shl.js +1125 -0
- package/shl/vhl.js +69 -0
- package/static/FHIRsmith128.png +0 -0
- package/static/FHIRsmith16.png +0 -0
- package/static/FHIRsmith32.png +0 -0
- package/static/FHIRsmith64.png +0 -0
- package/static/assets/css/bootstrap-fhir.css +5302 -0
- package/static/assets/css/bootstrap-glyphicons.css +2 -0
- package/static/assets/css/bootstrap.css +4097 -0
- package/static/assets/css/jquery-ui.css +523 -0
- package/static/assets/css/jquery-ui.structure.css +863 -0
- package/static/assets/css/jquery-ui.structure.min.css +5 -0
- package/static/assets/css/jquery-ui.theme.css +439 -0
- package/static/assets/css/jquery-ui.theme.min.css +5 -0
- package/static/assets/css/jquery.ui.all.css +7 -0
- package/static/assets/css/modules.css +18 -0
- package/static/assets/css/project.css +367 -0
- package/static/assets/css/pygments-manni.css +66 -0
- package/static/assets/css/tags.css +74 -0
- package/static/assets/css/xml.css +2 -0
- package/static/assets/fonts/glyphiconshalflings-regular.eot +0 -0
- package/static/assets/fonts/glyphiconshalflings-regular.otf +0 -0
- package/static/assets/fonts/glyphiconshalflings-regular.svg +175 -0
- package/static/assets/fonts/glyphiconshalflings-regular.ttf +0 -0
- package/static/assets/fonts/glyphiconshalflings-regular.woff +0 -0
- package/static/assets/ico/apple-touch-icon-114-precomposed.png +0 -0
- package/static/assets/ico/apple-touch-icon-144-precomposed.png +0 -0
- package/static/assets/ico/apple-touch-icon-57-precomposed.png +0 -0
- package/static/assets/ico/apple-touch-icon-72-precomposed.png +0 -0
- package/static/assets/ico/favicon.ico +0 -0
- package/static/assets/ico/favicon.png +0 -0
- package/static/assets/images/fhir-logo-www.png +0 -0
- package/static/assets/images/fhir-logo.png +0 -0
- package/static/assets/images/hl7-logo.png +0 -0
- package/static/assets/images/logo_ansinew.jpg +0 -0
- package/static/assets/images/search.png +0 -0
- package/static/assets/images/stripe.png +0 -0
- package/static/assets/images/target.png +0 -0
- package/static/assets/images/tx-registry-root.gif +0 -0
- package/static/assets/images/tx-registry.png +0 -0
- package/static/assets/images/tx-server.png +0 -0
- package/static/assets/images/tx-version.png +0 -0
- package/static/assets/js/bootstrap.min.js +6 -0
- package/static/assets/js/fhir-gw.js +259 -0
- package/static/assets/js/fhir.js +2 -0
- package/static/assets/js/html5shiv.js +8 -0
- package/static/assets/js/jcookie.js +96 -0
- package/static/assets/js/jquery-ui.min.js +6 -0
- package/static/assets/js/jquery.js +10716 -0
- package/static/assets/js/jquery.min.js +2 -0
- package/static/assets/js/jquery.ui.core.js +314 -0
- package/static/assets/js/jquery.ui.draggable.js +825 -0
- package/static/assets/js/jquery.ui.mouse.js +162 -0
- package/static/assets/js/jquery.ui.resizable.js +842 -0
- package/static/assets/js/jquery.ui.widget.js +268 -0
- package/static/assets/js/json2.js +487 -0
- package/static/assets/js/jtip.js +97 -0
- package/static/assets/js/respond.min.js +6 -0
- package/static/assets/js/statuspage.js +70 -0
- package/static/assets/js/xml.js +2 -0
- package/static/dist/js/bootstrap.js +1964 -0
- package/static/favicon.png +0 -0
- package/static/fhir.css +626 -0
- package/static/icon-fhir-16.png +0 -0
- package/static/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
- package/static/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
- package/static/images/ui-bg_flat_10_000000_40x100.png +0 -0
- package/static/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
- package/static/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
- package/static/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- package/static/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
- package/static/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
- package/static/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
- package/static/images/ui-icons_222222_256x240.png +0 -0
- package/static/images/ui-icons_228ef1_256x240.png +0 -0
- package/static/images/ui-icons_ef8c08_256x240.png +0 -0
- package/static/images/ui-icons_ffd27a_256x240.png +0 -0
- package/static/images/ui-icons_ffffff_256x240.png +0 -0
- package/static/js/jquery.effects.blind.js +49 -0
- package/static/js/jquery.effects.bounce.js +78 -0
- package/static/js/jquery.effects.clip.js +54 -0
- package/static/js/jquery.effects.core.js +763 -0
- package/static/js/jquery.effects.drop.js +50 -0
- package/static/js/jquery.effects.explode.js +79 -0
- package/static/js/jquery.effects.fade.js +32 -0
- package/static/js/jquery.effects.fold.js +56 -0
- package/static/js/jquery.effects.highlight.js +50 -0
- package/static/js/jquery.effects.pulsate.js +51 -0
- package/static/js/jquery.effects.scale.js +178 -0
- package/static/js/jquery.effects.shake.js +57 -0
- package/static/js/jquery.effects.slide.js +50 -0
- package/static/js/jquery.effects.transfer.js +45 -0
- package/static/js/jquery.ui.accordion.js +611 -0
- package/static/js/jquery.ui.autocomplete.js +612 -0
- package/static/js/jquery.ui.button.js +416 -0
- package/static/js/jquery.ui.datepicker.js +1823 -0
- package/static/js/jquery.ui.dialog.js +878 -0
- package/static/js/jquery.ui.droppable.js +296 -0
- package/static/js/jquery.ui.position.js +252 -0
- package/static/js/jquery.ui.progressbar.js +109 -0
- package/static/js/jquery.ui.selectable.js +266 -0
- package/static/js/jquery.ui.slider.js +666 -0
- package/static/js/jquery.ui.sortable.js +1077 -0
- package/static/js/jquery.ui.tabs.js +758 -0
- package/stats.js +80 -0
- package/test-cache/vsac/vsac-valuesets.db +0 -0
- package/token/nginx_passport_setup.md +383 -0
- package/token/security_guide.md +294 -0
- package/token/token-template.html +330 -0
- package/token/token.js +1300 -0
- package/translations/Messages.properties +1510 -0
- package/translations/Messages_ar.properties +1399 -0
- package/translations/Messages_de.properties +836 -0
- package/translations/Messages_es.properties +737 -0
- package/translations/Messages_fr.properties +1 -0
- package/translations/Messages_ja.properties +893 -0
- package/translations/Messages_nl.properties +1357 -0
- package/translations/Messages_pt.properties +1302 -0
- package/translations/Messages_ru.properties +1 -0
- package/translations/Messages_uz.properties +1 -0
- package/translations/Messages_zh.properties +1 -0
- package/translations/rendering-phrases.properties +1128 -0
- package/translations/rendering-phrases_ar.properties +1091 -0
- package/translations/rendering-phrases_de.properties +6 -0
- package/translations/rendering-phrases_es.properties +6 -0
- package/translations/rendering-phrases_fr.properties +624 -0
- package/translations/rendering-phrases_ja.properties +21 -0
- package/translations/rendering-phrases_nl.properties +970 -0
- package/translations/rendering-phrases_pt.properties +1020 -0
- package/translations/rendering-phrases_ru.properties +1094 -0
- package/translations/rendering-phrases_uz.properties +1 -0
- package/translations/rendering-phrases_zh.properties +1 -0
- package/tx/README.md +418 -0
- package/tx/cm/cm-api.js +110 -0
- package/tx/cm/cm-database.js +735 -0
- package/tx/cm/cm-package.js +325 -0
- package/tx/cs/cs-api.js +789 -0
- package/tx/cs/cs-areacode.js +615 -0
- package/tx/cs/cs-country.js +1110 -0
- package/tx/cs/cs-cpt.js +785 -0
- package/tx/cs/cs-cs.js +1579 -0
- package/tx/cs/cs-currency.js +539 -0
- package/tx/cs/cs-db.js +1321 -0
- package/tx/cs/cs-hgvs.js +329 -0
- package/tx/cs/cs-lang.js +465 -0
- package/tx/cs/cs-loinc.js +1485 -0
- package/tx/cs/cs-mimetypes.js +238 -0
- package/tx/cs/cs-ndc.js +704 -0
- package/tx/cs/cs-omop.js +1025 -0
- package/tx/cs/cs-provider-api.js +43 -0
- package/tx/cs/cs-provider-list.js +37 -0
- package/tx/cs/cs-rxnorm.js +808 -0
- package/tx/cs/cs-snomed.js +1102 -0
- package/tx/cs/cs-ucum.js +514 -0
- package/tx/cs/cs-unii.js +271 -0
- package/tx/cs/cs-uri.js +218 -0
- package/tx/cs/cs-usstates.js +305 -0
- package/tx/dev.fhir.org.yml +14 -0
- package/tx/fixtures/test-cases-setup.json +18 -0
- package/tx/fixtures/test-cases.yml +16 -0
- package/tx/html/codesystem-operations.liquid +25 -0
- package/tx/html/home-metrics.liquid +247 -0
- package/tx/html/operations-form.liquid +148 -0
- package/tx/html/search-form.liquid +62 -0
- package/tx/html/tx-template.html +133 -0
- package/tx/html/valueset-operations.liquid +54 -0
- package/tx/importers/atc-to-fhir.js +316 -0
- package/tx/importers/import-loinc.module.js +1536 -0
- package/tx/importers/import-ndc.module.js +1088 -0
- package/tx/importers/import-rxnorm.module.js +898 -0
- package/tx/importers/import-sct.module.js +2457 -0
- package/tx/importers/import-unii.module.js +601 -0
- package/tx/importers/readme.md +453 -0
- package/tx/importers/subset-loinc.module.js +1081 -0
- package/tx/importers/subset-rxnorm.module.js +938 -0
- package/tx/importers/tx-import-base.js +351 -0
- package/tx/importers/tx-import-settings.js +310 -0
- package/tx/importers/tx-import.js +357 -0
- package/tx/library/canonical-resource.js +88 -0
- package/tx/library/capabilitystatement.js +292 -0
- package/tx/library/codesystem.js +774 -0
- package/tx/library/conceptmap.js +568 -0
- package/tx/library/designations.js +932 -0
- package/tx/library/errors.js +77 -0
- package/tx/library/extensions.js +117 -0
- package/tx/library/namingsystem.js +322 -0
- package/tx/library/operation-outcome.js +127 -0
- package/tx/library/parameters.js +105 -0
- package/tx/library/renderer.js +1559 -0
- package/tx/library/terminologycapabilities.js +418 -0
- package/tx/library/ucum-parsers.js +1029 -0
- package/tx/library/ucum-service.js +370 -0
- package/tx/library/ucum-types.js +1099 -0
- package/tx/library/valueset.js +543 -0
- package/tx/library.js +676 -0
- package/tx/ocl/cm-ocl.js +106 -0
- package/tx/ocl/cs-ocl.js +39 -0
- package/tx/ocl/vs-ocl.js +105 -0
- package/tx/operation-context.js +568 -0
- package/tx/params.js +613 -0
- package/tx/provider.js +403 -0
- package/tx/sct/ecl.js +1560 -0
- package/tx/sct/expressions.js +2077 -0
- package/tx/sct/structures.js +1396 -0
- package/tx/tx-html.js +1063 -0
- package/tx/tx.fhir.org.yml +39 -0
- package/tx/tx.js +927 -0
- package/tx/vs/vs-api.js +112 -0
- package/tx/vs/vs-database.js +786 -0
- package/tx/vs/vs-package.js +358 -0
- package/tx/vs/vs-vsac.js +366 -0
- package/tx/workers/batch-validate.js +129 -0
- package/tx/workers/batch.js +361 -0
- package/tx/workers/closure.js +32 -0
- package/tx/workers/expand.js +1845 -0
- package/tx/workers/lookup.js +407 -0
- package/tx/workers/metadata.js +467 -0
- package/tx/workers/operations.js +34 -0
- package/tx/workers/read.js +164 -0
- package/tx/workers/search.js +384 -0
- package/tx/workers/subsumes.js +334 -0
- package/tx/workers/translate.js +492 -0
- package/tx/workers/validate.js +2504 -0
- package/tx/workers/worker.js +904 -0
- package/tx/xml/capabilitystatement-xml.js +63 -0
- package/tx/xml/codesystem-xml.js +62 -0
- package/tx/xml/conceptmap-xml.js +65 -0
- package/tx/xml/namingsystem-xml.js +65 -0
- package/tx/xml/operationoutcome-xml.js +127 -0
- package/tx/xml/parameters-xml.js +312 -0
- package/tx/xml/terminologycapabilities-xml.js +64 -0
- package/tx/xml/valueset-xml.js +64 -0
- package/tx/xml/xml-base.js +603 -0
- package/vcl/vcl-parser.js +1098 -0
- package/vcl/vcl.js +253 -0
- package/windows-install.js +19 -0
- package/xig/xig-template.html +124 -0
- package/xig/xig.js +3049 -0
package/library/html.js
ADDED
|
@@ -0,0 +1,835 @@
|
|
|
1
|
+
const {validateParameter, validateOptionalParameter} = require("./utilities");
|
|
2
|
+
const NodeType = {
|
|
3
|
+
Document: 'Document',
|
|
4
|
+
Element: 'Element',
|
|
5
|
+
Text: 'Text',
|
|
6
|
+
Comment: 'Comment',
|
|
7
|
+
DocType: 'DocType',
|
|
8
|
+
Instruction: 'Instruction'
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
class XhtmlNode {
|
|
12
|
+
constructor(nodeType, name = null) {
|
|
13
|
+
this.nodeType = nodeType;
|
|
14
|
+
this.name = name;
|
|
15
|
+
this.attributes = new Map();
|
|
16
|
+
this.childNodes = [];
|
|
17
|
+
this.content = null; // for text nodes
|
|
18
|
+
this.inPara = false;
|
|
19
|
+
this.inLink = false;
|
|
20
|
+
this.pretty = true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Attribute methods
|
|
24
|
+
setAttribute(name, value) {
|
|
25
|
+
if (value != null) {
|
|
26
|
+
this.attributes.set(name, value);
|
|
27
|
+
}
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
attribute(name, value) {
|
|
32
|
+
return this.setAttribute(name, value);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
attr(name, value) {
|
|
36
|
+
return this.setAttribute(name, value);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
getAttribute(name) {
|
|
40
|
+
return this.attributes.get(name) || null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
hasAttribute(name) {
|
|
44
|
+
return this.attributes.has(name);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
removeAttribute(name) {
|
|
48
|
+
this.attributes.delete(name);
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Class helpers
|
|
53
|
+
clss(className) {
|
|
54
|
+
if (className) {
|
|
55
|
+
const existing = this.attributes.get('class');
|
|
56
|
+
if (existing) {
|
|
57
|
+
this.attributes.set('class', existing + ' ' + className);
|
|
58
|
+
} else {
|
|
59
|
+
this.attributes.set('class', className);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
style(style) {
|
|
66
|
+
if (style) {
|
|
67
|
+
this.attributes.set('style', style);
|
|
68
|
+
}
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
id(id) {
|
|
73
|
+
if (id) {
|
|
74
|
+
this.attributes.set('id', id);
|
|
75
|
+
}
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
title(title) {
|
|
80
|
+
if (title) {
|
|
81
|
+
this.attributes.set('title', title);
|
|
82
|
+
}
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Child node management
|
|
87
|
+
#makeTag(name) {
|
|
88
|
+
const node = new XhtmlNode(NodeType.Element, name);
|
|
89
|
+
if (this.inPara || name === 'p') {
|
|
90
|
+
node.inPara = true;
|
|
91
|
+
}
|
|
92
|
+
if (this.inLink || name === 'a') {
|
|
93
|
+
node.inLink = true;
|
|
94
|
+
}
|
|
95
|
+
const inlineElements = ['b', 'big', 'i', 'small', 'tt', 'abbr', 'acronym', 'cite', 'code',
|
|
96
|
+
'dfn', 'em', 'kbd', 'strong', 'samp', 'var', 'a', 'bdo', 'br', 'img', 'map', 'object',
|
|
97
|
+
'q', 'script', 'span', 'sub', 'sup', 'button', 'input', 'label', 'select', 'textarea'];
|
|
98
|
+
if (inlineElements.includes(name)) {
|
|
99
|
+
node.pretty = false;
|
|
100
|
+
}
|
|
101
|
+
return node;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
addTag(nameOrIndex, name = null) {
|
|
105
|
+
if (typeof nameOrIndex === 'number') {
|
|
106
|
+
const node = this.#makeTag(name);
|
|
107
|
+
this.childNodes.splice(nameOrIndex, 0, node);
|
|
108
|
+
return node;
|
|
109
|
+
} else {
|
|
110
|
+
const node = this.#makeTag(nameOrIndex);
|
|
111
|
+
this.childNodes.push(node);
|
|
112
|
+
return node;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
addText(content) {
|
|
117
|
+
if (content != null) {
|
|
118
|
+
const node = new XhtmlNode(NodeType.Text);
|
|
119
|
+
node.content = String(content);
|
|
120
|
+
this.childNodes.push(node);
|
|
121
|
+
return node;
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
addComment(content) {
|
|
127
|
+
if (content != null) {
|
|
128
|
+
const node = new XhtmlNode(NodeType.Comment);
|
|
129
|
+
node.content = content;
|
|
130
|
+
this.childNodes.push(node);
|
|
131
|
+
return node;
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
addChildren(nodes) {
|
|
137
|
+
if (nodes) {
|
|
138
|
+
for (const node of nodes) {
|
|
139
|
+
this.childNodes.push(node);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return this;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
addChild(node) {
|
|
146
|
+
if (node) {
|
|
147
|
+
this.childNodes.push(node);
|
|
148
|
+
}
|
|
149
|
+
return this;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
clear() {
|
|
153
|
+
this.childNodes = [];
|
|
154
|
+
return this;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
indexOf(node) {
|
|
158
|
+
return this.childNodes.indexOf(node);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
hasChildren() {
|
|
162
|
+
return this.childNodes.length > 0;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
getFirstElement() {
|
|
166
|
+
for (const child of this.childNodes) {
|
|
167
|
+
if (child.nodeType === NodeType.Element) {
|
|
168
|
+
return child;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Text content helpers
|
|
175
|
+
tx(content) {
|
|
176
|
+
return this.addText(content);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
txN(content) {
|
|
180
|
+
this.addText(content);
|
|
181
|
+
return this;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
stx(content) {
|
|
185
|
+
if (content) {
|
|
186
|
+
this.addText(' ' + content);
|
|
187
|
+
}
|
|
188
|
+
return this;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Fluent element creation methods
|
|
192
|
+
h(level, id = null) {
|
|
193
|
+
if (level < 1 || level > 6) {
|
|
194
|
+
throw new Error('Illegal Header level ' + level);
|
|
195
|
+
}
|
|
196
|
+
const node = this.addTag('h' + level);
|
|
197
|
+
if (id) {
|
|
198
|
+
node.setAttribute('id', id);
|
|
199
|
+
}
|
|
200
|
+
return node;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
h1() { return this.addTag('h1'); }
|
|
204
|
+
h2() { return this.addTag('h2'); }
|
|
205
|
+
h3() { return this.addTag('h3'); }
|
|
206
|
+
h4() { return this.addTag('h4'); }
|
|
207
|
+
h5() { return this.addTag('h5'); }
|
|
208
|
+
h6() { return this.addTag('h6'); }
|
|
209
|
+
|
|
210
|
+
div(style = null) {
|
|
211
|
+
const node = this.addTag('div');
|
|
212
|
+
if (style) {
|
|
213
|
+
node.setAttribute('style', style);
|
|
214
|
+
}
|
|
215
|
+
return node;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
span(style = null, title = null) {
|
|
219
|
+
const node = this.addTag('span');
|
|
220
|
+
if (style) {
|
|
221
|
+
node.setAttribute('style', style);
|
|
222
|
+
}
|
|
223
|
+
if (title) {
|
|
224
|
+
node.setAttribute('title', title);
|
|
225
|
+
}
|
|
226
|
+
return node;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
spanClss(className) {
|
|
230
|
+
const node = this.addTag('span');
|
|
231
|
+
if (className) {
|
|
232
|
+
node.setAttribute('class', className);
|
|
233
|
+
}
|
|
234
|
+
return node;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
para() { return this.addTag('p'); }
|
|
238
|
+
p() { return this.addTag('p'); }
|
|
239
|
+
|
|
240
|
+
pre(clss = null) {
|
|
241
|
+
const node = this.addTag('pre');
|
|
242
|
+
if (clss) {
|
|
243
|
+
node.setAttribute('class', clss);
|
|
244
|
+
}
|
|
245
|
+
return node;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
blockquote() { return this.addTag('blockquote'); }
|
|
249
|
+
|
|
250
|
+
// Lists
|
|
251
|
+
ul() { return this.addTag('ul'); }
|
|
252
|
+
ol() { return this.addTag('ol'); }
|
|
253
|
+
li() { return this.addTag('li'); }
|
|
254
|
+
|
|
255
|
+
// Tables
|
|
256
|
+
table(clss = null, forPresentation = false) {
|
|
257
|
+
const node = this.addTag('table');
|
|
258
|
+
if (clss) {
|
|
259
|
+
node.clss(clss);
|
|
260
|
+
}
|
|
261
|
+
if (forPresentation) {
|
|
262
|
+
node.clss('presentation');
|
|
263
|
+
}
|
|
264
|
+
return node;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
tr(afterRow = null) {
|
|
268
|
+
if (afterRow) {
|
|
269
|
+
const index = this.indexOf(afterRow);
|
|
270
|
+
return this.addTag(index + 1, 'tr');
|
|
271
|
+
}
|
|
272
|
+
return this.addTag('tr');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
th(index = null) {
|
|
276
|
+
if (index !== null) {
|
|
277
|
+
return this.addTag(index, 'th');
|
|
278
|
+
}
|
|
279
|
+
return this.addTag('th');
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
td(clss = null) {
|
|
283
|
+
const node = this.addTag('td');
|
|
284
|
+
if (clss) {
|
|
285
|
+
node.setAttribute('class', clss);
|
|
286
|
+
}
|
|
287
|
+
return node;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
thead() { return this.addTag('thead'); }
|
|
291
|
+
tbody() { return this.addTag('tbody'); }
|
|
292
|
+
tfoot() { return this.addTag('tfoot'); }
|
|
293
|
+
|
|
294
|
+
// Inline elements
|
|
295
|
+
b() { return this.addTag('b'); }
|
|
296
|
+
i() { return this.addTag('i'); }
|
|
297
|
+
em() { return this.addTag('em'); }
|
|
298
|
+
strong() { return this.addTag('strong'); }
|
|
299
|
+
small() { return this.addTag('small'); }
|
|
300
|
+
sub() { return this.addTag('sub'); }
|
|
301
|
+
sup() { return this.addTag('sup'); }
|
|
302
|
+
|
|
303
|
+
code(text = null) {
|
|
304
|
+
const node = this.addTag('code');
|
|
305
|
+
if (text) {
|
|
306
|
+
node.tx(text);
|
|
307
|
+
}
|
|
308
|
+
return node;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
codeWithText(preText, text, postText) {
|
|
312
|
+
this.tx(preText);
|
|
313
|
+
const code = this.addTag('code');
|
|
314
|
+
code.tx(text);
|
|
315
|
+
this.tx(postText);
|
|
316
|
+
return this;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Line breaks
|
|
320
|
+
br() {
|
|
321
|
+
this.addTag('br');
|
|
322
|
+
return this;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
hr() {
|
|
326
|
+
this.addTag('hr');
|
|
327
|
+
return this;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Links
|
|
331
|
+
ah(href, title = null) {
|
|
332
|
+
if (href == null) {
|
|
333
|
+
return this.addTag('span');
|
|
334
|
+
}
|
|
335
|
+
const node = this.addTag('a').setAttribute('href', href);
|
|
336
|
+
if (title) {
|
|
337
|
+
node.setAttribute('title', title);
|
|
338
|
+
}
|
|
339
|
+
return node;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
ahWithText(preText, href, title, text, postText) {
|
|
343
|
+
this.tx(preText);
|
|
344
|
+
const a = this.addTag('a').setAttribute('href', href);
|
|
345
|
+
if (title) {
|
|
346
|
+
a.setAttribute('title', title);
|
|
347
|
+
}
|
|
348
|
+
a.tx(text);
|
|
349
|
+
this.tx(postText);
|
|
350
|
+
return a;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
ahOrCode(href, title = null) {
|
|
354
|
+
if (href != null) {
|
|
355
|
+
return this.ah(href, title);
|
|
356
|
+
} else if (title != null) {
|
|
357
|
+
return this.code().setAttribute('title', title);
|
|
358
|
+
} else {
|
|
359
|
+
return this.code();
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
an(name, text = ' ') {
|
|
364
|
+
const a = this.addTag('a').setAttribute('name', name);
|
|
365
|
+
a.tx(text);
|
|
366
|
+
return a;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Images
|
|
370
|
+
img(src, alt, title = null) {
|
|
371
|
+
const node = this.addTag('img')
|
|
372
|
+
.setAttribute('src', src)
|
|
373
|
+
.setAttribute('alt', alt || '.');
|
|
374
|
+
if (title) {
|
|
375
|
+
node.setAttribute('title', title);
|
|
376
|
+
}
|
|
377
|
+
return node;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
imgT(src, alt) {
|
|
381
|
+
return this.img(src, alt, alt);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Forms
|
|
385
|
+
input(type, name, value = null) {
|
|
386
|
+
const node = this.addTag('input')
|
|
387
|
+
.setAttribute('type', type)
|
|
388
|
+
.setAttribute('name', name);
|
|
389
|
+
if (value != null) {
|
|
390
|
+
node.setAttribute('value', value);
|
|
391
|
+
}
|
|
392
|
+
return node;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
button(text) {
|
|
396
|
+
const node = this.addTag('button');
|
|
397
|
+
node.tx(text);
|
|
398
|
+
return node;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
select(name) {
|
|
402
|
+
return this.addTag('select').setAttribute('name', name);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
option(value, text, selected = false) {
|
|
406
|
+
const node = this.addTag('option').setAttribute('value', value);
|
|
407
|
+
node.tx(text);
|
|
408
|
+
if (selected) {
|
|
409
|
+
node.setAttribute('selected', 'selected');
|
|
410
|
+
}
|
|
411
|
+
return node;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
textarea(name, rows = null, cols = null) {
|
|
415
|
+
const node = this.addTag('textarea').setAttribute('name', name);
|
|
416
|
+
if (rows != null) {
|
|
417
|
+
node.setAttribute('rows', String(rows));
|
|
418
|
+
}
|
|
419
|
+
if (cols != null) {
|
|
420
|
+
node.setAttribute('cols', String(cols));
|
|
421
|
+
}
|
|
422
|
+
return node;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
label(forId) {
|
|
426
|
+
return this.addTag('label').setAttribute('for', forId);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Conditional
|
|
430
|
+
iff(test) {
|
|
431
|
+
if (test) {
|
|
432
|
+
return this;
|
|
433
|
+
} else {
|
|
434
|
+
return new XhtmlNode(NodeType.Element, 'span'); // disconnected node
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Separator helper
|
|
439
|
+
sep(text) {
|
|
440
|
+
if (this.hasChildren()) {
|
|
441
|
+
this.addText(text);
|
|
442
|
+
}
|
|
443
|
+
return this;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Rendering
|
|
447
|
+
notPretty() {
|
|
448
|
+
this.pretty = false;
|
|
449
|
+
return this;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
allText() {
|
|
453
|
+
let result = '';
|
|
454
|
+
for (const child of this.childNodes) {
|
|
455
|
+
if (child.nodeType === NodeType.Text) {
|
|
456
|
+
result += child.content || '';
|
|
457
|
+
} else if (child.nodeType === NodeType.Element) {
|
|
458
|
+
result += child.allText();
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return result;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
startCommaList(lastWord) {
|
|
465
|
+
validateParameter(lastWord, 'lastWord', String);
|
|
466
|
+
if (this.lastWord) {
|
|
467
|
+
throw new Error('Unclosed list');
|
|
468
|
+
}
|
|
469
|
+
this.lastWord = lastWord;
|
|
470
|
+
this.commaItems = [];
|
|
471
|
+
this.commaFirst = true;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
commaItem(text, link) {
|
|
475
|
+
validateParameter(text, 'text', String);
|
|
476
|
+
validateOptionalParameter(link, 'link', String);
|
|
477
|
+
|
|
478
|
+
if (!this.commaFirst) {
|
|
479
|
+
this.commaItems.push(this.tx(", "));
|
|
480
|
+
}
|
|
481
|
+
this.commaFirst = false;
|
|
482
|
+
if (link) {
|
|
483
|
+
this.ah(link).tx(text);
|
|
484
|
+
} else {
|
|
485
|
+
this.tx(text);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
stopCommaList() {
|
|
490
|
+
if (this.commaItems && this.commaItems.length > 0) {
|
|
491
|
+
this.commaItems[this.commaItems.length-1].content = " "+this.lastWord+" ";
|
|
492
|
+
}
|
|
493
|
+
this.lastWord = undefined;
|
|
494
|
+
this.commaItems = undefined;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Script execution methods
|
|
498
|
+
|
|
499
|
+
startScript(name) {
|
|
500
|
+
if (this.namedParams) {
|
|
501
|
+
throw new Error(`Sequence Error - script is already open @ ${name}`);
|
|
502
|
+
}
|
|
503
|
+
this.namedParams = new Map();
|
|
504
|
+
this.namedParamValues = new Map();
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
param(name) {
|
|
508
|
+
if (!this.namedParams) {
|
|
509
|
+
throw new Error('Sequence Error - script is not already open');
|
|
510
|
+
}
|
|
511
|
+
// Create a detached node that will be inserted when the script executes
|
|
512
|
+
const node = new XhtmlNode(NodeType.Element, 'p');
|
|
513
|
+
node.inPara = true;
|
|
514
|
+
this.namedParams.set(name, node);
|
|
515
|
+
return node;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
paramValue(name, value) {
|
|
519
|
+
if (!this.namedParamValues) {
|
|
520
|
+
throw new Error('Sequence Error - script is not already open');
|
|
521
|
+
}
|
|
522
|
+
this.namedParamValues.set(name, String(value));
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
execScript(structure) {
|
|
526
|
+
const scriptNodes = this.#parseFragment(`<div>${structure}</div>`);
|
|
527
|
+
this.#parseNodes(scriptNodes, this.childNodes);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
#parseNodes(source, dest) {
|
|
531
|
+
for (const n of source) {
|
|
532
|
+
if (n.name === 'param') {
|
|
533
|
+
const paramName = n.getAttribute('name');
|
|
534
|
+
const node = this.namedParams.get(paramName);
|
|
535
|
+
if (node) {
|
|
536
|
+
this.#parseNodes(node.childNodes, dest);
|
|
537
|
+
}
|
|
538
|
+
} else if (n.name === 'if') {
|
|
539
|
+
const test = n.getAttribute('test');
|
|
540
|
+
if (this.#passesTest(test)) {
|
|
541
|
+
this.#parseNodes(n.childNodes, dest);
|
|
542
|
+
}
|
|
543
|
+
} else {
|
|
544
|
+
dest.push(n);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
#passesTest(test) {
|
|
550
|
+
const parts = test.trim().split(/\s+/);
|
|
551
|
+
if (parts.length !== 3) {
|
|
552
|
+
return false;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const [paramName, operator, compareValue] = parts;
|
|
556
|
+
|
|
557
|
+
if (!this.namedParamValues.has(paramName)) {
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
const paramValue = this.namedParamValues.get(paramName);
|
|
562
|
+
|
|
563
|
+
switch (operator) {
|
|
564
|
+
case '=':
|
|
565
|
+
return compareValue.toLowerCase() === paramValue.toLowerCase();
|
|
566
|
+
case '!=':
|
|
567
|
+
return compareValue.toLowerCase() !== paramValue.toLowerCase();
|
|
568
|
+
case '<':
|
|
569
|
+
return this.#isInteger(paramValue) && this.#isInteger(compareValue) &&
|
|
570
|
+
parseInt(paramValue, 10) < parseInt(compareValue, 10);
|
|
571
|
+
case '<=':
|
|
572
|
+
return this.#isInteger(paramValue) && this.#isInteger(compareValue) &&
|
|
573
|
+
parseInt(paramValue, 10) <= parseInt(compareValue, 10);
|
|
574
|
+
case '>':
|
|
575
|
+
return this.#isInteger(paramValue) && this.#isInteger(compareValue) &&
|
|
576
|
+
parseInt(paramValue, 10) > parseInt(compareValue, 10);
|
|
577
|
+
case '>=':
|
|
578
|
+
return this.#isInteger(paramValue) && this.#isInteger(compareValue) &&
|
|
579
|
+
parseInt(paramValue, 10) >= parseInt(compareValue, 10);
|
|
580
|
+
default:
|
|
581
|
+
return false;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
#isInteger(str) {
|
|
586
|
+
return /^-?\d+$/.test(str);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
#parseFragment(html) {
|
|
590
|
+
const nodes = [];
|
|
591
|
+
const stack = [{ children: nodes }];
|
|
592
|
+
let current = stack[0];
|
|
593
|
+
let i = 0;
|
|
594
|
+
|
|
595
|
+
while (i < html.length) {
|
|
596
|
+
if (html[i] === '<') {
|
|
597
|
+
// Check for closing tag
|
|
598
|
+
if (html[i + 1] === '/') {
|
|
599
|
+
const endTag = html.indexOf('>', i);
|
|
600
|
+
stack.pop();
|
|
601
|
+
current = stack[stack.length - 1];
|
|
602
|
+
i = endTag + 1;
|
|
603
|
+
continue;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// Find tag end
|
|
607
|
+
const tagEnd = html.indexOf('>', i);
|
|
608
|
+
const tagContent = html.substring(i + 1, tagEnd);
|
|
609
|
+
const selfClosing = tagContent.endsWith('/');
|
|
610
|
+
const cleanContent = selfClosing ? tagContent.slice(0, -1).trim() : tagContent.trim();
|
|
611
|
+
|
|
612
|
+
// Parse tag name and attributes
|
|
613
|
+
const spaceIndex = cleanContent.indexOf(' ');
|
|
614
|
+
const tagName = spaceIndex === -1 ? cleanContent : cleanContent.substring(0, spaceIndex);
|
|
615
|
+
const attrString = spaceIndex === -1 ? '' : cleanContent.substring(spaceIndex + 1);
|
|
616
|
+
|
|
617
|
+
const node = new XhtmlNode(NodeType.Element, tagName);
|
|
618
|
+
|
|
619
|
+
// Parse attributes
|
|
620
|
+
const attrRegex = /(\w+)=["']([^"']*)["']/g;
|
|
621
|
+
let match;
|
|
622
|
+
while ((match = attrRegex.exec(attrString)) !== null) {
|
|
623
|
+
node.setAttribute(match[1], match[2]);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
current.children.push(node);
|
|
627
|
+
|
|
628
|
+
if (!selfClosing) {
|
|
629
|
+
stack.push({ children: node.childNodes });
|
|
630
|
+
current = stack[stack.length - 1];
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
i = tagEnd + 1;
|
|
634
|
+
} else {
|
|
635
|
+
// Text content
|
|
636
|
+
const nextTag = html.indexOf('<', i);
|
|
637
|
+
const textContent = nextTag === -1 ? html.substring(i) : html.substring(i, nextTag);
|
|
638
|
+
|
|
639
|
+
if (textContent.trim()) {
|
|
640
|
+
const textNode = new XhtmlNode(NodeType.Text);
|
|
641
|
+
textNode.content = textContent;
|
|
642
|
+
current.children.push(textNode);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
i = nextTag === -1 ? html.length : nextTag;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// Return children of the wrapper div
|
|
650
|
+
return nodes.length > 0 && nodes[0].childNodes ? nodes[0].childNodes : nodes;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
closeScript() {
|
|
654
|
+
if (!this.namedParams) {
|
|
655
|
+
throw new Error('Sequence Error - script is not already open');
|
|
656
|
+
}
|
|
657
|
+
this.namedParams = null;
|
|
658
|
+
this.namedParamValues = null;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* Process markdown content and add it as HTML child nodes
|
|
663
|
+
* @param {string} md - Markdown content to process
|
|
664
|
+
* @returns {XhtmlNode} - this node for chaining
|
|
665
|
+
*/
|
|
666
|
+
markdown(md) {
|
|
667
|
+
if (!md) {
|
|
668
|
+
return this;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
const commonmark = require('commonmark');
|
|
672
|
+
const reader = new commonmark.Parser();
|
|
673
|
+
const writer = new commonmark.HtmlRenderer({ safe: true });
|
|
674
|
+
|
|
675
|
+
const parsed = reader.parse(md);
|
|
676
|
+
const html = writer.render(parsed);
|
|
677
|
+
|
|
678
|
+
// Parse the HTML and add as children
|
|
679
|
+
const nodes = this.#parseFragment(`<div>${html}</div>`);
|
|
680
|
+
for (const node of nodes) {
|
|
681
|
+
this.childNodes.push(node);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
return this;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* Process markdown content and add it inline (strips block-level wrapper)
|
|
689
|
+
* Useful when you want to add markdown content within a paragraph
|
|
690
|
+
* @param {string} md - Markdown content to process
|
|
691
|
+
* @returns {XhtmlNode} - this node for chaining
|
|
692
|
+
*/
|
|
693
|
+
markdownInline(md) {
|
|
694
|
+
if (!md) {
|
|
695
|
+
return this;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
const commonmark = require('commonmark');
|
|
699
|
+
const reader = new commonmark.Parser();
|
|
700
|
+
const writer = new commonmark.HtmlRenderer({ safe: true });
|
|
701
|
+
|
|
702
|
+
const parsed = reader.parse(md);
|
|
703
|
+
const html = writer.render(parsed);
|
|
704
|
+
|
|
705
|
+
// Strip outer <p> tags if present for inline usage
|
|
706
|
+
const trimmedHtml = html.trim().replace(/^<p>/, '').replace(/<\/p>\s*$/, '');
|
|
707
|
+
|
|
708
|
+
// Parse the HTML and add as children
|
|
709
|
+
const nodes = this.#parseFragment(`<span>${trimmedHtml}</span>`);
|
|
710
|
+
for (const node of nodes) {
|
|
711
|
+
// Add children of the wrapper span, not the span itself
|
|
712
|
+
for (const child of node.childNodes) {
|
|
713
|
+
this.childNodes.push(child);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
return this;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
render(indent = 0, pretty = true) {
|
|
721
|
+
const effectivePretty = pretty && this.pretty;
|
|
722
|
+
const indentStr = effectivePretty ? ' '.repeat(indent) : '';
|
|
723
|
+
const newline = effectivePretty ? '\n' : '';
|
|
724
|
+
|
|
725
|
+
if (this.nodeType === NodeType.Text) {
|
|
726
|
+
return this.#escapeHtml(this.content || '');
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
if (this.nodeType === NodeType.Comment) {
|
|
730
|
+
return `${indentStr}<!-- ${this.content || ''} -->${newline}`;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
if (this.nodeType === NodeType.Element) {
|
|
734
|
+
const voidElements = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
|
|
735
|
+
'link', 'meta', 'param', 'source', 'track', 'wbr'];
|
|
736
|
+
const isVoid = voidElements.includes(this.name);
|
|
737
|
+
|
|
738
|
+
let attrs = '';
|
|
739
|
+
for (const [key, value] of this.attributes) {
|
|
740
|
+
attrs += ` ${key}="${this.#escapeAttr(value)}"`;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
if (isVoid) {
|
|
744
|
+
return `${indentStr}<${this.name}${attrs}/>${newline}`;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
if (this.childNodes.length === 0) {
|
|
748
|
+
return `${indentStr}<${this.name}${attrs}></${this.name}>${newline}`;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// Check if all children are text/inline
|
|
752
|
+
const allInline = this.childNodes.every(c =>
|
|
753
|
+
c.nodeType === NodeType.Text || !c.pretty
|
|
754
|
+
);
|
|
755
|
+
|
|
756
|
+
if (allInline || !effectivePretty) {
|
|
757
|
+
let content = '';
|
|
758
|
+
for (const child of this.childNodes) {
|
|
759
|
+
content += child.render(0, false);
|
|
760
|
+
}
|
|
761
|
+
return `${indentStr}<${this.name}${attrs}>${content}</${this.name}>${newline}`;
|
|
762
|
+
} else {
|
|
763
|
+
let content = '';
|
|
764
|
+
for (const child of this.childNodes) {
|
|
765
|
+
content += child.render(indent + 1, true);
|
|
766
|
+
}
|
|
767
|
+
return `${indentStr}<${this.name}${attrs}>${newline}${content}${indentStr}</${this.name}>${newline}`;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
return '';
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
#escapeHtml(text) {
|
|
775
|
+
return text
|
|
776
|
+
.replace(/&/g, '&')
|
|
777
|
+
.replace(/</g, '<')
|
|
778
|
+
.replace(/>/g, '>');
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
#escapeAttr(text) {
|
|
782
|
+
return String(text)
|
|
783
|
+
.replace(/&/g, '&')
|
|
784
|
+
.replace(/</g, '<')
|
|
785
|
+
.replace(/>/g, '>')
|
|
786
|
+
.replace(/"/g, '"');
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
toString() {
|
|
790
|
+
return this.render(0, true);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
toStringPretty() {
|
|
794
|
+
return this.render(0, true);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
toStringCompact() {
|
|
798
|
+
return this.render(0, false);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// Factory functions
|
|
803
|
+
function div(style = null) {
|
|
804
|
+
const node = new XhtmlNode(NodeType.Element, 'div');
|
|
805
|
+
node.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
|
|
806
|
+
if (style) {
|
|
807
|
+
node.setAttribute('style', style);
|
|
808
|
+
}
|
|
809
|
+
return node;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
function element(name) {
|
|
813
|
+
return new XhtmlNode(NodeType.Element, name);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
function text(content) {
|
|
817
|
+
const node = new XhtmlNode(NodeType.Text);
|
|
818
|
+
node.content = content;
|
|
819
|
+
return node;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
function comment(content) {
|
|
823
|
+
const node = new XhtmlNode(NodeType.Comment);
|
|
824
|
+
node.content = content;
|
|
825
|
+
return node;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
module.exports = {
|
|
829
|
+
XhtmlNode,
|
|
830
|
+
NodeType,
|
|
831
|
+
div,
|
|
832
|
+
element,
|
|
833
|
+
text,
|
|
834
|
+
comment
|
|
835
|
+
};
|