@litejs/dom 23.12.1 → 24.7.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/README.md +15 -17
- package/css.js +32 -0
- package/dom.js +21 -32
- package/net.js +4 -2
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
LiteJS DOM – [![Coverage][1]][2] [![Size][3]][4] [![Buy Me A Tea][5]][6]
|
|
11
11
|
==========
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Dependency-free DOM library for handling HTML files on server-side.
|
|
14
14
|
[DOM spec](https://dom.spec.whatwg.org/) |
|
|
15
15
|
[Selectors Level 3](http://www.w3.org/TR/selectors/)
|
|
16
16
|
|
|
@@ -20,18 +20,6 @@ Examples
|
|
|
20
20
|
|
|
21
21
|
```javascript
|
|
22
22
|
const { document, DOMParser, XMLSerializer } = require("@litejs/dom");
|
|
23
|
-
const { XMLHttpRequest } = require("@litejs/dom/net.js");
|
|
24
|
-
|
|
25
|
-
// Use XMLHttpRequest in server side
|
|
26
|
-
var xhr = new XMLHttpRequest()
|
|
27
|
-
xhr.open("GET", "https://litejs.com")
|
|
28
|
-
xhr.responseType = "document"
|
|
29
|
-
xhr.onload = function() {
|
|
30
|
-
var doc = xhr.responseXML
|
|
31
|
-
// Work with DOM in familiar way
|
|
32
|
-
console.log(doc.querySelector("title").textContent)
|
|
33
|
-
}
|
|
34
|
-
xhr.send()
|
|
35
23
|
|
|
36
24
|
// Build DOM manually
|
|
37
25
|
const el = document.createElement("h1");
|
|
@@ -40,11 +28,9 @@ el.className = "large";
|
|
|
40
28
|
|
|
41
29
|
const fragment = document.createDocumentFragment();
|
|
42
30
|
fragment.appendChild(document.createTextNode("hello"));
|
|
43
|
-
fragment.appendChild(document.createTextNode(" world"));
|
|
44
31
|
el.appendChild(fragment);
|
|
45
32
|
|
|
46
|
-
|
|
47
|
-
// hello world
|
|
33
|
+
// Replace the DOM tree with parsed HTML
|
|
48
34
|
el.innerHTML = "<b>hello world</b>";
|
|
49
35
|
el.toString();
|
|
50
36
|
// <h1 id="123" class="large"><b>hello world</b></h1>
|
|
@@ -55,6 +41,18 @@ el.toString(true);
|
|
|
55
41
|
|
|
56
42
|
el.querySelectorAll("b");
|
|
57
43
|
// [ "<b>hello world</b>" ]
|
|
44
|
+
|
|
45
|
+
// Use XMLHttpRequest in server side
|
|
46
|
+
const { XMLHttpRequest } = require("@litejs/dom/net.js");
|
|
47
|
+
const xhr = new XMLHttpRequest();
|
|
48
|
+
xhr.open("GET", "https://litejs.com");
|
|
49
|
+
xhr.responseType = "document";
|
|
50
|
+
xhr.onload = function() {
|
|
51
|
+
const document = xhr.responseXML;
|
|
52
|
+
// Work with DOM in familiar way
|
|
53
|
+
console.log(document.querySelector("title").textContent);
|
|
54
|
+
}
|
|
55
|
+
xhr.send();
|
|
58
56
|
```
|
|
59
57
|
|
|
60
58
|
## Contributing
|
|
@@ -63,7 +61,7 @@ Follow [Coding Style Guide](https://github.com/litejs/litejs/wiki/Style-Guide),
|
|
|
63
61
|
run tests `npm install; npm test`.
|
|
64
62
|
|
|
65
63
|
|
|
66
|
-
> Copyright (c) 2014-
|
|
64
|
+
> Copyright (c) 2014-2024 Lauri Rooden <lauri@rooden.ee>
|
|
67
65
|
[MIT License](https://litejs.com/MIT-LICENSE.txt) |
|
|
68
66
|
[GitHub repo](https://github.com/litejs/dom) |
|
|
69
67
|
[npm package](https://npmjs.org/package/@litejs/dom) |
|
package/css.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
/*! litejs.com/MIT-LICENSE.txt */
|
|
3
|
+
|
|
4
|
+
exports.CSSStyleDeclaration = CSSStyleDeclaration
|
|
5
|
+
|
|
6
|
+
// CSSStyleDeclaration is a single CSS declaration block,
|
|
7
|
+
// accessible via HTMLElement.style for inline styles, document.styleSheets[0].cssRules[0].style, and getComputedStyle()
|
|
8
|
+
function CSSStyleDeclaration(style) {
|
|
9
|
+
this.cssText = style
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
CSSStyleDeclaration.prototype = {
|
|
13
|
+
get cssText() {
|
|
14
|
+
return Object.keys(this).map(function(key) {
|
|
15
|
+
return (key === "cssFloat" ? "float:" : hyphenCase(key) + ":") + this[key]
|
|
16
|
+
}, this).join(";")
|
|
17
|
+
},
|
|
18
|
+
set cssText(style) {
|
|
19
|
+
for (var m, re = /(?:^|;)\s*([-a-z]+)\s*:((?:("|')(?:\\.|(?!\3)[^\\])*?\3|[^"';])+)(?=;|$)/ig; (m = re.exec(style)); ) {
|
|
20
|
+
this[m[1] === "float" ? "cssFloat" : camelCase(m[1])] = m[2].trim()
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function camelCase(str) {
|
|
26
|
+
return str.replace(/-([a-z])/g, function(_, a) { return a.toUpperCase() })
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function hyphenCase(str) {
|
|
30
|
+
return str.replace(/[A-Z]/g, "-$&").toLowerCase()
|
|
31
|
+
}
|
|
32
|
+
|
package/dom.js
CHANGED
|
@@ -16,6 +16,7 @@ var boolAttrs = {
|
|
|
16
16
|
, rawTextElements = { SCRIPT: /<(?=\/script)/i, STYLE: /<(?=\/style)/i }
|
|
17
17
|
, rawTextEscape = { SCRIPT: /<(?=\/script|!--)/ig, STYLE: /<(?=\/style|!--)/ig }
|
|
18
18
|
, hasOwn = voidElements.hasOwnProperty
|
|
19
|
+
, CSSStyleDeclaration = require("./css.js").CSSStyleDeclaration
|
|
19
20
|
, selector = require("./selector.js")
|
|
20
21
|
, Node = {
|
|
21
22
|
ELEMENT_NODE: 1,
|
|
@@ -83,6 +84,7 @@ var boolAttrs = {
|
|
|
83
84
|
if ((re = rawTextElements[child.tagName])) {
|
|
84
85
|
for (text = ""; (m = tagRe.exec(html)) && !re.test(m[0]); text += m[3] || m[0]);
|
|
85
86
|
child.textContent = text.replace(unescRe, unescFn)
|
|
87
|
+
if (!m) break
|
|
86
88
|
} else if (!voidElements[child.tagName] && !m[8]) tree = child
|
|
87
89
|
} else {
|
|
88
90
|
tree.appendChild(
|
|
@@ -110,7 +112,7 @@ var boolAttrs = {
|
|
|
110
112
|
return this._style || (this._style = new CSSStyleDeclaration(this.getAttribute("style") || ""))
|
|
111
113
|
},
|
|
112
114
|
set style(value) {
|
|
113
|
-
this.
|
|
115
|
+
this.style.cssText = value
|
|
114
116
|
},
|
|
115
117
|
contains: function (el) {
|
|
116
118
|
for (; el; el = el.parentNode) if (el === this) return true
|
|
@@ -182,9 +184,9 @@ var boolAttrs = {
|
|
|
182
184
|
return selector.find(this, sel)
|
|
183
185
|
},
|
|
184
186
|
toString: function(minify) {
|
|
185
|
-
return rawTextElements[this.tagName] ? this.textContent : this.
|
|
187
|
+
return rawTextElements[this.tagName] ? this.textContent : this.childNodes.reduce(function(memo, node) {
|
|
186
188
|
return memo + node.toString(minify)
|
|
187
|
-
}, "")
|
|
189
|
+
}, "")
|
|
188
190
|
}
|
|
189
191
|
}
|
|
190
192
|
, Element = {
|
|
@@ -209,7 +211,7 @@ var boolAttrs = {
|
|
|
209
211
|
return attr ? attr.value : null
|
|
210
212
|
},
|
|
211
213
|
setAttribute: function(name, value) {
|
|
212
|
-
this.attributes.setNamedItem(name, value)
|
|
214
|
+
this.attributes.setNamedItem(new Attr(this, name, value))
|
|
213
215
|
},
|
|
214
216
|
removeAttribute: function(name) {
|
|
215
217
|
this.attributes.removeNamedItem(name)
|
|
@@ -286,8 +288,7 @@ NamedNodeMap.prototype = {
|
|
|
286
288
|
, attr = this[loName] || null
|
|
287
289
|
if (loName === "style" && this.ownerElement._style) {
|
|
288
290
|
if (attr === null) attr = this[loName] = new Attr(this.ownerElement, name, "")
|
|
289
|
-
attr.value = this.ownerElement._style.
|
|
290
|
-
delete this.ownerElement._style
|
|
291
|
+
attr.value = this.ownerElement._style.cssText
|
|
291
292
|
}
|
|
292
293
|
return attr
|
|
293
294
|
},
|
|
@@ -298,11 +299,11 @@ NamedNodeMap.prototype = {
|
|
|
298
299
|
if (attr !== null) delete this[loName]
|
|
299
300
|
return attr
|
|
300
301
|
},
|
|
301
|
-
setNamedItem: function(
|
|
302
|
-
this.
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
302
|
+
setNamedItem: function(attr) {
|
|
303
|
+
var oldAttr = this.getNamedItem(attr.name)
|
|
304
|
+
if (attr.name === "style") attr.value = new CSSStyleDeclaration(attr.value).cssText
|
|
305
|
+
this[attr.name] = attr
|
|
306
|
+
return oldAttr
|
|
306
307
|
},
|
|
307
308
|
toString: function(minify) {
|
|
308
309
|
var map = this
|
|
@@ -315,6 +316,7 @@ NamedNodeMap.prototype = {
|
|
|
315
316
|
if (!isXml) {
|
|
316
317
|
if (hasOwn.call(boolAttrs, loName)) return name
|
|
317
318
|
if (minify) {
|
|
319
|
+
value = loName.slice(0, 2) === "on" ? value.replace(/^[\s\uFEFF\xA0;]+|[\s\uFEFF\xA0;]+$/g, "") : value.replace(/\s+/g, " ").trim()
|
|
318
320
|
if (hasOwn.call(defaultAttrs, (tagName + " " + name + " " + value).toLowerCase())) return
|
|
319
321
|
if (!quotedAttrRe.test(value)) return name + "=" + value
|
|
320
322
|
if (value.split("\"").length > value.split("'").length) return name + "='" + value.replace(/'/g, "'") + "'"
|
|
@@ -325,18 +327,6 @@ NamedNodeMap.prototype = {
|
|
|
325
327
|
}
|
|
326
328
|
}
|
|
327
329
|
|
|
328
|
-
function CSSStyleDeclaration(style) {
|
|
329
|
-
for (var m, re = /(?:^|;)\s*([-a-z]+)\s*:((?:("|')(?:\\.|(?!\3)[^\\])*?\3|[^"';])+)(?=;|$)/ig; (m = re.exec(style)); ) {
|
|
330
|
-
this[m[1] === "float" ? "cssFloat" : camelCase(m[1])] = m[2].trim()
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
CSSStyleDeclaration.prototype.valueOf = function() {
|
|
335
|
-
return Object.keys(this).map(function(key) {
|
|
336
|
-
return (key === "cssFloat" ? "float:" : hyphenCase(key) + ":") + this[key]
|
|
337
|
-
}, this).join(";")
|
|
338
|
-
}
|
|
339
|
-
|
|
340
330
|
function DocumentFragment() {
|
|
341
331
|
this.childNodes = []
|
|
342
332
|
}
|
|
@@ -430,6 +420,14 @@ function Document() {
|
|
|
430
420
|
}
|
|
431
421
|
|
|
432
422
|
extendNode(Document, Element, {
|
|
423
|
+
get title() {
|
|
424
|
+
var el = selector.find(this, "title", 1)
|
|
425
|
+
return el && el.textContent || ""
|
|
426
|
+
},
|
|
427
|
+
set title(text) {
|
|
428
|
+
var el = selector.find(this, "title", 1) || this.appendChild(this.createElement("title"))
|
|
429
|
+
el.textContent = text
|
|
430
|
+
},
|
|
433
431
|
nodeType: 9,
|
|
434
432
|
nodeName: "#document",
|
|
435
433
|
contentType: "text/html",
|
|
@@ -492,17 +490,8 @@ function getSibling(node, step, type) {
|
|
|
492
490
|
return type > 0 ? getElement(silbings, index + step, step, type) : silbings && silbings[index + step] || null
|
|
493
491
|
}
|
|
494
492
|
|
|
495
|
-
function camelCase(str) {
|
|
496
|
-
return str.replace(/-([a-z])/g, function(_, a) { return a.toUpperCase() })
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
function hyphenCase(str) {
|
|
500
|
-
return str.replace(/[A-Z]/g, "-$&").toLowerCase()
|
|
501
|
-
}
|
|
502
|
-
|
|
503
493
|
exports.document = new Document()
|
|
504
494
|
exports.entities = entities
|
|
505
|
-
exports.CSSStyleDeclaration = CSSStyleDeclaration
|
|
506
495
|
exports.DOMParser = DOMParser
|
|
507
496
|
exports.Document = Document
|
|
508
497
|
exports.DocumentFragment = DocumentFragment
|
package/net.js
CHANGED
|
@@ -87,11 +87,13 @@ XMLHttpRequest.prototype = {
|
|
|
87
87
|
result[entrie[0]] = entrie[1]
|
|
88
88
|
return result
|
|
89
89
|
}, {})
|
|
90
|
-
require(url.protocol.slice(0, -1)).request(url, function(res) {
|
|
90
|
+
var req = require(url.protocol.slice(0, -1)).request(url, function(res) {
|
|
91
91
|
head(res.statusCode, res.statusMessage, res.headers)
|
|
92
92
|
res.on("data", fillBody)
|
|
93
93
|
res.on("end", done)
|
|
94
|
-
})
|
|
94
|
+
})
|
|
95
|
+
if (xhr.onerror) req.on("error", xhr.onerror)
|
|
96
|
+
req.end(data)
|
|
95
97
|
return
|
|
96
98
|
}
|
|
97
99
|
if (url.protocol === "data:") {
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@litejs/dom",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "24.7.0",
|
|
4
4
|
"description": "A small DOM library for server-side testing, rendering, and handling of HTML files",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Lauri Rooden <lauri@rooden.ee>",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"document",
|
|
9
9
|
"dom",
|
|
10
|
+
"html",
|
|
10
11
|
"DOMParser",
|
|
11
12
|
"XMLHttpRequest",
|
|
12
13
|
"XMLSerializer",
|
|
@@ -17,12 +18,11 @@
|
|
|
17
18
|
"*.js"
|
|
18
19
|
],
|
|
19
20
|
"scripts": {
|
|
20
|
-
"
|
|
21
|
-
"test
|
|
21
|
+
"lint": "npx jshint -c .github/jshint.json *.js",
|
|
22
|
+
"test": "lj t test/*.js"
|
|
22
23
|
},
|
|
23
24
|
"repository": "github:litejs/dom",
|
|
24
25
|
"devDependencies": {
|
|
25
|
-
"@litejs/cli": "23.11.1"
|
|
26
|
-
"jshint": "2.13.6"
|
|
26
|
+
"@litejs/cli": "23.11.1"
|
|
27
27
|
}
|
|
28
28
|
}
|