This repository has been archived by the owner on Feb 14, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmicroVDom.js
188 lines (188 loc) · 5.24 KB
/
microVDom.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// microVDom - JavaScript Version
var microDocument = (function () {
// Node Types
const ELEMENT_NODE = 1;
const TEXT_NODE = 3;
const COMMENT_NODE = 8;
const DOCUMENT_NODE = 9;
const DOCUMENT_TYPE_NODE = 10;
const SELF_CLOSING_TAGS = [
"area",
"base",
"br",
"col",
"command",
"embed",
"hr",
"img",
"input",
"keygen",
"link",
"meta",
"param",
"source",
"track",
"wbr"
];
function compose(parameter, ...functions) {
for (var curFunc of functions) {
parameter = curFunc(parameter);
}
return parameter;
}
function htmlSpecialChars(string) {
return compose(string,
(s) => s.replace(/&/g, "&"),
(s) => s.replace(/"/g, """),
(s) => s.replace(/'/g, "'"),
(s) => s.replace(/</g, "<"),
(s) => s.replace(/>/g, ">")
);
}
// The DocumentType interface represents a Node containing a doctype.
function documentType(type = "html") {
this.nodeType = DOCUMENT_TYPE_NODE;
this.docType = type;
}
documentType.prototype.render = function () {
return "<!DOCTYPE " + this.docType.toUpperCase() + ">\n";
};
// The Text interface represents the textual content of Elements
function text(string = "") {
this.nodeType = TEXT_NODE;
this.data = string;
}
text.prototype.render = function () {
return htmlSpecialChars(this.data);
};
function htmlBlob(tagString) {
this.data = tagString;
}
htmlBlob.prototype.render = function () {
return this.data;
};
function comment(string) {
this.nodeType = COMMENT_NODE;
this.data = string;
}
comment.prototype.render = function () {
return "<!--" + htmlSpecialChars(this.data) + "-->\n";
};
// This type represents a DOM element's attribute as an object.
function attr(name, value) {
this.name = name;
this.value = value;
}
attr.prototype.render = function () {
return " " + this.name + "=\"" + this.value + "\"";
};
function parentNode() {
// Contains all Elements that are children of this ParentNode.
this.children = [];
this.childElementCount = 0;
}
parentNode.prototype.appendOneChild = function (node) {
if ((typeof node) === "string") {
this.children.push(new text(node));
} else if ("nodeType" in node) {
this.children.push(node);
}
};
parentNode.prototype.prependOneChild = function (node) {
if ((typeof node) === "string") {
this.children.unshift(new text(node));
} else if ("nodeType" in node) {
this.children.unshift(node);
}
};
parentNode.prototype.addChildren = function (nodes, append = true) {
var nodesToAdd = (Array.isArray(nodes) ? nodes : [nodes]);
for (var node of nodesToAdd) {
this[(append ? "append" : "prepend") + "OneChild"](node);
this.childElementCount++;
}
};
parentNode.prototype.appendChild = function (nodes) {
this.addChildren(nodes, true);
};
parentNode.prototype.prependChild = function (nodes) {
this.addChildren(nodes, false);
};
function element(tagName, attrMap = null) {
parentNode.call(this);
this.nodeType = ELEMENT_NODE;
this.attributes = [];
this.tagName = tagName;
this.selfClosing = SELF_CLOSING_TAGS.indexOf(tagName) !== -1;
if (attrMap !== null && Array.isArray(attrMap)) {
attrMap.forEach((value, name) => this.setAttribute(value, name));
}
}
element.prototype = Object.create(parentNode.prototype);
element.prototype.setAttribute = function (attribute, value = "") {
if (attribute instanceof attr) {
this.attributes[attribute.name] = attribute;
} else if ((typeof attribute) === "string") {
this.attributes[attribute.name] = new attr(attribute, value);
}
};
element.prototype.render = function () {
var openTag = "<" + this.tagName;
if (this.attributes.length > 0) {
for (var attr of this.attributes) {
openTag += attr.render();
}
}
openTag += ">\n";
if (this.selfClosing) {
return openTag;
}
var contents = "";
if (this.children.length > 0) {
for (var childNode of this.children) {
contents += childNode.render();
}
}
var closeTag = "</" + this.tagName + ">\n";
return openTag + contents + closeTag;
};
function microDocument(docType = "html") {
parentNode.call(this);
this.characterSet = "UTF-8";
this.docType = new documentType(docType);
this.nodeType = DOCUMENT_NODE;
this.documentElement = this.createElement("html");
this.head = this.createElement("head");
this.body = this.createElement("body");
this.documentElement.appendChild([this.head, this.body]);
this.appendChild([this.docType, this.documentElement]);
}
microDocument.prototype = Object.create(parentNode.prototype);
microDocument.prototype.createAttribute = function (name, value) {
return new attr(name, value);
};
microDocument.prototype.createComment = function (string = "") {
return new comment(string);
};
microDocument.prototype.createElement = function (tagName, attrMap = null) {
return new element(tagName, attrMap);
};
microDocument.prototype.createTextNode = function (string = "") {
return new text(string);
};
microDocument.prototype.createHtmlBlob = function (tagString) {
return new htmlBlob(tagString);
};
microDocument.prototype.render = function () {
var html = "";
for (var childNode of this.children) {
html += childNode.render();
}
return html;
};
return microDocument;
})();
// NodeJS `require` compatibility
if (typeof module !== "undefined") {
module.exports = microDocument;
}