als-document 1.0.1-alpha → 1.0.2-alpha

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 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,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,9 +21,9 @@ 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
+ class Node{
182
182
  constructor(tagName,attributes={},parent=null){
183
183
  this.isSingle=false;
184
184
  this.tagName=tagName;
185
185
  this.attributes=attributes;
186
186
  this.childNodes=[];
187
187
  if (parent!==null) parent.childNodes.push(this)
188
188
  this.parent=parent;
189
189
  this._classList=null;
190
190
  this.__style=null;
191
191
  this._dataset=null
192
192
  }
193
193
  get id(){ return this.attributes.id || null; }
194
194
  get className(){return this.attributes.class || null}
195
195
  get parentNode(){ return this.parent }
196
196
  get ancestors(){
197
197
  const ancestors=[]
198
198
  let element=this.parent
199
199
  while (element.tagName!=='ROOT'){
200
200
  ancestors.push(element)
201
201
  element=element.parent
202
202
  }
203
203
  return ancestors.reverse()
204
204
  }
205
205
  get childIndex(){ return this.parent.childNodes ? this.parent.childNodes.indexOf(this) : null }
206
206
  get previousElementSibling(){ return this.prev }
207
207
  get prev(){
208
208
  if (!this.childIndex) return null
209
209
  return this.parent.childNodes[this.childIndex-1]
210
210
  }
211
211
  get nextElementSibling(){ return this.next }
212
212
  get next(){
213
213
  if (!this.childIndex) return null
214
214
  return this.parent.childNodes[this.childIndex+1] || null
215
215
  }
216
216
  get dataset(){
217
217
  if (!this._dataset) this._dataset=getDataset(this);
218
218
  return this._dataset;
219
219
  }
220
220
  get classList(){
221
221
  if (!this._classList) this._classList=new NodeClassList(this);
222
222
  return this._classList;
223
223
  }
224
224
  get style(){
225
225
  if (!this.__style) this.__style=buildStyle(this.attributes)
226
226
  return this.__style
227
227
  }
228
228
  get outerHTML(){
229
229
  const attrs=Object.entries(this.attributes).map(([key,val])=>`${key}="${val}"`).join(" ");
230
230
  return `<${this.tagName} ${attrs}>${this.innerHTML}</${this.tagName}>`;
231
231
  }
232
232
  getAttribute(attrName){ return this.attributes[attrName] || null }
233
233
  setAttribute(attrName,value){ this.attributes[attrName]=value }
234
234
  removeAttribute(attrName){ delete this.attributes[attrName] }
235
235
  remove(){
236
236
  if (!this.parent) return
237
237
  const index=this.childIndex;
238
238
  if (index!==null) this.parent.childNodes.splice(index,1);
239
239
  }
240
240
  get innerHTML(){
241
241
  return this.childNodes.map(child=>{
242
242
  if (child instanceof Node || child instanceof SingleNode) return child.outerHTML;
243
243
  else if (child instanceof TextNode) return child.textContent;
244
244
  else return child
245
245
  }).join("");
246
246
  }
247
247
  $$(query){return this.querySelectorAll(query)}
248
248
  querySelectorAll(query){
249
249
  const selectors=Query.get(query)
250
250
  return find(selectors,this,new Set())
251
251
  }
252
252
  $(query){return this.querySelector(query)}
253
253
  querySelector(query){
254
254
  const selectors=Query.get(query)
255
255
  return find(selectors,this,new Set(),true)[0] || null
256
256
  }
257
257
  getElementsByClassName(query){ return this.querySelectorAll('.'+query) }
258
258
  getElementsByTagName(query){ return this.querySelectorAll(query) }
259
259
  getElementById(query){ return this.querySelector('#'+query) }
260
260
  get children(){
261
261
  return this.childNodes.filter(child=>{
262
262
  if (!(child instanceof Node)) return false
263
263
  if (child.tagName==='#comment') return false
264
264
  return true
265
265
  });
266
266
  }
267
267
  insertAdjacentElement(position,newElement){
268
268
  if(newElement.tagName==='ROOT' && newElement.childNodes.length>0) newElement=newElement.childNodes[0]
269
269
  const pos=position.toLowerCase();
270
270
  if (pos==="afterbegin") this.childNodes.unshift(newElement);
271
271
  else if (pos==="beforeend") this.childNodes.push(newElement);
272
272
  if (!this.parent) return newElement
273
273
  if (pos==="beforebegin") this.parent.childNodes.unshift(newElement);
274
274
  else if (pos==="afterend") this.parent.childNodes.splice(this.childIndex+1,0,newElement);
275
275
  return newElement
276
276
  }
277
277
  insertAdjacentHTML(position,html){
278
278
  const newNode=parseHTML(html);
279
279
  return this.insertAdjacentElement(position,newNode);
280
280
  }
281
281
  insertAdjacentText(position,text){
282
282
  return this.insertAdjacentElement(position,new TextNode(text));
283
283
  }
284
284
  set innerHTML(html){
285
285
  const parsed=parseHTML(html);
286
286
  this.childNodes=parsed.childNodes;
287
287
  }
288
288
  set outerHTML(html){
289
289
  const parsed=parseHTML(html);
290
290
  if (!this.parent) return console.log('element has no parent node')
291
291
  const index=this.childIndex
292
292
  if (index!==null) this.parent.childNodes.splice(index,1,...parsed.childNodes);
293
293
  }
294
294
  appendChild(newChild){
295
295
  if (newChild instanceof Node || newChild instanceof TextNode || newChild instanceof SingleNode){
296
296
  if (newChild.parent) newChild.parent.childNodes=newChild.parent.childNodes.filter(child=>child!==newChild);
297
297
  } else if(typeof newChild==='string') newChild=new TextNode(newChild)
298
298
  else return newChild
299
299
  this.childNodes.push(newChild);
300
300
  newChild.parent=this;
301
301
  return newChild;
302
302
  }
303
303
  get textContent(){
304
304
  if (this.childNodes.length===0) return this.nodeName==='#text' ? this.nodeValue : '';
305
305
  return this.childNodes.map(child=>{
306
306
  if(child instanceof SingleNode) return ''
307
307
  if(child instanceof TextNode) return child.nodeValue
308
308
  if(child instanceof Node) return child.textContent;
309
309
  else return child;
310
310
  }).join(" ");
311
311
  }
312
312
  set textContent(value){
313
313
  this.childNodes=[];
314
314
  if (value!==null && value!==undefined){
315
315
  this.childNodes.push(value.toString());
316
316
  }
317
317
  }
318
318
  }
319
- class SingleNode extends Node{
320
319
  constructor(tagName,attributes={},parent=null){
321
320
  if(attributes['?'] && tagName==='?xml') delete attributes['?']
322
321
  super(tagName,attributes,parent);
323
322
  this.isSingle=true
324
323
  }
325
324
  get outerHTML(){
326
325
  if (this.tagName==="#cdata-section") return `<![CDATA[${this.textContent}]]>`;
327
326
  const attrs=Object.entries(this.attributes).map(([key,val])=>`${key}="${val}"`).join(" ");
328
327
  return `<${this.tagName} ${attrs}${this.tagName==='?xml' ? '?' : ''}>`;
329
328
  }
330
329
  get innerHTML(){ return ""; }
331
330
  set innerHTML(_){ }
332
331
  $(_){return null}
333
332
  $$(_){return []}
334
333
  querySelectorAll(_){ return []; }
335
334
  querySelector(_){ return null; }
336
335
  getElementsByClassName(_){ return []; }
337
336
  getElementsByTagName(_){ return []; }
338
337
  getElementById(_){ return null; }
339
338
  get children(){ return []; }
340
339
  insertAdjacentElement(_,__){ }
341
340
  insertAdjacentHTML(_,__){ }
342
341
  insertAdjacentText(_,__){ }
343
342
  appendChild(_){ }
344
343
  get textContent(){ return ""; }
345
344
  set textContent(_){ }
345
+ class SingleNode extends Node{
346
346
  constructor(tagName,attributes={},parent=null){
347
347
  if(attributes['?'] && tagName==='?xml') delete attributes['?']
348
348
  super(tagName,attributes,parent);
349
349
  this.isSingle=true
350
350
  }
351
351
  get outerHTML(){
352
352
  if (this.tagName==="#cdata-section") return `<![CDATA[${this.nodeValue}]]>`;
353
353
  const attrs=Object.entries(this.attributes).map(([key,val])=>`${key}="${val}"`).join(" ");
354
354
  return `<${this.tagName} ${attrs}${this.tagName==='?xml' ? '?' : ''}>`;
355
355
  }
356
356
  get innerHTML(){ return ""; }
357
357
  set innerHTML(_){ }
358
358
  $(_){return null}
359
359
  $$(_){return []}
360
360
  querySelectorAll(_){ return []; }
361
361
  querySelector(_){ return null; }
362
362
  getElementsByClassName(_){ return []; }
363
363
  getElementsByTagName(_){ return []; }
364
364
  getElementById(_){ return null; }
365
365
  get children(){ return []; }
366
366
  insertAdjacentElement(_,__){ }
367
367
  insertAdjacentHTML(_,__){ }
368
368
  insertAdjacentText(_,__){ }
369
369
  appendChild(_){ }
370
370
  get textContent(){ return ""; }
371
371
  set textContent(_){ }
372
372
  }
373
373
  function parseAttributes(str){
374
374
  const attrs={};
375
375
  let key="";
376
376
  let value="";
377
377
  let isKey=true;
378
378
  let quoteChar=null;
379
379
  for (let i=0; i< str.length; i++){
380
380
  const char=str[i];
381
381
  if (isKey && (char==='=' || char===' ')){
382
382
  if (char==='=') isKey=false;
383
383
  else if (key.trim()){
384
384
  attrs[key.trim()]=true;
385
385
  key="";
386
386
  }
387
387
  continue;
388
388
  }
389
389
  if (!quoteChar && (char==='"' || char==="'")){
390
390
  quoteChar=char;
391
391
  continue;
392
392
  } else if (quoteChar && char===quoteChar){
393
393
  quoteChar=null;
394
394
  attrs[key.trim()]=value.trim();
395
395
  key=""; value=""; isKey=true;
396
396
  continue;
397
397
  }
398
398
  if (isKey) key+=char;
399
399
  else value+=char;
400
400
  }
401
401
  if (key.trim() &&!value) attrs[key.trim()]=true;
402
402
  return attrs;
403
403
  }