als-document 1.0.0-alpha → 1.0.0-beta
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/document.js +14 -6
- package/index.js +14 -6
- package/index.mjs +14 -6
- package/package.json +2 -5
- package/readme.md +32 -3
- package/src/build.js +5 -4
- package/src/node/node.js +45 -11
- package/src/node/root.js +11 -0
- package/src/node/single-node.js +6 -5
- package/src/parse/cache.js +33 -0
- package/src/parse/parse-atts.js +1 -1
- package/src/parse/parser.js +30 -6
- package/src/query/check-element.js +1 -2
- package/tests/cache.js +19 -0
- package/tests/index.html +6 -5
- package/tests/node.js +1 -1
- package/tests/parse-real.js +3 -2
- package/tests/parser.js +6 -6
- package/tests/test.js +169 -0
package/document.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const alsDocument = (function(){
|
|
2
2
|
class Query{
|
|
3
3
|
static get(query){
|
|
4
4
|
let q=new Query(query)
|
|
5
5
|
return q.selectors
|
|
6
6
|
}
|
|
7
7
|
constructor(query){
|
|
8
8
|
this.query=query
|
|
9
9
|
this.selectors=[]
|
|
10
10
|
this.stringValues=[];
|
|
11
11
|
this.parseSelectors(query.split(','))
|
|
12
12
|
}
|
|
13
13
|
parseSelectors(selectors){
|
|
14
14
|
selectors.forEach(selector=>{
|
|
15
15
|
let originalSelector=selector.trim()
|
|
16
16
|
selector=this.removeSpaces(selector)
|
|
17
17
|
this.stringValues=[]
|
|
18
18
|
selector=selector.replace(/\[.*?\]/g,(value)=>{
|
|
19
19
|
this.stringValues.push(value)
|
|
20
20
|
return `[${this.stringValues.length-1}]`
|
|
21
21
|
})
|
|
22
22
|
let [element,ancestors]=this.splitAndCutLast(selector,' ')
|
|
23
23
|
element=this.getFamily(element)
|
|
24
24
|
if (ancestors.length>0)
|
|
25
25
|
element.ancestors=ancestors.map(ancestor=>this.getFamily(ancestor))
|
|
26
26
|
element.group=originalSelector
|
|
27
27
|
this.selectors.push(element)
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
30
|
splitAndCutLast(string,splitBy){
|
|
31
31
|
const array=string.split(splitBy);
|
|
32
32
|
const last=array.pop();
|
|
33
33
|
return [last,array];
|
|
34
34
|
}
|
|
35
35
|
getFamily(group,element,prev,prevAny,sign){
|
|
36
36
|
if (group.match(/\~|\+/)!==null){
|
|
37
37
|
let [last,prevBrothers]=this.splitAndCutLast(group,/\~|\+/)
|
|
38
38
|
let signs=group.replace(last,'')
|
|
39
39
|
prevBrothers.forEach(el=>signs=signs.replace(el,''))
|
|
40
40
|
signs=signs.match(/\~|\+/g)
|
|
41
41
|
if (signs.length==1){
|
|
42
42
|
sign=signs[0]
|
|
43
43
|
} else if (signs.length>1){
|
|
44
44
|
sign=signs.splice(signs.length-1,signs.length-1)[0]
|
|
45
45
|
prevBrothers[0]=prevBrothers.map((b,i)=>{
|
|
46
46
|
if (i< prevBrothers.length-1) b+=signs[i]
|
|
47
47
|
return b
|
|
48
48
|
}).join('')
|
|
49
49
|
prevBrothers[0]=this.getFamily(prevBrothers[0])
|
|
50
50
|
}
|
|
51
51
|
if (sign=='~') prevAny=prevBrothers[0]
|
|
52
52
|
else if (sign=='+') prev=prevBrothers[0]
|
|
53
53
|
element=last
|
|
54
54
|
} else element=group
|
|
55
55
|
let family
|
|
56
56
|
if (prev || prevAny){
|
|
57
57
|
family=this.getParents(element)
|
|
58
58
|
if (prev) family.prev=this.getParents(prev)
|
|
59
59
|
if (prevAny) family.prevAny=this.getParents(prevAny)
|
|
60
60
|
} else family=this.getParents(element)
|
|
61
61
|
if (family.query!==group) family.group=group
|
|
62
62
|
return family
|
|
63
63
|
}
|
|
64
64
|
getParents(selector){
|
|
65
65
|
if (typeof selector=='string'){
|
|
66
66
|
let [element,parents]=this.splitAndCutLast(selector,'>')
|
|
67
67
|
element=this.buildElement(element)
|
|
68
68
|
parents=parents.map(parent=>this.buildElement(parent))
|
|
69
69
|
if (parents.length>0) element.parents=parents
|
|
70
70
|
return element
|
|
71
71
|
} else return selector
|
|
72
72
|
}
|
|
73
73
|
buildElement(element,id=null,tag=null,classList=[]){
|
|
74
74
|
let query=element
|
|
75
75
|
element=element.replace(/\#(\w-?)*/,$id=>{
|
|
76
76
|
id=$id.replace(/^\#/,''); return ''
|
|
77
77
|
})
|
|
78
78
|
element=element.replace(/\.(\w-?)*/,$class=>{
|
|
79
79
|
classList.push($class.replace(/^\./,'')); return ''
|
|
80
80
|
})
|
|
81
81
|
element=element.replace(/(\w\:?-?)*/,$tag=>{
|
|
82
82
|
tag=$tag=='' ? null : $tag; return ''
|
|
83
83
|
})
|
|
84
84
|
let attribs=this.getAttributes(element)
|
|
85
85
|
element={ query }
|
|
86
86
|
if (id) element.id=id
|
|
87
87
|
if (tag) element.tag=tag
|
|
88
88
|
if (classList.length>0) element.classList=classList
|
|
89
89
|
if (attribs.length>0) element.attribs=attribs
|
|
90
90
|
return element
|
|
91
91
|
}
|
|
92
92
|
getAttributes(element){
|
|
93
93
|
let attribs=this.stringValues.filter((value,index)=>{
|
|
94
94
|
let searchValue=`[${index}]`
|
|
95
95
|
if (element.match(searchValue)) return true
|
|
96
96
|
else return false
|
|
97
97
|
})
|
|
98
98
|
attribs=attribs.map(attrib=>{
|
|
99
99
|
let query=attrib
|
|
100
100
|
attrib=attrib.replace('[','').replace(']','')
|
|
101
101
|
let [name,value]=attrib.split(/[\~\|\^\$\*]?\=/)
|
|
102
102
|
let sign=attrib.replace(name,'').replace(value,'')
|
|
103
103
|
attrib={ query }
|
|
104
104
|
if (name) attrib.name=name
|
|
105
105
|
if (value) attrib.value=value.trim().replace(/^\"/,'').replace(/\"$/,'')
|
|
106
106
|
if (sign){
|
|
107
107
|
attrib.sign=sign
|
|
108
108
|
attrib.check=this.getAttribFn(sign).bind(attrib)
|
|
109
109
|
}
|
|
110
110
|
return attrib
|
|
111
111
|
});
|
|
112
112
|
return attribs
|
|
113
113
|
}
|
|
114
114
|
getAttribFn(sign){
|
|
115
115
|
if (sign=='=') return function (value){ return value===this.value }
|
|
116
116
|
if (sign=='*=') return function (value){ return value.includes(this.value) }
|
|
117
117
|
if (sign=='^=') return function (value){ return value.startsWith(this.value) }
|
|
118
118
|
if (sign=='$=') return function (value){ return value.endsWith(this.value) }
|
|
119
119
|
if (sign=='|=') return function (value){
|
|
120
120
|
return value.trim().split(' ').length==1
|
|
121
121
|
&& (value.startsWith(this.value) || value.startsWith(this.value+'-'))
|
|
122
122
|
? true : false
|
|
123
123
|
}
|
|
124
124
|
if (sign=='~=') return function (value){
|
|
125
125
|
return this.value.trim().split(' ').length==1 && value.includes(this.value) ? true : false
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
removeSpaces(selector){
|
|
129
129
|
selector=selector.replace(/\s{2}/g,' ')
|
|
130
130
|
selector=selector.replace(/\s?\^?\$?\|?\~?\*?\=\s*/g,(m)=>m.trim())
|
|
131
131
|
selector=selector.replace(/\s?(\+|\~|\>)\s?/g,(m)=>m.trim())
|
|
132
132
|
return selector
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
|
-
function checkElement(el,selector){
|
|
136
135
|
if(selector==undefined) return true
|
|
137
136
|
if(el==null) return false
|
|
138
137
|
let{tag,classList,attributes,id,prev,ancestors,parents,prevAny}=selector
|
|
139
138
|
if(typeof el==='string') return false
|
|
140
139
|
if(el.isSpecial) return false
|
|
141
140
|
if(id!==undefined && el.id===null) return false
|
|
142
141
|
if(id && id!==el.id) return false
|
|
143
142
|
if(tag && el.tagName===undefined) return false
|
|
144
143
|
else if(tag && tag!==el.tagName) return false
|
|
145
144
|
const clas=el.attributes.class
|
|
146
145
|
if(classList!==undefined && (clas===undefined || clas==='')) return false
|
|
147
146
|
else if(classList!==undefined){
|
|
148
147
|
if(classList.every(e=>el.classList.contains(e))===false) return false
|
|
149
148
|
}
|
|
150
149
|
if(checkattributes(attributes,el)===false) return false
|
|
151
150
|
if(checkElement(el.prev,prev)===false) return false
|
|
152
151
|
if(checkAncestors(el.ancestors,ancestors)===false) return false
|
|
153
152
|
if(checkParents(el.ancestors,parents)===false) return false
|
|
154
153
|
if(el.parent){
|
|
155
154
|
if(checkPrevAny(el.parent.children,el.childIndex,prevAny)==false) return false
|
|
156
155
|
}
|
|
157
156
|
return true
|
|
157
|
+
function checkElement(el,selector){
|
|
158
158
|
if(selector==undefined) return true
|
|
159
159
|
if(el==null) return false
|
|
160
160
|
let{tag,classList,attribs:attributes,id,prev,ancestors,parents,prevAny}=selector
|
|
161
161
|
if(typeof el==='string') return false
|
|
162
162
|
if(id!==undefined && el.id===null) return false
|
|
163
163
|
if(id && id!==el.id) return false
|
|
164
164
|
if(tag && el.tagName===undefined) return false
|
|
165
165
|
else if(tag && tag!==el.tagName) return false
|
|
166
166
|
const clas=el.attributes.class
|
|
167
167
|
if(classList!==undefined && (clas===undefined || clas==='')) return false
|
|
168
168
|
else if(classList!==undefined){
|
|
169
169
|
if(classList.every(e=>el.classList.contains(e))===false) return false
|
|
170
170
|
}
|
|
171
171
|
if(checkattributes(attributes,el)===false) return false
|
|
172
172
|
if(checkElement(el.prev,prev)===false) return false
|
|
173
173
|
if(checkAncestors(el.ancestors,ancestors)===false) return false
|
|
174
174
|
if(checkParents(el.ancestors,parents)===false) return false
|
|
175
175
|
if(el.parent){
|
|
176
176
|
if(checkPrevAny(el.parent.children,el.childIndex,prevAny)==false) return false
|
|
177
177
|
}
|
|
178
178
|
return true
|
|
179
179
|
}
|
|
180
180
|
function checkattributes(attributes=[],el){
|
|
181
181
|
let elattributes=el.attributes
|
|
182
182
|
let names=Object.keys(elattributes)
|
|
183
183
|
let passedTests=0
|
|
184
184
|
if(attributes) for(let i=0; i<attributes.length; i++){
|
|
185
185
|
let{name,value,check}=attributes[i]
|
|
186
186
|
if(name=='inner' && value!==undefined && check && el.inner){
|
|
187
187
|
if(check(el.inner)) passedTests++
|
|
188
188
|
}
|
|
189
189
|
if(!names.includes(name)) continue
|
|
190
190
|
else if(value==undefined) passedTests++
|
|
191
191
|
else if(value && elattributes[name]){
|
|
192
192
|
if(check(elattributes[name])==false) continue
|
|
193
193
|
else passedTests++
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
if(passedTests==attributes.length) return true
|
|
197
197
|
else return false
|
|
198
198
|
}
|
|
199
199
|
function checkPrevAny(children=[],index,prevAny){
|
|
200
200
|
let size=children.length
|
|
201
201
|
if((size==0 || index==0) && prevAny) return false
|
|
202
202
|
for(let i=index; i>=0; i--){
|
|
203
203
|
if(checkElement(children[i],prevAny)) return true
|
|
204
204
|
}
|
|
205
205
|
return false
|
|
206
206
|
}
|
|
207
207
|
function checkAncestors(ancestors=[],selectorAncestors=[]){
|
|
208
208
|
let count=0
|
|
209
209
|
if(selectorAncestors.length==0) return true
|
|
210
210
|
let endIndex=ancestors.length-1
|
|
211
211
|
let selectorIndex=selectorAncestors.length-1
|
|
212
212
|
while(selectorIndex>=0){
|
|
213
213
|
for(let i=endIndex; i>=0; i--){
|
|
214
214
|
endIndex=i-1
|
|
215
215
|
if(checkElement(ancestors[i],selectorAncestors[selectorIndex])==true){
|
|
216
216
|
count++
|
|
217
217
|
break
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
220
|
selectorIndex--
|
|
221
221
|
}
|
|
222
222
|
if(count==selectorAncestors.length) return true
|
|
223
223
|
else return false
|
|
@@ -21,14 +21,22 @@ function buildStyle(attributes){
|
|
|
21
21
|
const styles=attributes.style || "";
|
|
22
22
|
con
|
|
23
23
|
|
|
24
24
|
class NodeClassList{
|
|
25
25
|
constructor(node){ this.node=node }
|
|
26
26
|
get classes(){ return (this.node.attributes.class || "").split(" ").filter(Boolean) }
|
|
27
27
|
set classes(val){ this.node.attributes.class=val.join(" ") }
|
|
28
28
|
contains(className){ return this.classes.includes(className) }
|
|
29
29
|
add(className){
|
|
30
30
|
const currentClasses=this.classes;
|
|
31
31
|
if (!currentClasses.includes(className)) this.classes=[...currentClasses,className];
|
|
32
32
|
}
|
|
33
33
|
remove(className){ this.classes=this.classes.filter(cls=>cls!==className); }
|
|
34
34
|
toggle(className){
|
|
35
35
|
if (this.classes.includes(className)) this.remove(className);
|
|
36
36
|
else this.add(className);
|
|
37
37
|
}
|
|
38
38
|
replace(oldClass,newClass){
|
|
39
39
|
if (this.classes.includes(oldClass)){
|
|
40
40
|
this.remove(oldClass);
|
|
41
41
|
this.add(newClass);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
class Node{
|
|
46
45
|
constructor(tagName,attributes={},parent=null){
|
|
47
46
|
this.isSingle=false;
|
|
48
47
|
this.tagName=tagName;
|
|
49
48
|
this.attributes=attributes;
|
|
50
49
|
this.childNodes=[];
|
|
51
50
|
if (parent!==null) parent.childNodes.push(this)
|
|
52
51
|
this.parent=parent;
|
|
53
52
|
this._classList=null;
|
|
54
53
|
this.__style=null;
|
|
55
54
|
this._dataset=null
|
|
56
55
|
}
|
|
57
56
|
get id(){ return this.attributes.id || null; }
|
|
58
57
|
get className(){return this.attributes.class || null}
|
|
59
58
|
get parentNode(){ return this.parent }
|
|
60
59
|
get ancestors(){
|
|
61
60
|
const ancestors=[]
|
|
62
61
|
let element=this.parent
|
|
63
62
|
while (element.tagName!=='ROOT'){
|
|
64
63
|
ancestors.push(element)
|
|
65
64
|
element=element.parent
|
|
66
65
|
}
|
|
67
66
|
return ancestors.reverse()
|
|
68
67
|
}
|
|
69
68
|
get childIndex(){ return this.parent.childNodes ? this.parent.childNodes.indexOf(this) : null }
|
|
70
69
|
get previousElementSibling(){ return this.prev }
|
|
71
70
|
get prev(){
|
|
72
71
|
if (!this.childIndex) return null
|
|
73
72
|
return this.parent.childNodes[this.childIndex-1]
|
|
74
73
|
}
|
|
75
74
|
get nextElementSibling(){ return this.next }
|
|
76
75
|
get next(){
|
|
77
76
|
if (!this.childIndex) return null
|
|
78
77
|
return this.parent.childNodes[this.childIndex+1] || null
|
|
79
78
|
}
|
|
80
79
|
get dataset(){
|
|
81
80
|
if (!this._dataset) this._dataset=getDataset(this);
|
|
82
81
|
return this._dataset;
|
|
83
82
|
}
|
|
84
83
|
get classList(){
|
|
85
84
|
if (!this._classList) this._classList=new NodeClassList(this);
|
|
86
85
|
return this._classList;
|
|
87
86
|
}
|
|
88
87
|
get style(){
|
|
89
88
|
if (!this.__style) this.__style=buildStyle(this.attributes)
|
|
90
89
|
return this.__style
|
|
91
90
|
}
|
|
92
91
|
get outerHTML(){
|
|
93
92
|
const attrs=Object.entries(this.attributes).map(([key,val])=>`${key}="${val}"`).join(" ");
|
|
94
93
|
return `<${this.tagName} ${attrs}>${this.innerHTML}</${this.tagName}>`;
|
|
95
94
|
}
|
|
96
95
|
getAttribute(attrName){ return this.attributes[attrName] || null }
|
|
97
96
|
setAttribute(attrName,value){ this.attributes[attrName]=value }
|
|
98
97
|
removeAttribute(attrName){ delete this.attributes[attrName] }
|
|
99
98
|
remove(){
|
|
100
99
|
if (!this.parent) return
|
|
101
100
|
const index=this.childIndex;
|
|
102
101
|
if (index!==null) this.parent.childNodes.splice(index,1);
|
|
103
102
|
}
|
|
104
103
|
get innerHTML(){
|
|
105
104
|
return this.childNodes.map(child=>{
|
|
106
105
|
if (child instanceof Node || child instanceof SingleNode) return child.outerHTML;
|
|
107
106
|
else if (child instanceof TextNode) return child.textContent;
|
|
108
107
|
else return child
|
|
109
108
|
}).join("");
|
|
110
109
|
}
|
|
111
110
|
$$(query){return this.querySelectorAll(query)}
|
|
112
111
|
querySelectorAll(query){
|
|
113
112
|
const selectors=Query.get(query)
|
|
114
113
|
return find(selectors,this,new Set())
|
|
115
114
|
}
|
|
116
115
|
$(query){return this.querySelector(query)}
|
|
117
116
|
querySelector(query){
|
|
118
117
|
const selectors=Query.get(query)
|
|
119
118
|
return find(selectors,this,new Set(),true)[0]
|
|
120
119
|
}
|
|
121
120
|
getElementsByClassName(query){ return this.querySelectorAll('.'+query) }
|
|
122
121
|
getElementsByTagName(query){ return this.querySelectorAll(query) }
|
|
123
122
|
getElementById(query){ return this.querySelector('#'+query) }
|
|
124
123
|
get children(){
|
|
125
124
|
return this.childNodes.filter(child=>{
|
|
126
125
|
if (!(child instanceof Node)) return false
|
|
127
126
|
if (child.tagName==='#comment') return false
|
|
128
127
|
return true
|
|
129
128
|
});
|
|
130
129
|
}
|
|
131
130
|
insertAdjacentElement(position,newElement){
|
|
132
131
|
if(newElement.tagName==='ROOT' && newElement.childNodes.length>0) newElement=newElement.childNodes[0]
|
|
133
132
|
const pos=position.toLowerCase();
|
|
134
133
|
if (pos==="afterbegin") this.childNodes.unshift(newElement);
|
|
135
134
|
else if (pos==="beforeend") this.childNodes.push(newElement);
|
|
136
135
|
if (!this.parent) return newElement
|
|
137
136
|
if (pos==="beforebegin") this.parent.childNodes.unshift(newElement);
|
|
138
137
|
else if (pos==="afterend") this.parent.childNodes.splice(this.childIndex+1,0,newElement);
|
|
139
138
|
return newElement
|
|
140
139
|
}
|
|
141
140
|
insertAdjacentHTML(position,html){
|
|
142
141
|
const newNode=parseHTML(html);
|
|
143
142
|
return this.insertAdjacentElement(position,newNode);
|
|
144
143
|
}
|
|
145
144
|
insertAdjacentText(position,text){
|
|
146
145
|
return this.insertAdjacentElement(position,new TextNode(text));
|
|
147
146
|
}
|
|
148
147
|
set innerHTML(html){
|
|
149
148
|
const parsed=parseHTML(html);
|
|
150
149
|
this.childNodes=parsed.childNodes;
|
|
151
150
|
}
|
|
152
151
|
set outerHTML(html){
|
|
153
152
|
const parsed=parseHTML(html);
|
|
154
153
|
if (!this.parent) return console.log('element has no parent node')
|
|
155
154
|
const index=this.childIndex
|
|
156
155
|
if (index!==null) this.parent.childNodes.splice(index,1,...parsed.childNodes);
|
|
157
156
|
}
|
|
158
157
|
appendChild(newChild){
|
|
159
158
|
if (newChild instanceof Node || newChild instanceof TextNode || newChild instanceof SingleNode){
|
|
160
159
|
if (newChild.parent) newChild.parent.childNodes=newChild.parent.childNodes.filter(child=>child!==newChild);
|
|
161
160
|
} else if(typeof newChild==='string') newChild=new TextNode(newChild)
|
|
162
161
|
else return newChild
|
|
163
162
|
this.childNodes.push(newChild);
|
|
164
163
|
newChild.parent=this;
|
|
165
164
|
return newChild;
|
|
166
165
|
}
|
|
167
166
|
get textContent(){
|
|
168
167
|
if (this.childNodes.length===0) return this.nodeName==='#text' ? this.nodeValue : '';
|
|
169
168
|
return this.childNodes.map(child=>{
|
|
170
169
|
if(child instanceof SingleNode) return ''
|
|
171
170
|
if(child instanceof TextNode) return child.nodeValue
|
|
172
171
|
if(child instanceof Node) return child.textContent;
|
|
173
172
|
else return child;
|
|
174
173
|
}).join(" ");
|
|
175
174
|
}
|
|
176
175
|
set textContent(value){
|
|
177
176
|
this.childNodes=[];
|
|
178
177
|
if (value!==null && value!==undefined){
|
|
179
178
|
this.childNodes.push(value.toString());
|
|
180
179
|
}
|
|
181
180
|
}
|
|
181
|
+
function insertBefore(arr,index,newItem){
|
|
182
182
|
const existingIndex=arr.indexOf(newItem);
|
|
183
183
|
if (existingIndex!==-1) arr.splice(existingIndex,1);
|
|
184
184
|
arr.splice(index,0,newItem);
|
|
185
|
+
}
|
|
185
186
|
class Node{
|
|
186
187
|
constructor(tagName,attributes={},parent=null){
|
|
187
188
|
this.isSingle=false;
|
|
188
189
|
this.tagName=tagName;
|
|
189
190
|
this.attributes=attributes;
|
|
190
191
|
this.childNodes=[];
|
|
191
192
|
if (parent!==null) parent.childNodes.push(this)
|
|
192
193
|
this.parent=parent;
|
|
193
194
|
this._classList=null;
|
|
194
195
|
this.__style=null;
|
|
195
196
|
this._dataset=null
|
|
196
197
|
}
|
|
197
198
|
get id(){ return this.attributes.id ? this.attributes.id : null; }
|
|
198
199
|
set id(newValue){ this.attributes.id=newValue; }
|
|
199
200
|
get className(){return this.attributes.class || null}
|
|
200
201
|
get parentNode(){ return this.parent }
|
|
201
202
|
get ancestors(){
|
|
202
203
|
if(!this.parent) return []
|
|
203
204
|
const ancestors=[]
|
|
204
205
|
let element=this.parent
|
|
205
206
|
while (element.tagName!=='ROOT'){
|
|
206
207
|
ancestors.push(element)
|
|
207
208
|
element=element.parent
|
|
208
209
|
}
|
|
209
210
|
return ancestors.reverse()
|
|
210
211
|
}
|
|
211
212
|
get childNodeIndex(){
|
|
212
213
|
if(!this.parent) return null
|
|
213
214
|
return this.parent.childNodes ? this.parent.childNodes.indexOf(this) : null
|
|
214
215
|
}
|
|
215
216
|
get childIndex(){
|
|
216
217
|
if(!this.parent) return null
|
|
217
218
|
return this.parent.children ? this.parent.children.indexOf(this) : null
|
|
218
219
|
}
|
|
219
220
|
get previousElementSibling(){ return this.prev }
|
|
220
221
|
get prev(){
|
|
221
222
|
if (!this.childIndex) return null
|
|
222
223
|
return this.parent.children[this.childIndex-1]
|
|
223
224
|
}
|
|
224
225
|
get nextElementSibling(){ return this.next }
|
|
225
226
|
get next(){
|
|
226
227
|
if (!this.childIndex) return null
|
|
227
228
|
return this.parent.children[this.childIndex+1] || null
|
|
228
229
|
}
|
|
229
230
|
get dataset(){
|
|
230
231
|
if (!this._dataset) this._dataset=getDataset(this);
|
|
231
232
|
return this._dataset;
|
|
232
233
|
}
|
|
233
234
|
get classList(){
|
|
234
235
|
if (!this._classList) this._classList=new NodeClassList(this);
|
|
235
236
|
return this._classList;
|
|
236
237
|
}
|
|
237
238
|
get style(){
|
|
238
239
|
if (!this.__style) this.__style=buildStyle(this.attributes)
|
|
239
240
|
return this.__style
|
|
240
241
|
}
|
|
241
242
|
get outerHTML(){
|
|
242
243
|
const attrs=Object.entries(this.attributes).map(([key,val])=>val.length ? `${key}="${val}"` : key).join(" ");
|
|
243
244
|
return `<${this.tagName}${attrs ? ' '+attrs : ''}>${this.innerHTML}</${this.tagName}>`;
|
|
244
245
|
}
|
|
245
246
|
getAttribute(attrName){ return this.attributes[attrName] || null }
|
|
246
247
|
setAttribute(attrName,value){ this.attributes[attrName]=value }
|
|
247
248
|
removeAttribute(attrName){ delete this.attributes[attrName] }
|
|
248
249
|
remove(){
|
|
249
250
|
if (!this.parent) return
|
|
250
251
|
const index=this.childNodeIndex;
|
|
251
252
|
if (index!==null) this.parent.childNodes.splice(index,1);
|
|
252
253
|
}
|
|
253
254
|
get innerHTML(){
|
|
254
255
|
return this.childNodes.map(child=>{
|
|
255
256
|
if (child instanceof Node || child instanceof SingleNode) return child.outerHTML;
|
|
256
257
|
else if (child instanceof TextNode) return child.textContent;
|
|
257
258
|
else return child
|
|
258
259
|
}).join("");
|
|
259
260
|
}
|
|
260
261
|
$$(query){return this.querySelectorAll(query)}
|
|
261
262
|
querySelectorAll(query){
|
|
262
263
|
const selectors=Query.get(query)
|
|
263
264
|
return find(selectors,this,new Set())
|
|
264
265
|
}
|
|
265
266
|
$(query){return this.querySelector(query)}
|
|
266
267
|
querySelector(query){
|
|
267
268
|
const selectors=Query.get(query)
|
|
268
269
|
return find(selectors,this,new Set(),true)[0] || null
|
|
269
270
|
}
|
|
270
271
|
getElementsByClassName(query){ return this.querySelectorAll('.'+query) }
|
|
271
272
|
getElementsByTagName(query){ return this.querySelectorAll(query) }
|
|
272
273
|
getElementById(query){ return this.querySelector('#'+query) }
|
|
273
274
|
get children(){
|
|
274
275
|
return this.childNodes.filter(child=>{
|
|
275
276
|
if (!(child instanceof Node)) return false
|
|
276
277
|
if (child.tagName==='#comment') return false
|
|
277
278
|
return true
|
|
278
279
|
});
|
|
279
280
|
}
|
|
280
281
|
insertAdjacentElement(position,newElement){
|
|
281
282
|
if(newElement.tagName==='ROOT' && newElement.childNodes.length>0) newElement=newElement.childNodes[0]
|
|
282
283
|
const pos=position.toLowerCase();
|
|
283
284
|
if (pos==="afterbegin") this.childNodes.unshift(newElement);
|
|
284
285
|
else if (pos==="beforeend") this.childNodes.push(newElement);
|
|
285
286
|
newElement.parent=this
|
|
286
287
|
if (!this.parent) return newElement
|
|
287
288
|
if (pos==="beforebegin") insertBefore(this.parent.childNodes,this.childNodeIndex,newElement)
|
|
288
289
|
else if (pos==="afterend") this.parent.childNodes.splice(this.childNodeIndex+1,0,newElement);
|
|
289
290
|
newElement.parent=this.parent
|
|
290
291
|
return newElement
|
|
291
292
|
}
|
|
292
293
|
insertAdjacentHTML(position,html){
|
|
293
294
|
const newNode=parseHTML(html);
|
|
294
295
|
newNode.childNodes.reverse().forEach(node=>{
|
|
295
296
|
this.insertAdjacentElement(position,node);
|
|
296
297
|
});
|
|
297
298
|
return newNode
|
|
298
299
|
}
|
|
299
300
|
insertAdjacentText(position,text){
|
|
300
301
|
return this.insertAdjacentElement(position,new TextNode(text));
|
|
301
302
|
}
|
|
302
303
|
insert(position,element){
|
|
303
304
|
const positions=['beforebegin','afterbegin','beforeend','afterend']
|
|
304
305
|
if(positions[position]) position=positions[position]
|
|
305
306
|
if(typeof element==='string'){
|
|
306
307
|
element=element.trim()
|
|
307
308
|
if(element.startsWith('<') && element.endsWith('>')){
|
|
308
309
|
return this.insertAdjacentHTML(position,element)
|
|
309
310
|
}
|
|
310
311
|
return this.insertAdjacentText(position,element)
|
|
311
312
|
}
|
|
312
313
|
return this.insertAdjacentElement(position,element)
|
|
313
314
|
}
|
|
314
315
|
set innerHTML(html){
|
|
315
316
|
const parsed=parseHTML(html);
|
|
316
317
|
this.childNodes=parsed.childNodes;
|
|
317
318
|
}
|
|
318
319
|
set outerHTML(html){
|
|
319
320
|
const parsed=parseHTML(html);
|
|
320
321
|
if (!this.parent) return console.log('element has no parent node')
|
|
321
322
|
const index=this.childIndex
|
|
322
323
|
if (index!==null) this.parent.childNodes.splice(index,1,...parsed.childNodes);
|
|
323
324
|
}
|
|
324
325
|
appendChild(newChild){
|
|
325
326
|
if (newChild instanceof Node || newChild instanceof TextNode || newChild instanceof SingleNode){
|
|
326
327
|
if (newChild.parent) newChild.parent.childNodes=newChild.parent.childNodes.filter(child=>child!==newChild);
|
|
327
328
|
} else if(typeof newChild==='string') newChild=new TextNode(newChild)
|
|
328
329
|
else return newChild
|
|
329
330
|
this.childNodes.push(newChild);
|
|
330
331
|
newChild.parent=this;
|
|
331
332
|
return newChild;
|
|
332
333
|
}
|
|
333
334
|
get textContent(){
|
|
334
335
|
if (this.childNodes.length===0) return this.nodeName==='#text' ? this.nodeValue : '';
|
|
335
336
|
return this.childNodes.map(child=>{
|
|
336
337
|
if(child instanceof SingleNode) return ''
|
|
337
338
|
if(child instanceof TextNode) return child.nodeValue
|
|
338
339
|
if(child instanceof Node) return child.textContent;
|
|
339
340
|
else return child;
|
|
340
341
|
}).join(" ");
|
|
341
342
|
}
|
|
342
343
|
set textContent(value){
|
|
343
344
|
this.childNodes=[];
|
|
344
345
|
if (value!==null && value!==undefined){
|
|
345
346
|
this.childNodes.push(value.toString());
|
|
346
347
|
}
|
|
347
348
|
}
|
|
348
349
|
}
|
|
349
|
-
class SingleNode extends Node{
|
|
350
350
|
constructor(tagName,attributes={},parent=null){
|
|
351
351
|
if(attributes['?'] && tagName==='?xml') delete attributes['?']
|
|
352
352
|
super(tagName,attributes,parent);
|
|
353
353
|
this.isSingle=true
|
|
354
354
|
}
|
|
355
355
|
get outerHTML(){
|
|
356
356
|
if (this.tagName==="#cdata-section") return `<![CDATA[${this.textContent}]]>`;
|
|
357
357
|
const attrs=Object.entries(this.attributes).map(([key,val])=>`${key}="${val}"`).join(" ");
|
|
358
358
|
return `<${this.tagName} ${attrs}${this.tagName==='?xml' ? '?' : ''}>`;
|
|
359
359
|
}
|
|
360
360
|
get innerHTML(){ return ""; }
|
|
361
361
|
set innerHTML(_){ }
|
|
362
362
|
$(_){return null}
|
|
363
363
|
$$(_){return []}
|
|
364
364
|
querySelectorAll(_){ return []; }
|
|
365
365
|
querySelector(_){ return null; }
|
|
366
366
|
getElementsByClassName(_){ return []; }
|
|
367
367
|
getElementsByTagName(_){ return []; }
|
|
368
368
|
getElementById(_){ return null; }
|
|
369
369
|
get children(){ return []; }
|
|
370
370
|
insertAdjacentElement(_,__){ }
|
|
371
371
|
insertAdjacentHTML(_,__){ }
|
|
372
372
|
insertAdjacentText(_,__){ }
|
|
373
373
|
appendChild(_){ }
|
|
374
374
|
get textContent(){ return ""; }
|
|
375
375
|
set textContent(_){ }
|
|
376
|
+
class SingleNode extends Node{
|
|
376
377
|
constructor(tagName,attributes={},parent=null){
|
|
377
378
|
if(attributes['?'] && tagName==='?xml') delete attributes['?']
|
|
378
379
|
super(tagName,attributes,parent);
|
|
379
380
|
this.isSingle=true
|
|
380
381
|
}
|
|
381
382
|
get outerHTML(){
|
|
382
383
|
if (this.tagName==="#cdata-section") return `<![CDATA[${this.nodeValue}]]>`;
|
|
383
384
|
const attrs=Object.entries(this.attributes).map(([key,val])=>val.length ? `${key}="${val}"` : key).join(" ");
|
|
384
385
|
return `<${this.tagName} ${attrs}${this.tagName==='?xml' ? '?' : ''}>`;
|
|
385
386
|
}
|
|
386
387
|
get innerHTML(){ return ""; }
|
|
387
388
|
set innerHTML(_){ }
|
|
388
389
|
$(_){return null}
|
|
389
390
|
$$(_){return []}
|
|
390
391
|
querySelectorAll(_){ return []; }
|
|
391
392
|
querySelector(_){ return null; }
|
|
392
393
|
getElementsByClassName(_){ return []; }
|
|
393
394
|
getElementsByTagName(_){ return []; }
|
|
394
395
|
getElementById(_){ return null; }
|
|
395
396
|
get children(){ return []; }
|
|
396
397
|
insertAdjacentElement(_,__){ }
|
|
397
398
|
insertAdjacentHTML(_,__){ }
|
|
398
399
|
insertAdjacentText(_,__){ }
|
|
399
400
|
appendChild(_){ }
|
|
400
401
|
insert(_,__){ }
|
|
401
402
|
get textContent(){ return ""; }
|
|
402
403
|
set textContent(_){ }
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
class Root extends Node{
|
|
403
407
|
constructor(){
|
|
404
408
|
super('ROOT',{},null);
|
|
405
409
|
this.isSingle=false
|
|
406
410
|
}
|
|
407
411
|
get body(){return this.$('body')}
|
|
408
412
|
get head(){return this.$('head')}
|
|
409
413
|
get title(){return this.$('title')}
|
|
410
414
|
set title(title){return this.$('title').innerHTML=title}
|
|
411
415
|
}
|
|
412
|
-
function parseAttributes(str){
|
|
413
416
|
const attrs={};
|
|
414
417
|
let key="";
|
|
415
418
|
let value="";
|
|
416
419
|
let isKey=true;
|
|
417
420
|
let quoteChar=null;
|
|
418
421
|
for (let i=0; i< str.length; i++){
|
|
419
422
|
const char=str[i];
|
|
420
423
|
if (isKey && (char==='=' || char===' ')){
|
|
421
424
|
if (char==='=') isKey=false;
|
|
422
425
|
else if (key.trim()){
|
|
423
426
|
attrs[key.trim()]=true;
|
|
424
427
|
key="";
|
|
425
428
|
}
|
|
426
429
|
continue;
|
|
427
430
|
}
|
|
428
431
|
if (!quoteChar && (char==='"' || char==="'")){
|
|
429
432
|
quoteChar=char;
|
|
430
433
|
continue;
|
|
431
434
|
} else if (quoteChar && char===quoteChar){
|
|
432
435
|
quoteChar=null;
|
|
433
436
|
attrs[key.trim()]=value.trim();
|
|
434
437
|
key=""; value=""; isKey=true;
|
|
435
438
|
continue;
|
|
436
439
|
}
|
|
437
440
|
if (isKey) key+=char;
|
|
438
441
|
else value+=char;
|
|
439
442
|
}
|
|
440
443
|
if (key.trim() &&!value) attrs[key.trim()]=true;
|
|
441
444
|
return attrs;
|
|
445
|
+
function parseAttributes(str){
|
|
442
446
|
const attrs={};
|
|
443
447
|
let key="";
|
|
444
448
|
let value="";
|
|
445
449
|
let isKey=true;
|
|
446
450
|
let quoteChar=null;
|
|
447
451
|
for (let i=0; i< str.length; i++){
|
|
448
452
|
const char=str[i];
|
|
449
453
|
if (isKey && (char==='=' || char===' ')){
|
|
450
454
|
if (char==='=') isKey=false;
|
|
451
455
|
else if (key.trim()){
|
|
452
456
|
attrs[key.trim()]=true;
|
|
453
457
|
key="";
|
|
454
458
|
}
|
|
455
459
|
continue;
|
|
456
460
|
}
|
|
457
461
|
if (!quoteChar && (char==='"' || char==="'")){
|
|
458
462
|
quoteChar=char;
|
|
459
463
|
continue;
|
|
460
464
|
} else if (quoteChar && char===quoteChar){
|
|
461
465
|
quoteChar=null;
|
|
462
466
|
attrs[key.trim()]=value.trim();
|
|
463
467
|
key=""; value=""; isKey=true;
|
|
464
468
|
continue;
|
|
465
469
|
}
|
|
466
470
|
if (isKey) key+=char;
|
|
467
471
|
else value+=char;
|
|
468
472
|
}
|
|
469
473
|
if (key.trim() &&!value) attrs[key.trim()]='';
|
|
470
474
|
return attrs;
|
|
471
475
|
}
|
|
472
476
|
const VOID_TAGS=new Set(["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr","!doctype",'?xml']);
|
|
473
|
-
function parseHTML(html){
|
|
474
477
|
const root=new Node("ROOT");
|
|
475
478
|
const stack=[root];
|
|
476
479
|
let currentText="",i=0;
|
|
477
480
|
function parseSpecial(startStr,endStr,n1,n2,tag){
|
|
478
481
|
if (!html.startsWith(startStr,i)) return false
|
|
479
482
|
const end=html.indexOf(endStr,i+n1);
|
|
480
483
|
const strNode=new Node(tag,{},stack[stack.length-1]);
|
|
481
484
|
strNode.childNodes.push(html.substring(i+n1,end));
|
|
482
485
|
i=end+n2;
|
|
483
486
|
return true
|
|
484
487
|
}
|
|
485
488
|
while (i< html.length){
|
|
486
489
|
if (parseSpecial("<!--","-->",4,3,'#comment')) continue
|
|
487
490
|
if (parseSpecial("<script","</script>",8,9,'script')) continue
|
|
488
491
|
if (parseSpecial("<style","</style>",7,8,'style')) continue
|
|
489
492
|
if (html.startsWith("<![CDATA[",i)){
|
|
490
493
|
const end=html.indexOf("]]>",i+9);
|
|
491
494
|
if (end===-1) break;
|
|
492
495
|
const content=html.substring(i+9,end);
|
|
493
496
|
const cdataNode=new SingleNode("#cdata-section",{},stack[stack.length-1]);
|
|
494
497
|
cdataNode.nodeValue=content;
|
|
495
498
|
i=end+3;
|
|
496
499
|
continue;
|
|
497
500
|
}
|
|
498
501
|
if (html.startsWith("<",i)){
|
|
499
502
|
if (currentText.trim()){
|
|
500
503
|
stack[stack.length-1].childNodes.push(new TextNode(currentText.trim()));
|
|
501
504
|
currentText="";
|
|
502
505
|
}
|
|
503
506
|
let tagEnd=i+1;
|
|
504
507
|
let insideQuotes=false;
|
|
505
508
|
let quoteChar=null;
|
|
506
509
|
while (tagEnd< html.length){
|
|
507
510
|
const char=html[tagEnd];
|
|
508
511
|
if (!insideQuotes && (char==='"' || char==="'")){
|
|
509
512
|
insideQuotes=true;
|
|
510
513
|
quoteChar=char;
|
|
511
514
|
} else if (insideQuotes && char===quoteChar){
|
|
512
515
|
insideQuotes=false;
|
|
513
516
|
quoteChar=null;
|
|
514
517
|
}
|
|
515
518
|
if (!insideQuotes && char==='>') break;
|
|
516
519
|
tagEnd++;
|
|
517
520
|
}
|
|
518
521
|
const tagContent=html.substring(i+1,tagEnd);
|
|
519
522
|
if (tagContent.startsWith("/")) stack.pop();
|
|
520
523
|
else{
|
|
521
524
|
let isSelfClosing=tagContent.endsWith('/');
|
|
522
525
|
const tagNameEnd=tagContent.search(/\s|>|\//);
|
|
523
526
|
const tagName=tagContent.substring(0,tagNameEnd>0 ? tagNameEnd : tagEnd-i-1);
|
|
524
527
|
const attributesString=tagContent.substring(tagName.length,isSelfClosing ? tagContent.length-1 : tagContent.length).trim();
|
|
525
528
|
const attributes=parseAttributes(attributesString);
|
|
526
529
|
if (VOID_TAGS.has(tagName.toLowerCase()) || isSelfClosing) new SingleNode(tagName,attributes,stack[stack.length-1])
|
|
527
530
|
else stack.push(new Node(tagName,attributes,stack[stack.length-1]));
|
|
528
531
|
}
|
|
529
532
|
i=tagEnd+1;
|
|
530
533
|
} else{
|
|
531
534
|
currentText+=html[i];
|
|
532
535
|
i++;
|
|
533
536
|
}
|
|
534
537
|
}
|
|
535
538
|
if (currentText.trim()) stack[stack.length-1].childNodes.push(new TextNode(currentText.trim()));
|
|
536
539
|
return root;
|
|
540
|
+
function parseHTML(html){
|
|
537
541
|
const root=new Root();
|
|
538
542
|
const stack=[root];
|
|
539
543
|
let currentText="",i=0;
|
|
540
544
|
let max=0
|
|
541
545
|
function parseScript(){
|
|
542
546
|
if (!html.startsWith("<script",i)) return false;
|
|
543
547
|
const openTagEnd=html.indexOf(">",i);
|
|
544
548
|
if (openTagEnd===-1) return false;
|
|
545
549
|
const attributesString=html.substring(i+7,openTagEnd).trim();
|
|
546
550
|
const attributes=parseAttributes(attributesString);
|
|
547
551
|
let closeTagStart=html.indexOf("</script>",openTagEnd);
|
|
548
552
|
if (closeTagStart===-1) return false;
|
|
549
553
|
const content=html.substring(openTagEnd+1,closeTagStart);
|
|
550
554
|
const scriptNode=new Node('script',attributes,stack[stack.length-1]);
|
|
551
555
|
if(content.length>0) scriptNode.childNodes.push(content);
|
|
552
556
|
i=closeTagStart+9;
|
|
553
557
|
return true;
|
|
554
558
|
}
|
|
555
559
|
function parseSpecial(startStr,endStr,n1,n2,tag){
|
|
556
560
|
if (!html.startsWith(startStr,i)) return false
|
|
557
561
|
const end=html.indexOf(endStr,i+n1);
|
|
558
562
|
const strNode=new Node(tag,{},stack[stack.length-1]);
|
|
559
563
|
strNode.childNodes.push(html.substring(i+n1,end));
|
|
560
564
|
i=end+n2;
|
|
561
565
|
return true
|
|
562
566
|
}
|
|
563
567
|
while (i< html.length){
|
|
564
568
|
if(i>=max) max=i;
|
|
565
569
|
else break;
|
|
566
570
|
if (parseScript()) continue
|
|
567
571
|
if (parseSpecial("<!--","-->",4,3,'#comment')) continue
|
|
568
572
|
if (parseSpecial("<style","</style>",7,8,'style')) continue
|
|
569
573
|
if (html.startsWith("<![CDATA[",i)){
|
|
570
574
|
const end=html.indexOf("]]>",i+9);
|
|
571
575
|
if (end===-1) break;
|
|
572
576
|
const content=html.substring(i+9,end);
|
|
573
577
|
const cdataNode=new SingleNode("#cdata-section",{},stack[stack.length-1]);
|
|
574
578
|
cdataNode.nodeValue=content;
|
|
575
579
|
i=end+3;
|
|
576
580
|
continue;
|
|
577
581
|
}
|
|
578
582
|
if (html.startsWith("<",i)){
|
|
579
583
|
if (currentText && stack[stack.length-1]){
|
|
580
584
|
const textNode=new TextNode(currentText)
|
|
581
585
|
stack[stack.length-1].childNodes.push(textNode);
|
|
582
586
|
textNode.parent=stack[stack.length-1]
|
|
583
587
|
currentText="";
|
|
584
588
|
}
|
|
585
589
|
let tagEnd=i+1;
|
|
586
590
|
let insideQuotes=false;
|
|
587
591
|
let quoteChar=null;
|
|
588
592
|
while (tagEnd< html.length){
|
|
589
593
|
const char=html[tagEnd];
|
|
590
594
|
if (!insideQuotes && (char==='"' || char==="'")){
|
|
591
595
|
insideQuotes=true;
|
|
592
596
|
quoteChar=char;
|
|
593
597
|
} else if (insideQuotes && char===quoteChar){
|
|
594
598
|
insideQuotes=false;
|
|
595
599
|
quoteChar=null;
|
|
596
600
|
}
|
|
597
601
|
if (!insideQuotes && char==='>') break;
|
|
598
602
|
tagEnd++;
|
|
599
603
|
}
|
|
600
604
|
const tagContent=html.substring(i+1,tagEnd);
|
|
601
605
|
if (tagContent.startsWith("/")) stack.pop();
|
|
602
606
|
else{
|
|
603
607
|
let isSelfClosing=tagContent.endsWith('/');
|
|
604
608
|
const tagNameEnd=tagContent.search(/\s|>|\//);
|
|
605
609
|
const tagName=tagContent.substring(0,tagNameEnd>0 ? tagNameEnd : tagEnd-i-1);
|
|
606
610
|
const attributesString=tagContent.substring(tagName.length,isSelfClosing ? tagContent.length-1 : tagContent.length).trim();
|
|
607
611
|
const attributes=parseAttributes(attributesString);
|
|
608
612
|
if (VOID_TAGS.has(tagName.toLowerCase()) || isSelfClosing) new SingleNode(tagName,attributes,stack[stack.length-1])
|
|
609
613
|
else stack.push(new Node(tagName,attributes,stack[stack.length-1]));
|
|
610
614
|
}
|
|
611
615
|
i=tagEnd+1;
|
|
612
616
|
} else{
|
|
613
617
|
currentText+=html[i];
|
|
614
618
|
i++;
|
|
615
619
|
}
|
|
616
620
|
}
|
|
617
621
|
if (currentText.trim() && stack[stack.length-1]) stack[stack.length-1].childNodes.push(new TextNode(currentText));
|
|
618
622
|
return root;
|
|
623
|
+
}
|
|
624
|
+
function buildFromCache(cached){
|
|
619
625
|
function buildNode(cache,parent=null){
|
|
620
626
|
if(typeof cache==='string') return parent.childNodes.push(cache)
|
|
621
627
|
const{isSingle,tagName,attributes,childNodes,textContent}=cache
|
|
622
628
|
if(textContent) return parent.childNodes.push(new TextNode(textContent))
|
|
623
629
|
if(isSingle) return parent.childNodes.push(new SingleNode(tagName,attributes))
|
|
624
630
|
const newDoc=tagName==='ROOT' ? new Root() : new Node(tagName,attributes,parent)
|
|
625
631
|
childNodes.forEach(childNode=>{
|
|
626
632
|
buildNode(childNode,newDoc)
|
|
627
633
|
});
|
|
628
634
|
return newDoc
|
|
629
635
|
}
|
|
630
636
|
return buildNode(cached)
|
|
637
|
+
}
|
|
631
638
|
|
|
639
|
+
function cacheDoc(doc){
|
|
632
640
|
const props=['isSingle','tagName','attributes']
|
|
633
641
|
function addToCache(element,cache={}){
|
|
634
642
|
if(typeof element==='string') return element
|
|
635
643
|
if(element.nodeName==='#text') return{textContent:element.textContent}
|
|
636
644
|
props.forEach(prop=>{
|
|
637
645
|
if(element[prop]) cache[prop]=element[prop]
|
|
638
646
|
});
|
|
639
647
|
if(!element.childNodes) return cache
|
|
640
648
|
cache.childNodes=[]
|
|
641
649
|
element.childNodes.forEach(childNode=>{
|
|
642
650
|
cache.childNodes.push(addToCache(childNode))
|
|
643
651
|
});
|
|
644
652
|
return cache
|
|
645
653
|
}
|
|
646
654
|
return addToCache(doc)
|
|
647
655
|
}
|
|
648
|
-
return { parseHTML, Node, Query, TextNode, SingleNode }
|
|
656
|
+
return { parseHTML, Node, Query, TextNode, SingleNode, buildFromCache, cacheDoc, Root }
|
|
649
657
|
})()
|