pseudo-dom 0.9.0 → 0.11.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 +918 -18
- package/browser/pseudo-dom.js +3296 -604
- package/browser/pseudo-dom.min.js +1 -1
- package/dist/factories/createDataset.d.ts +10 -10
- package/dist/factories/createDataset.js +78 -78
- package/dist/factories/createStyleDeclaration.d.ts +30 -30
- package/dist/factories/createStyleDeclaration.js +64 -64
- package/dist/factories/parseHTML.d.ts +13 -0
- package/dist/factories/parseHTML.js +84 -0
- package/dist/factories/parseHTML.min.js +1 -0
- package/dist/factories/serializeHTML.d.ts +15 -0
- package/dist/factories/serializeHTML.js +114 -0
- package/dist/factories/serializeHTML.min.js +1 -0
- package/dist/interfaces/PseudoCSSStyleDeclaration.d.ts +14 -14
- package/dist/interfaces/PseudoCSSStyleDeclaration.js +5 -5
- package/dist/interfaces/PseudoElement.d.ts +765 -702
- package/dist/interfaces/PseudoHTMLElement.d.ts +33 -33
- package/dist/interfaces/PseudoShadowRoot.d.ts +9 -0
- package/dist/services/CSSStyleDeclarationService.d.ts +73 -73
- package/dist/services/CSSStyleDeclarationService.js +156 -156
- package/dist/services/ElementService.d.ts +371 -191
- package/dist/services/ElementService.js +732 -426
- package/dist/services/ElementService.min.js +1 -1
- package/dist/services/HTMLElementService.d.ts +32 -0
- package/dist/services/HTMLElementService.js +67 -0
- package/dist/services/HTMLElementService.min.js +1 -1
- package/dist/services/NodeService.d.ts +8 -0
- package/dist/services/NodeService.js +11 -0
- package/dist/services/NodeService.min.js +1 -1
- package/dist/services/ShadowRootService.d.ts +12 -0
- package/dist/services/ShadowRootService.js +16 -1
- package/dist/services/ShadowRootService.min.js +1 -1
- package/package.json +2 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A live DOMStringMap-like object for an element's data-* attributes.
|
|
3
|
-
* @memberOf module:factories
|
|
4
|
-
* @param {*} element The element whose data-* attributes this reflects
|
|
5
|
-
* @returns {Object.<string, string>}
|
|
6
|
-
*/
|
|
7
|
-
declare const createDataset: (element: any) => {
|
|
8
|
-
[key: string]: string;
|
|
9
|
-
};
|
|
10
|
-
export default createDataset;
|
|
1
|
+
/**
|
|
2
|
+
* A live DOMStringMap-like object for an element's data-* attributes.
|
|
3
|
+
* @memberOf module:factories
|
|
4
|
+
* @param {*} element The element whose data-* attributes this reflects
|
|
5
|
+
* @returns {Object.<string, string>}
|
|
6
|
+
*/
|
|
7
|
+
declare const createDataset: (element: any) => {
|
|
8
|
+
[key: string]: string;
|
|
9
|
+
};
|
|
10
|
+
export default createDataset;
|
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
require('core-js/modules/esnext.iterator.constructor.js')
|
|
4
|
-
require('core-js/modules/esnext.iterator.map.js')
|
|
5
|
-
Object.defineProperty(exports, '__esModule', {
|
|
6
|
-
value: true
|
|
7
|
-
})
|
|
8
|
-
/**
|
|
9
|
-
* @file Wraps an element in a Proxy which behaves like the DOM's DOMStringMap (element.dataset): a live view of its
|
|
10
|
-
* data-* attributes, under their camelCase names, backed by the element's own getAttribute / setAttribute /
|
|
11
|
-
* hasAttribute / removeAttribute (nothing is stored separately, so it can never fall out of sync with the
|
|
12
|
-
* attributes).
|
|
13
|
-
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
14
|
-
* @version 1.0.0
|
|
15
|
-
*/
|
|
16
|
-
const createStyleDeclaration_1 = require('./createStyleDeclaration')
|
|
17
|
-
const DATA_PREFIX = 'data-'
|
|
18
|
-
const attributeName = property => `${DATA_PREFIX}${(0, createStyleDeclaration_1.camelToKebab)(property)}`
|
|
19
|
-
/**
|
|
20
|
-
* Every data-* attribute name currently on the element, as [attributeName, camelCaseName] pairs.
|
|
21
|
-
* @param {*} element
|
|
22
|
-
* @returns {Array<Array<string>>}
|
|
23
|
-
*/
|
|
24
|
-
const dataAttributes = element => {
|
|
25
|
-
const names = []
|
|
26
|
-
for (let index = 0; index < element.attributes.length; index++) {
|
|
27
|
-
const name = element.attributes.item(index).name
|
|
28
|
-
if (name.indexOf(DATA_PREFIX) === 0 && name.length > DATA_PREFIX.length) {
|
|
29
|
-
names.push([name, (0, createStyleDeclaration_1.kebabToCamel)(name.slice(DATA_PREFIX.length))])
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return names
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* A live DOMStringMap-like object for an element's data-* attributes.
|
|
36
|
-
* @memberOf module:factories
|
|
37
|
-
* @param {*} element The element whose data-* attributes this reflects
|
|
38
|
-
* @returns {Object.<string, string>}
|
|
39
|
-
*/
|
|
40
|
-
const createDataset = element => new Proxy({}, {
|
|
41
|
-
get (_target, property) {
|
|
42
|
-
if (typeof property !== 'string') {
|
|
43
|
-
return undefined
|
|
44
|
-
}
|
|
45
|
-
const value = element.getAttribute(attributeName(property))
|
|
46
|
-
return value === null ? undefined : value
|
|
47
|
-
},
|
|
48
|
-
set (_target, property, value) {
|
|
49
|
-
if (typeof property !== 'string') {
|
|
50
|
-
return false
|
|
51
|
-
}
|
|
52
|
-
element.setAttribute(attributeName(property), String(value))
|
|
53
|
-
return true
|
|
54
|
-
},
|
|
55
|
-
deleteProperty (_target, property) {
|
|
56
|
-
if (typeof property === 'string') {
|
|
57
|
-
element.removeAttribute(attributeName(property))
|
|
58
|
-
}
|
|
59
|
-
return true
|
|
60
|
-
},
|
|
61
|
-
has (_target, property) {
|
|
62
|
-
return typeof property === 'string' && element.hasAttribute(attributeName(property))
|
|
63
|
-
},
|
|
64
|
-
ownKeys () {
|
|
65
|
-
return dataAttributes(element).map(([, camelCaseName]) => camelCaseName)
|
|
66
|
-
},
|
|
67
|
-
getOwnPropertyDescriptor (_target, property) {
|
|
68
|
-
if (typeof property !== 'string' || !element.hasAttribute(attributeName(property))) {
|
|
69
|
-
return undefined
|
|
70
|
-
}
|
|
71
|
-
return {
|
|
72
|
-
enumerable: true,
|
|
73
|
-
configurable: true,
|
|
74
|
-
value: element.getAttribute(attributeName(property))
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
})
|
|
78
|
-
exports.default = createDataset
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
require('core-js/modules/esnext.iterator.constructor.js')
|
|
4
|
+
require('core-js/modules/esnext.iterator.map.js')
|
|
5
|
+
Object.defineProperty(exports, '__esModule', {
|
|
6
|
+
value: true
|
|
7
|
+
})
|
|
8
|
+
/**
|
|
9
|
+
* @file Wraps an element in a Proxy which behaves like the DOM's DOMStringMap (element.dataset): a live view of its
|
|
10
|
+
* data-* attributes, under their camelCase names, backed by the element's own getAttribute / setAttribute /
|
|
11
|
+
* hasAttribute / removeAttribute (nothing is stored separately, so it can never fall out of sync with the
|
|
12
|
+
* attributes).
|
|
13
|
+
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
14
|
+
* @version 1.0.0
|
|
15
|
+
*/
|
|
16
|
+
const createStyleDeclaration_1 = require('./createStyleDeclaration')
|
|
17
|
+
const DATA_PREFIX = 'data-'
|
|
18
|
+
const attributeName = property => `${DATA_PREFIX}${(0, createStyleDeclaration_1.camelToKebab)(property)}`
|
|
19
|
+
/**
|
|
20
|
+
* Every data-* attribute name currently on the element, as [attributeName, camelCaseName] pairs.
|
|
21
|
+
* @param {*} element
|
|
22
|
+
* @returns {Array<Array<string>>}
|
|
23
|
+
*/
|
|
24
|
+
const dataAttributes = element => {
|
|
25
|
+
const names = []
|
|
26
|
+
for (let index = 0; index < element.attributes.length; index++) {
|
|
27
|
+
const name = element.attributes.item(index).name
|
|
28
|
+
if (name.indexOf(DATA_PREFIX) === 0 && name.length > DATA_PREFIX.length) {
|
|
29
|
+
names.push([name, (0, createStyleDeclaration_1.kebabToCamel)(name.slice(DATA_PREFIX.length))])
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return names
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A live DOMStringMap-like object for an element's data-* attributes.
|
|
36
|
+
* @memberOf module:factories
|
|
37
|
+
* @param {*} element The element whose data-* attributes this reflects
|
|
38
|
+
* @returns {Object.<string, string>}
|
|
39
|
+
*/
|
|
40
|
+
const createDataset = element => new Proxy({}, {
|
|
41
|
+
get (_target, property) {
|
|
42
|
+
if (typeof property !== 'string') {
|
|
43
|
+
return undefined
|
|
44
|
+
}
|
|
45
|
+
const value = element.getAttribute(attributeName(property))
|
|
46
|
+
return value === null ? undefined : value
|
|
47
|
+
},
|
|
48
|
+
set (_target, property, value) {
|
|
49
|
+
if (typeof property !== 'string') {
|
|
50
|
+
return false
|
|
51
|
+
}
|
|
52
|
+
element.setAttribute(attributeName(property), String(value))
|
|
53
|
+
return true
|
|
54
|
+
},
|
|
55
|
+
deleteProperty (_target, property) {
|
|
56
|
+
if (typeof property === 'string') {
|
|
57
|
+
element.removeAttribute(attributeName(property))
|
|
58
|
+
}
|
|
59
|
+
return true
|
|
60
|
+
},
|
|
61
|
+
has (_target, property) {
|
|
62
|
+
return typeof property === 'string' && element.hasAttribute(attributeName(property))
|
|
63
|
+
},
|
|
64
|
+
ownKeys () {
|
|
65
|
+
return dataAttributes(element).map(([, camelCaseName]) => camelCaseName)
|
|
66
|
+
},
|
|
67
|
+
getOwnPropertyDescriptor (_target, property) {
|
|
68
|
+
if (typeof property !== 'string' || !element.hasAttribute(attributeName(property))) {
|
|
69
|
+
return undefined
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
enumerable: true,
|
|
73
|
+
configurable: true,
|
|
74
|
+
value: element.getAttribute(attributeName(property))
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
exports.default = createDataset
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Wraps a CSSStyleDeclarationService in a Proxy so arbitrary camelCase CSS properties (element.style.
|
|
3
|
-
* backgroundColor) work like the DOM's, on top of its real methods (getPropertyValue, setProperty, cssText, ...).
|
|
4
|
-
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
5
|
-
* @version 1.0.0
|
|
6
|
-
*/
|
|
7
|
-
import { CSSStyleDeclarationService } from '../services/CSSStyleDeclarationService';
|
|
8
|
-
/**
|
|
9
|
-
* kebab-case -> camelCase ("background-color" -> "backgroundColor").
|
|
10
|
-
* @param {string} name
|
|
11
|
-
* @returns {string}
|
|
12
|
-
*/
|
|
13
|
-
declare const kebabToCamel: (name: string) => string;
|
|
14
|
-
/**
|
|
15
|
-
* camelCase -> kebab-case ("backgroundColor" -> "background-color").
|
|
16
|
-
* @param {string} name
|
|
17
|
-
* @returns {string}
|
|
18
|
-
*/
|
|
19
|
-
declare const camelToKebab: (name: string) => string;
|
|
20
|
-
/**
|
|
21
|
-
* A live CSSStyleDeclaration-like object: its real methods (cssText, getPropertyValue, setProperty, ...) work as
|
|
22
|
-
* declared, and any other property name is treated as a camelCase CSS property (declaration.backgroundColor reads /
|
|
23
|
-
* writes the "background-color" declaration), matching what a real element.style supports.
|
|
24
|
-
* @memberOf module:factories
|
|
25
|
-
* @param {string} [cssText=''] Initial declarations
|
|
26
|
-
* @returns {CSSStyleDeclarationService}
|
|
27
|
-
*/
|
|
28
|
-
declare const createStyleDeclaration: (cssText?: string) => CSSStyleDeclarationService;
|
|
29
|
-
export { kebabToCamel, camelToKebab };
|
|
30
|
-
export default createStyleDeclaration;
|
|
1
|
+
/**
|
|
2
|
+
* @file Wraps a CSSStyleDeclarationService in a Proxy so arbitrary camelCase CSS properties (element.style.
|
|
3
|
+
* backgroundColor) work like the DOM's, on top of its real methods (getPropertyValue, setProperty, cssText, ...).
|
|
4
|
+
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
5
|
+
* @version 1.0.0
|
|
6
|
+
*/
|
|
7
|
+
import { CSSStyleDeclarationService } from '../services/CSSStyleDeclarationService';
|
|
8
|
+
/**
|
|
9
|
+
* kebab-case -> camelCase ("background-color" -> "backgroundColor").
|
|
10
|
+
* @param {string} name
|
|
11
|
+
* @returns {string}
|
|
12
|
+
*/
|
|
13
|
+
declare const kebabToCamel: (name: string) => string;
|
|
14
|
+
/**
|
|
15
|
+
* camelCase -> kebab-case ("backgroundColor" -> "background-color").
|
|
16
|
+
* @param {string} name
|
|
17
|
+
* @returns {string}
|
|
18
|
+
*/
|
|
19
|
+
declare const camelToKebab: (name: string) => string;
|
|
20
|
+
/**
|
|
21
|
+
* A live CSSStyleDeclaration-like object: its real methods (cssText, getPropertyValue, setProperty, ...) work as
|
|
22
|
+
* declared, and any other property name is treated as a camelCase CSS property (declaration.backgroundColor reads /
|
|
23
|
+
* writes the "background-color" declaration), matching what a real element.style supports.
|
|
24
|
+
* @memberOf module:factories
|
|
25
|
+
* @param {string} [cssText=''] Initial declarations
|
|
26
|
+
* @returns {CSSStyleDeclarationService}
|
|
27
|
+
*/
|
|
28
|
+
declare const createStyleDeclaration: (cssText?: string) => CSSStyleDeclarationService;
|
|
29
|
+
export { kebabToCamel, camelToKebab };
|
|
30
|
+
export default createStyleDeclaration;
|
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', {
|
|
4
|
-
value: true
|
|
5
|
-
})
|
|
6
|
-
exports.camelToKebab = exports.kebabToCamel = void 0
|
|
7
|
-
/**
|
|
8
|
-
* @file Wraps a CSSStyleDeclarationService in a Proxy so arbitrary camelCase CSS properties (element.style.
|
|
9
|
-
* backgroundColor) work like the DOM's, on top of its real methods (getPropertyValue, setProperty, cssText, ...).
|
|
10
|
-
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
11
|
-
* @version 1.0.0
|
|
12
|
-
*/
|
|
13
|
-
const CSSStyleDeclarationService_1 = require('../services/CSSStyleDeclarationService')
|
|
14
|
-
const isIndex = property => /^\d+$/.test(property)
|
|
15
|
-
/**
|
|
16
|
-
* kebab-case -> camelCase ("background-color" -> "backgroundColor").
|
|
17
|
-
* @param {string} name
|
|
18
|
-
* @returns {string}
|
|
19
|
-
*/
|
|
20
|
-
const kebabToCamel = name => name.replace(/-([a-z0-9])/gi, (_match, letter) => letter.toUpperCase())
|
|
21
|
-
exports.kebabToCamel = kebabToCamel
|
|
22
|
-
/**
|
|
23
|
-
* camelCase -> kebab-case ("backgroundColor" -> "background-color").
|
|
24
|
-
* @param {string} name
|
|
25
|
-
* @returns {string}
|
|
26
|
-
*/
|
|
27
|
-
const camelToKebab = name => name.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`)
|
|
28
|
-
exports.camelToKebab = camelToKebab
|
|
29
|
-
/**
|
|
30
|
-
* A live CSSStyleDeclaration-like object: its real methods (cssText, getPropertyValue, setProperty, ...) work as
|
|
31
|
-
* declared, and any other property name is treated as a camelCase CSS property (declaration.backgroundColor reads /
|
|
32
|
-
* writes the "background-color" declaration), matching what a real element.style supports.
|
|
33
|
-
* @memberOf module:factories
|
|
34
|
-
* @param {string} [cssText=''] Initial declarations
|
|
35
|
-
* @returns {CSSStyleDeclarationService}
|
|
36
|
-
*/
|
|
37
|
-
const createStyleDeclaration = (cssText = '') => {
|
|
38
|
-
const target = new CSSStyleDeclarationService_1.CSSStyleDeclarationService(cssText)
|
|
39
|
-
return new Proxy(target, {
|
|
40
|
-
get (declaration, property, receiver) {
|
|
41
|
-
if (typeof property !== 'string') {
|
|
42
|
-
return Reflect.get(declaration, property, receiver)
|
|
43
|
-
}
|
|
44
|
-
if (isIndex(property)) {
|
|
45
|
-
return declaration.item(Number(property))
|
|
46
|
-
}
|
|
47
|
-
if (property in declaration) {
|
|
48
|
-
return Reflect.get(declaration, property, receiver)
|
|
49
|
-
}
|
|
50
|
-
return declaration.getPropertyValue(camelToKebab(property))
|
|
51
|
-
},
|
|
52
|
-
set (declaration, property, value) {
|
|
53
|
-
if (typeof property !== 'string' || property === 'cssText') {
|
|
54
|
-
return Reflect.set(declaration, property, value)
|
|
55
|
-
}
|
|
56
|
-
declaration.setProperty(camelToKebab(property), value === null || typeof value === 'undefined' ? '' : String(value))
|
|
57
|
-
return true
|
|
58
|
-
},
|
|
59
|
-
has (declaration, property) {
|
|
60
|
-
return typeof property === 'string' && (property in declaration || declaration.getPropertyValue(camelToKebab(property)) !== '')
|
|
61
|
-
}
|
|
62
|
-
})
|
|
63
|
-
}
|
|
64
|
-
exports.default = createStyleDeclaration
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', {
|
|
4
|
+
value: true
|
|
5
|
+
})
|
|
6
|
+
exports.camelToKebab = exports.kebabToCamel = void 0
|
|
7
|
+
/**
|
|
8
|
+
* @file Wraps a CSSStyleDeclarationService in a Proxy so arbitrary camelCase CSS properties (element.style.
|
|
9
|
+
* backgroundColor) work like the DOM's, on top of its real methods (getPropertyValue, setProperty, cssText, ...).
|
|
10
|
+
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
11
|
+
* @version 1.0.0
|
|
12
|
+
*/
|
|
13
|
+
const CSSStyleDeclarationService_1 = require('../services/CSSStyleDeclarationService')
|
|
14
|
+
const isIndex = property => /^\d+$/.test(property)
|
|
15
|
+
/**
|
|
16
|
+
* kebab-case -> camelCase ("background-color" -> "backgroundColor").
|
|
17
|
+
* @param {string} name
|
|
18
|
+
* @returns {string}
|
|
19
|
+
*/
|
|
20
|
+
const kebabToCamel = name => name.replace(/-([a-z0-9])/gi, (_match, letter) => letter.toUpperCase())
|
|
21
|
+
exports.kebabToCamel = kebabToCamel
|
|
22
|
+
/**
|
|
23
|
+
* camelCase -> kebab-case ("backgroundColor" -> "background-color").
|
|
24
|
+
* @param {string} name
|
|
25
|
+
* @returns {string}
|
|
26
|
+
*/
|
|
27
|
+
const camelToKebab = name => name.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`)
|
|
28
|
+
exports.camelToKebab = camelToKebab
|
|
29
|
+
/**
|
|
30
|
+
* A live CSSStyleDeclaration-like object: its real methods (cssText, getPropertyValue, setProperty, ...) work as
|
|
31
|
+
* declared, and any other property name is treated as a camelCase CSS property (declaration.backgroundColor reads /
|
|
32
|
+
* writes the "background-color" declaration), matching what a real element.style supports.
|
|
33
|
+
* @memberOf module:factories
|
|
34
|
+
* @param {string} [cssText=''] Initial declarations
|
|
35
|
+
* @returns {CSSStyleDeclarationService}
|
|
36
|
+
*/
|
|
37
|
+
const createStyleDeclaration = (cssText = '') => {
|
|
38
|
+
const target = new CSSStyleDeclarationService_1.CSSStyleDeclarationService(cssText)
|
|
39
|
+
return new Proxy(target, {
|
|
40
|
+
get (declaration, property, receiver) {
|
|
41
|
+
if (typeof property !== 'string') {
|
|
42
|
+
return Reflect.get(declaration, property, receiver)
|
|
43
|
+
}
|
|
44
|
+
if (isIndex(property)) {
|
|
45
|
+
return declaration.item(Number(property))
|
|
46
|
+
}
|
|
47
|
+
if (property in declaration) {
|
|
48
|
+
return Reflect.get(declaration, property, receiver)
|
|
49
|
+
}
|
|
50
|
+
return declaration.getPropertyValue(camelToKebab(property))
|
|
51
|
+
},
|
|
52
|
+
set (declaration, property, value) {
|
|
53
|
+
if (typeof property !== 'string' || property === 'cssText') {
|
|
54
|
+
return Reflect.set(declaration, property, value)
|
|
55
|
+
}
|
|
56
|
+
declaration.setProperty(camelToKebab(property), value === null || typeof value === 'undefined' ? '' : String(value))
|
|
57
|
+
return true
|
|
58
|
+
},
|
|
59
|
+
has (declaration, property) {
|
|
60
|
+
return typeof property === 'string' && (property in declaration || declaration.getPropertyValue(camelToKebab(property)) !== '')
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
exports.default = createStyleDeclaration
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse an HTML string into the nodes it describes (siblings at the top level, exactly like the DOM's own HTML
|
|
3
|
+
* parsing does for innerHTML / insertAdjacentHTML - there is no single root unless the markup itself has one).
|
|
4
|
+
* @memberOf module:factories
|
|
5
|
+
* @param {string} html
|
|
6
|
+
* @param {*} ownerDocument The document the new nodes belong to (matches what innerHTML etc. would set), or null
|
|
7
|
+
* @param {function(new: *, {tagName: string})} ElementClass The class to build each parsed element with
|
|
8
|
+
* @returns {Array<*>}
|
|
9
|
+
*/
|
|
10
|
+
declare const parseHTML: (html: string, ownerDocument: any, ElementClass: new (options: {
|
|
11
|
+
tagName: string;
|
|
12
|
+
}) => any) => Array<any>;
|
|
13
|
+
export default parseHTML;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', {
|
|
4
|
+
value: true
|
|
5
|
+
})
|
|
6
|
+
/**
|
|
7
|
+
* @file Parses an HTML string into pseudo-dom nodes, for innerHTML / outerHTML / insertAdjacentHTML. Built on
|
|
8
|
+
* htmlparser2's Parser (a SAX-style tokenizer) with a custom handler which builds pseudo-dom nodes directly -
|
|
9
|
+
* htmlparser2's own default DomHandler / domutils tree (which this never uses) is stubbed out of the browser bundle
|
|
10
|
+
* by the browser.ignore config, the same way css-select's unused default adapter already is.
|
|
11
|
+
*
|
|
12
|
+
* The class to build parsed elements with is given by the caller (rather than imported here) so this has no
|
|
13
|
+
* dependency on ElementService / HTMLElementService - importing either here, from a factory ElementService itself
|
|
14
|
+
* would need to call, would create an import cycle.
|
|
15
|
+
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
16
|
+
* @version 1.0.0
|
|
17
|
+
*/
|
|
18
|
+
const htmlparser2_1 = require('htmlparser2')
|
|
19
|
+
const NodeService_1 = require('../services/NodeService')
|
|
20
|
+
/**
|
|
21
|
+
* Parse an HTML string into the nodes it describes (siblings at the top level, exactly like the DOM's own HTML
|
|
22
|
+
* parsing does for innerHTML / insertAdjacentHTML - there is no single root unless the markup itself has one).
|
|
23
|
+
* @memberOf module:factories
|
|
24
|
+
* @param {string} html
|
|
25
|
+
* @param {*} ownerDocument The document the new nodes belong to (matches what innerHTML etc. would set), or null
|
|
26
|
+
* @param {function(new: *, {tagName: string})} ElementClass The class to build each parsed element with
|
|
27
|
+
* @returns {Array<*>}
|
|
28
|
+
*/
|
|
29
|
+
const parseHTML = (html, ownerDocument, ElementClass) => {
|
|
30
|
+
const roots = []
|
|
31
|
+
const stack = []
|
|
32
|
+
const appendNode = node => {
|
|
33
|
+
node.ownerDocumentStore = ownerDocument
|
|
34
|
+
if (stack.length) {
|
|
35
|
+
stack[stack.length - 1].appendChild(node)
|
|
36
|
+
} else {
|
|
37
|
+
roots.push(node)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const parser = new htmlparser2_1.Parser({
|
|
41
|
+
onopentagname (name) {
|
|
42
|
+
const element = new ElementClass({
|
|
43
|
+
tagName: name
|
|
44
|
+
})
|
|
45
|
+
appendNode(element)
|
|
46
|
+
stack.push(element)
|
|
47
|
+
},
|
|
48
|
+
onattribute (name, value) {
|
|
49
|
+
if (!stack.length) {
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
const element = stack[stack.length - 1]
|
|
53
|
+
// pseudo-dom's className / classList and style are not kept in sync with a literal 'class' / 'style'
|
|
54
|
+
// attribute the way setAttribute usually is (there is no such special-casing here, unlike a real DOM) - route
|
|
55
|
+
// them to the real objects directly, the same way cssSelectAdapter does for reading 'class' when matching a
|
|
56
|
+
// CSS selector, so parsed markup's class="..." / style="..." actually populates className/classList and style.
|
|
57
|
+
if (name === 'class') {
|
|
58
|
+
element.className = value
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
if (name === 'style' && element.style) {
|
|
62
|
+
element.style.cssText = value
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
element.setAttribute(name, value)
|
|
66
|
+
},
|
|
67
|
+
ontext (text) {
|
|
68
|
+
appendNode(new NodeService_1.TextService(text))
|
|
69
|
+
},
|
|
70
|
+
oncomment (data) {
|
|
71
|
+
appendNode(new NodeService_1.CommentService(data))
|
|
72
|
+
},
|
|
73
|
+
onclosetag () {
|
|
74
|
+
stack.pop()
|
|
75
|
+
}
|
|
76
|
+
}, {
|
|
77
|
+
lowerCaseTags: true,
|
|
78
|
+
lowerCaseAttributeNames: true
|
|
79
|
+
})
|
|
80
|
+
parser.write(String(html || ''))
|
|
81
|
+
parser.end()
|
|
82
|
+
return roots
|
|
83
|
+
}
|
|
84
|
+
exports.default = parseHTML
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const htmlparser2_1=require("htmlparser2"),NodeService_1=require("../services/NodeService"),parseHTML=(e,t,r)=>{const s=[],n=[],o=e=>{e.ownerDocumentStore=t,n.length?n[n.length-1].appendChild(e):s.push(e)},a=new htmlparser2_1.Parser({onopentagname(e){const t=new r({tagName:e});o(t),n.push(t)},onattribute(e,t){if(!n.length)return;const r=n[n.length-1];"class"!==e?"style"===e&&r.style?r.style.cssText=t:r.setAttribute(e,t):r.className=t},ontext(e){o(new NodeService_1.TextService(e))},oncomment(e){o(new NodeService_1.CommentService(e))},onclosetag(){n.pop()}},{lowerCaseTags:!0,lowerCaseAttributeNames:!0});return a.write(String(e||"")),a.end(),s};exports.default=parseHTML;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A node's children, serialized in order (this is what innerHTML returns).
|
|
3
|
+
* @memberOf module:factories
|
|
4
|
+
* @param {*} node
|
|
5
|
+
* @returns {string}
|
|
6
|
+
*/
|
|
7
|
+
declare const serializeChildren: (node: any) => string;
|
|
8
|
+
/**
|
|
9
|
+
* An element itself, serialized with its children (this is what outerHTML returns).
|
|
10
|
+
* @memberOf module:factories
|
|
11
|
+
* @param {*} element
|
|
12
|
+
* @returns {string}
|
|
13
|
+
*/
|
|
14
|
+
declare const serializeOuter: (element: any) => string;
|
|
15
|
+
export { serializeChildren, serializeOuter };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
require('core-js/modules/esnext.iterator.constructor.js')
|
|
4
|
+
require('core-js/modules/esnext.iterator.filter.js')
|
|
5
|
+
require('core-js/modules/esnext.iterator.map.js')
|
|
6
|
+
require('core-js/modules/esnext.set.add-all.js')
|
|
7
|
+
require('core-js/modules/esnext.set.delete-all.js')
|
|
8
|
+
require('core-js/modules/esnext.set.difference.js')
|
|
9
|
+
require('core-js/modules/esnext.set.every.js')
|
|
10
|
+
require('core-js/modules/esnext.set.filter.js')
|
|
11
|
+
require('core-js/modules/esnext.set.find.js')
|
|
12
|
+
require('core-js/modules/esnext.set.intersection.js')
|
|
13
|
+
require('core-js/modules/esnext.set.is-disjoint-from.js')
|
|
14
|
+
require('core-js/modules/esnext.set.is-subset-of.js')
|
|
15
|
+
require('core-js/modules/esnext.set.is-superset-of.js')
|
|
16
|
+
require('core-js/modules/esnext.set.join.js')
|
|
17
|
+
require('core-js/modules/esnext.set.map.js')
|
|
18
|
+
require('core-js/modules/esnext.set.reduce.js')
|
|
19
|
+
require('core-js/modules/esnext.set.some.js')
|
|
20
|
+
require('core-js/modules/esnext.set.symmetric-difference.js')
|
|
21
|
+
require('core-js/modules/esnext.set.union.js')
|
|
22
|
+
Object.defineProperty(exports, '__esModule', {
|
|
23
|
+
value: true
|
|
24
|
+
})
|
|
25
|
+
exports.serializeOuter = exports.serializeChildren = void 0
|
|
26
|
+
/**
|
|
27
|
+
* @file Serializes pseudo-dom nodes back into an HTML string, for innerHTML / outerHTML.
|
|
28
|
+
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
29
|
+
* @version 1.0.0
|
|
30
|
+
*/
|
|
31
|
+
const NodeService_1 = require('../services/NodeService')
|
|
32
|
+
// Void elements are self-closing and never serialize a closing tag or children (there is no HTML parsing of their
|
|
33
|
+
// content either - the DOM never lets them have children in the first place).
|
|
34
|
+
const VOID_ELEMENTS = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'])
|
|
35
|
+
// These property-backed names (see ElementService / HTMLElementService's constructors) are not real HTML content
|
|
36
|
+
// attributes - offsetWidth and friends describe layout, which does not exist here, and innerHTML is JS-only - so
|
|
37
|
+
// they must never appear in serialized markup, however getAttributeNames() may report them.
|
|
38
|
+
const NEVER_SERIALIZE = new Set(['innerHTML', 'clientHeight', 'clientLeft', 'clientTop', 'clientWidth', 'scrollHeight', 'scrollLeft', 'scrollTop', 'scrollWidth', 'offsetHeight', 'offsetLeft', 'offsetParent', 'offsetTop', 'offsetWidth'])
|
|
39
|
+
// The attribute name to serialize a property-backed name as, when it differs from the property name
|
|
40
|
+
const ATTRIBUTE_NAME = {
|
|
41
|
+
className: 'class'
|
|
42
|
+
}
|
|
43
|
+
// Boolean HTML attributes: present (with no value) when true, absent entirely when false
|
|
44
|
+
const BOOLEAN_ATTRIBUTES = new Set(['hidden'])
|
|
45
|
+
/**
|
|
46
|
+
* Escape text so it is safe inside HTML text content.
|
|
47
|
+
* @param {string} text
|
|
48
|
+
* @returns {string}
|
|
49
|
+
*/
|
|
50
|
+
const escapeText = text => text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
51
|
+
/**
|
|
52
|
+
* Escape a value so it is safe inside a double-quoted HTML attribute.
|
|
53
|
+
* @param {string} value
|
|
54
|
+
* @returns {string}
|
|
55
|
+
*/
|
|
56
|
+
const escapeAttributeValue = value => value.replace(/&/g, '&').replace(/"/g, '"')
|
|
57
|
+
/**
|
|
58
|
+
* Every attribute of the element, serialized (class instead of className, boolean attributes bare, the never-real
|
|
59
|
+
* mock properties left out, style added from the live CSSStyleDeclaration when it is not empty).
|
|
60
|
+
* @param {*} element
|
|
61
|
+
* @returns {string}
|
|
62
|
+
*/
|
|
63
|
+
const serializeAttributes = element => {
|
|
64
|
+
let result = (element.getAttributeNames ? element.getAttributeNames() : []).filter(name => !NEVER_SERIALIZE.has(name)).map(name => {
|
|
65
|
+
if (BOOLEAN_ATTRIBUTES.has(name)) {
|
|
66
|
+
return element[name] ? ` ${name}` : ''
|
|
67
|
+
}
|
|
68
|
+
const value = element.getAttribute(name)
|
|
69
|
+
return value === '' ? '' : ` ${ATTRIBUTE_NAME[name] || name}="${escapeAttributeValue(value)}"`
|
|
70
|
+
}).join('')
|
|
71
|
+
const style = element.style
|
|
72
|
+
if (style && style.cssText) {
|
|
73
|
+
result += ` style="${escapeAttributeValue(style.cssText)}"`
|
|
74
|
+
}
|
|
75
|
+
return result
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* One node, serialized (its own markup only - see serializeChildren for its descendants too).
|
|
79
|
+
* @param {*} node
|
|
80
|
+
* @returns {string}
|
|
81
|
+
*/
|
|
82
|
+
const serializeNode = node => {
|
|
83
|
+
if (node.nodeType === NodeService_1.NodeService.TEXT_NODE) {
|
|
84
|
+
return escapeText(node.nodeValue || '')
|
|
85
|
+
}
|
|
86
|
+
if (node.nodeType === NodeService_1.NodeService.COMMENT_NODE) {
|
|
87
|
+
return `<!--${node.nodeValue || ''}-->`
|
|
88
|
+
}
|
|
89
|
+
if (node.nodeType !== NodeService_1.NodeService.ELEMENT_NODE) {
|
|
90
|
+
return ''
|
|
91
|
+
}
|
|
92
|
+
const tagName = node.tagName
|
|
93
|
+
const attributes = serializeAttributes(node)
|
|
94
|
+
if (VOID_ELEMENTS.has(tagName)) {
|
|
95
|
+
return `<${tagName}${attributes}>`
|
|
96
|
+
}
|
|
97
|
+
return `<${tagName}${attributes}>${serializeChildren(node)}</${tagName}>`
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* A node's children, serialized in order (this is what innerHTML returns).
|
|
101
|
+
* @memberOf module:factories
|
|
102
|
+
* @param {*} node
|
|
103
|
+
* @returns {string}
|
|
104
|
+
*/
|
|
105
|
+
const serializeChildren = node => Array.from(node.childNodes).map(serializeNode).join('')
|
|
106
|
+
exports.serializeChildren = serializeChildren
|
|
107
|
+
/**
|
|
108
|
+
* An element itself, serialized with its children (this is what outerHTML returns).
|
|
109
|
+
* @memberOf module:factories
|
|
110
|
+
* @param {*} element
|
|
111
|
+
* @returns {string}
|
|
112
|
+
*/
|
|
113
|
+
const serializeOuter = element => serializeNode(element)
|
|
114
|
+
exports.serializeOuter = serializeOuter
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.filter.js"),require("core-js/modules/esnext.iterator.map.js"),require("core-js/modules/esnext.set.add-all.js"),require("core-js/modules/esnext.set.delete-all.js"),require("core-js/modules/esnext.set.difference.js"),require("core-js/modules/esnext.set.every.js"),require("core-js/modules/esnext.set.filter.js"),require("core-js/modules/esnext.set.find.js"),require("core-js/modules/esnext.set.intersection.js"),require("core-js/modules/esnext.set.is-disjoint-from.js"),require("core-js/modules/esnext.set.is-subset-of.js"),require("core-js/modules/esnext.set.is-superset-of.js"),require("core-js/modules/esnext.set.join.js"),require("core-js/modules/esnext.set.map.js"),require("core-js/modules/esnext.set.reduce.js"),require("core-js/modules/esnext.set.some.js"),require("core-js/modules/esnext.set.symmetric-difference.js"),require("core-js/modules/esnext.set.union.js"),Object.defineProperty(exports,"__esModule",{value:!0}),exports.serializeOuter=exports.serializeChildren=void 0;const NodeService_1=require("../services/NodeService"),VOID_ELEMENTS=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]),NEVER_SERIALIZE=new Set(["innerHTML","clientHeight","clientLeft","clientTop","clientWidth","scrollHeight","scrollLeft","scrollTop","scrollWidth","offsetHeight","offsetLeft","offsetParent","offsetTop","offsetWidth"]),ATTRIBUTE_NAME={className:"class"},BOOLEAN_ATTRIBUTES=new Set(["hidden"]),escapeText=e=>e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"),escapeAttributeValue=e=>e.replace(/&/g,"&").replace(/"/g,"""),serializeAttributes=e=>{let s=(e.getAttributeNames?e.getAttributeNames():[]).filter(e=>!NEVER_SERIALIZE.has(e)).map(s=>{if(BOOLEAN_ATTRIBUTES.has(s))return e[s]?` ${s}`:"";const r=e.getAttribute(s);return""===r?"":` ${ATTRIBUTE_NAME[s]||s}="${escapeAttributeValue(r)}"`}).join("");const r=e.style;return r&&r.cssText&&(s+=` style="${escapeAttributeValue(r.cssText)}"`),s},serializeNode=e=>{if(e.nodeType===NodeService_1.NodeService.TEXT_NODE)return escapeText(e.nodeValue||"");if(e.nodeType===NodeService_1.NodeService.COMMENT_NODE)return`\x3c!--${e.nodeValue||""}--\x3e`;if(e.nodeType!==NodeService_1.NodeService.ELEMENT_NODE)return"";const s=e.tagName,r=serializeAttributes(e);return VOID_ELEMENTS.has(s)?`<${s}${r}>`:`<${s}${r}>${serializeChildren(e)}</${s}>`},serializeChildren=e=>Array.from(e.childNodes).map(serializeNode).join("");exports.serializeChildren=serializeChildren;const serializeOuter=e=>serializeNode(e);exports.serializeOuter=serializeOuter;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Substitute for the DOM CSSStyleDeclaration Class. Real instances (from createStyleDeclaration) also accept
|
|
3
|
-
* arbitrary camelCase CSS property names (declaration.backgroundColor), which cannot be expressed in an interface.
|
|
4
|
-
*/
|
|
5
|
-
export interface PseudoCSSStyleDeclaration {
|
|
6
|
-
get length(): number;
|
|
7
|
-
get cssText(): string;
|
|
8
|
-
set cssText(cssText: string);
|
|
9
|
-
item(index: number): string;
|
|
10
|
-
getPropertyValue(property: string): string;
|
|
11
|
-
getPropertyPriority(property: string): string;
|
|
12
|
-
setProperty(property: string, value: string, priority: string): void;
|
|
13
|
-
removeProperty(property: string): string;
|
|
14
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* @file Substitute for the DOM CSSStyleDeclaration Class. Real instances (from createStyleDeclaration) also accept
|
|
3
|
+
* arbitrary camelCase CSS property names (declaration.backgroundColor), which cannot be expressed in an interface.
|
|
4
|
+
*/
|
|
5
|
+
export interface PseudoCSSStyleDeclaration {
|
|
6
|
+
get length(): number;
|
|
7
|
+
get cssText(): string;
|
|
8
|
+
set cssText(cssText: string);
|
|
9
|
+
item(index: number): string;
|
|
10
|
+
getPropertyValue(property: string): string;
|
|
11
|
+
getPropertyPriority(property: string): string;
|
|
12
|
+
setProperty(property: string, value: string, priority: string): void;
|
|
13
|
+
removeProperty(property: string): string;
|
|
14
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', {
|
|
4
|
-
value: true
|
|
5
|
-
})
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', {
|
|
4
|
+
value: true
|
|
5
|
+
})
|