als-document 1.0.3-alpha → 1.0.4-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/index.js CHANGED
@@ -1,573 +1,33 @@
1
- class Query{
2
- static get(query){
3
- let q=new Query(query)
4
- return q.selectors
5
- }
6
- constructor(query){
7
- this.query=query
8
- this.selectors=[]
9
- this.stringValues=[];
10
- this.parseSelectors(query.split(','))
11
- }
12
- parseSelectors(selectors){
13
- selectors.forEach(selector=>{
14
- let originalSelector=selector.trim()
15
- selector=this.removeSpaces(selector)
16
- this.stringValues=[]
17
- selector=selector.replace(/\[.*?\]/g,(value)=>{
18
- this.stringValues.push(value)
19
- return `[${this.stringValues.length-1}]`
20
- })
21
- let [element,ancestors]=this.splitAndCutLast(selector,' ')
22
- element=this.getFamily(element)
23
- if (ancestors.length>0)
24
- element.ancestors=ancestors.map(ancestor=>this.getFamily(ancestor))
25
- element.group=originalSelector
26
- this.selectors.push(element)
27
- });
28
- }
29
- splitAndCutLast(string,splitBy){
30
- const array=string.split(splitBy);
31
- const last=array.pop();
32
- return [last,array];
33
- }
34
- getFamily(group,element,prev,prevAny,sign){
35
- if (group.match(/\~|\+/)!==null){
36
- let [last,prevBrothers]=this.splitAndCutLast(group,/\~|\+/)
37
- let signs=group.replace(last,'')
38
- prevBrothers.forEach(el=>signs=signs.replace(el,''))
39
- signs=signs.match(/\~|\+/g)
40
- if (signs.length==1){
41
- sign=signs[0]
42
- } else if (signs.length>1){
43
- sign=signs.splice(signs.length-1,signs.length-1)[0]
44
- prevBrothers[0]=prevBrothers.map((b,i)=>{
45
- if (i< prevBrothers.length-1) b+=signs[i]
46
- return b
47
- }).join('')
48
- prevBrothers[0]=this.getFamily(prevBrothers[0])
49
- }
50
- if (sign=='~') prevAny=prevBrothers[0]
51
- else if (sign=='+') prev=prevBrothers[0]
52
- element=last
53
- } else element=group
54
- let family
55
- if (prev || prevAny){
56
- family=this.getParents(element)
57
- if (prev) family.prev=this.getParents(prev)
58
- if (prevAny) family.prevAny=this.getParents(prevAny)
59
- } else family=this.getParents(element)
60
- if (family.query!==group) family.group=group
61
- return family
62
- }
63
- getParents(selector){
64
- if (typeof selector=='string'){
65
- let [element,parents]=this.splitAndCutLast(selector,'>')
66
- element=this.buildElement(element)
67
- parents=parents.map(parent=>this.buildElement(parent))
68
- if (parents.length>0) element.parents=parents
69
- return element
70
- } else return selector
71
- }
72
- buildElement(element,id=null,tag=null,classList=[]){
73
- let query=element
74
- element=element.replace(/\#(\w-?)*/,$id=>{
75
- id=$id.replace(/^\#/,''); return ''
76
- })
77
- element=element.replace(/\.(\w-?)*/,$class=>{
78
- classList.push($class.replace(/^\./,'')); return ''
79
- })
80
- element=element.replace(/(\w\:?-?)*/,$tag=>{
81
- tag=$tag=='' ? null : $tag; return ''
82
- })
83
- let attribs=this.getAttributes(element)
84
- element={ query }
85
- if (id) element.id=id
86
- if (tag) element.tag=tag
87
- if (classList.length>0) element.classList=classList
88
- if (attribs.length>0) element.attribs=attribs
89
- return element
90
- }
91
- getAttributes(element){
92
- let attribs=this.stringValues.filter((value,index)=>{
93
- let searchValue=`[${index}]`
94
- if (element.match(searchValue)) return true
95
- else return false
96
- })
97
- attribs=attribs.map(attrib=>{
98
- let query=attrib
99
- attrib=attrib.replace('[','').replace(']','')
100
- let [name,value]=attrib.split(/[\~\|\^\$\*]?\=/)
101
- let sign=attrib.replace(name,'').replace(value,'')
102
- attrib={ query }
103
- if (name) attrib.name=name
104
- if (value) attrib.value=value.trim().replace(/^\"/,'').replace(/\"$/,'')
105
- if (sign){
106
- attrib.sign=sign
107
- attrib.check=this.getAttribFn(sign).bind(attrib)
108
- }
109
- return attrib
110
- });
111
- return attribs
112
- }
113
- getAttribFn(sign){
114
- if (sign=='=') return function (value){ return value===this.value }
115
- if (sign=='*=') return function (value){ return value.includes(this.value) }
116
- if (sign=='^=') return function (value){ return value.startsWith(this.value) }
117
- if (sign=='$=') return function (value){ return value.endsWith(this.value) }
118
- if (sign=='|=') return function (value){
119
- return value.trim().split(' ').length==1
120
- && (value.startsWith(this.value) || value.startsWith(this.value+'-'))
121
- ? true : false
122
- }
123
- if (sign=='~=') return function (value){
124
- return this.value.trim().split(' ').length==1 && value.includes(this.value) ? true : false
125
- }
126
- }
127
- removeSpaces(selector){
128
- selector=selector.replace(/\s{2}/g,' ')
129
- selector=selector.replace(/\s?\^?\$?\|?\~?\*?\=\s*/g,(m)=>m.trim())
130
- selector=selector.replace(/\s?(\+|\~|\>)\s?/g,(m)=>m.trim())
131
- return selector
132
- }
133
- }
134
- function checkElement(el,selector){
135
- if(selector==undefined) return true
136
- if(el==null) return false
137
- let{tag,classList,attributes,id,prev,ancestors,parents,prevAny}=selector
138
- if(typeof el==='string') return false
139
- if(id!==undefined && el.id===null) return false
140
- if(id && id!==el.id) return false
141
- if(tag && el.tagName===undefined) return false
142
- else if(tag && tag!==el.tagName) return false
143
- const clas=el.attributes.class
144
- if(classList!==undefined && (clas===undefined || clas==='')) return false
145
- else if(classList!==undefined){
146
- if(classList.every(e=>el.classList.contains(e))===false) return false
147
- }
148
- if(checkattributes(attributes,el)===false) return false
149
- if(checkElement(el.prev,prev)===false) return false
150
- if(checkAncestors(el.ancestors,ancestors)===false) return false
151
- if(checkParents(el.ancestors,parents)===false) return false
152
- if(el.parent){
153
- if(checkPrevAny(el.parent.children,el.childIndex,prevAny)==false) return false
154
- }
155
- return true
156
- }
157
- function checkattributes(attributes=[],el){
158
- let elattributes=el.attributes
159
- let names=Object.keys(elattributes)
160
- let passedTests=0
161
- if(attributes) for(let i=0; i<attributes.length; i++){
162
- let{name,value,check}=attributes[i]
163
- if(name=='inner' && value!==undefined && check && el.inner){
164
- if(check(el.inner)) passedTests++
165
- }
166
- if(!names.includes(name)) continue
167
- else if(value==undefined) passedTests++
168
- else if(value && elattributes[name]){
169
- if(check(elattributes[name])==false) continue
170
- else passedTests++
171
- }
172
- }
173
- if(passedTests==attributes.length) return true
174
- else return false
175
- }
176
- function checkPrevAny(children=[],index,prevAny){
177
- let size=children.length
178
- if((size==0 || index==0) && prevAny) return false
179
- for(let i=index; i>=0; i--){
180
- if(checkElement(children[i],prevAny)) return true
181
- }
182
- return false
183
- }
184
- function checkAncestors(ancestors=[],selectorAncestors=[]){
185
- let count=0
186
- if(selectorAncestors.length==0) return true
187
- let endIndex=ancestors.length-1
188
- let selectorIndex=selectorAncestors.length-1
189
- while(selectorIndex>=0){
190
- for(let i=endIndex; i>=0; i--){
191
- endIndex=i-1
192
- if(checkElement(ancestors[i],selectorAncestors[selectorIndex])==true){
193
- count++
194
- break
195
- }
196
- }
197
- selectorIndex--
198
- }
199
- if(count==selectorAncestors.length) return true
200
- else return false
201
- }
202
- function checkParents(ancestors=[],selectorParents=[]){
203
- if(selectorParents.length===0) return true
204
- if(ancestors.length< selectorParents.length) return false
205
- let index=ancestors.length-1
206
- for(let i=selectorParents.length-1; i>=0; i--){
207
- if(checkElement(ancestors[index],selectorParents[i])===false) return false
208
- index--
209
- }
210
- return true
211
- }
1
+ class Query{
212
2
  static get(query){
213
3
  let q=new Query(query)
214
4
  return q.selectors
215
5
  }
216
6
  constructor(query){
217
7
  this.query=query
218
8
  this.selectors=[]
219
9
  this.stringValues=[];
220
10
  this.parseSelectors(query.split(','))
221
11
  }
222
12
  parseSelectors(selectors){
223
13
  selectors.forEach(selector=>{
224
14
  let originalSelector=selector.trim()
225
15
  selector=this.removeSpaces(selector)
226
16
  this.stringValues=[]
227
17
  selector=selector.replace(/\[.*?\]/g,(value)=>{
228
18
  this.stringValues.push(value)
229
19
  return `[${this.stringValues.length-1}]`
230
20
  })
231
21
  let [element,ancestors]=this.splitAndCutLast(selector,' ')
232
22
  element=this.getFamily(element)
233
23
  if (ancestors.length>0)
234
24
  element.ancestors=ancestors.map(ancestor=>this.getFamily(ancestor))
235
25
  element.group=originalSelector
236
26
  this.selectors.push(element)
237
27
  });
238
28
  }
239
29
  splitAndCutLast(string,splitBy){
240
30
  const array=string.split(splitBy);
241
31
  const last=array.pop();
242
32
  return [last,array];
243
33
  }
244
34
  getFamily(group,element,prev,prevAny,sign){
245
35
  if (group.match(/\~|\+/)!==null){
246
36
  let [last,prevBrothers]=this.splitAndCutLast(group,/\~|\+/)
247
37
  let signs=group.replace(last,'')
248
38
  prevBrothers.forEach(el=>signs=signs.replace(el,''))
249
39
  signs=signs.match(/\~|\+/g)
250
40
  if (signs.length==1){
251
41
  sign=signs[0]
252
42
  } else if (signs.length>1){
253
43
  sign=signs.splice(signs.length-1,signs.length-1)[0]
254
44
  prevBrothers[0]=prevBrothers.map((b,i)=>{
255
45
  if (i< prevBrothers.length-1) b+=signs[i]
256
46
  return b
257
47
  }).join('')
258
48
  prevBrothers[0]=this.getFamily(prevBrothers[0])
259
49
  }
260
50
  if (sign=='~') prevAny=prevBrothers[0]
261
51
  else if (sign=='+') prev=prevBrothers[0]
262
52
  element=last
263
53
  } else element=group
264
54
  let family
265
55
  if (prev || prevAny){
266
56
  family=this.getParents(element)
267
57
  if (prev) family.prev=this.getParents(prev)
268
58
  if (prevAny) family.prevAny=this.getParents(prevAny)
269
59
  } else family=this.getParents(element)
270
60
  if (family.query!==group) family.group=group
271
61
  return family
272
62
  }
273
63
  getParents(selector){
274
64
  if (typeof selector=='string'){
275
65
  let [element,parents]=this.splitAndCutLast(selector,'>')
276
66
  element=this.buildElement(element)
277
67
  parents=parents.map(parent=>this.buildElement(parent))
278
68
  if (parents.length>0) element.parents=parents
279
69
  return element
280
70
  } else return selector
281
71
  }
282
72
  buildElement(element,id=null,tag=null,classList=[]){
283
73
  let query=element
284
74
  element=element.replace(/\#(\w-?)*/,$id=>{
285
75
  id=$id.replace(/^\#/,''); return ''
286
76
  })
287
77
  element=element.replace(/\.(\w-?)*/,$class=>{
288
78
  classList.push($class.replace(/^\./,'')); return ''
289
79
  })
290
80
  element=element.replace(/(\w\:?-?)*/,$tag=>{
291
81
  tag=$tag=='' ? null : $tag; return ''
292
82
  })
293
83
  let attribs=this.getAttributes(element)
294
84
  element={ query }
295
85
  if (id) element.id=id
296
86
  if (tag) element.tag=tag
297
87
  if (classList.length>0) element.classList=classList
298
88
  if (attribs.length>0) element.attribs=attribs
299
89
  return element
300
90
  }
301
91
  getAttributes(element){
302
92
  let attribs=this.stringValues.filter((value,index)=>{
303
93
  let searchValue=`[${index}]`
304
94
  if (element.match(searchValue)) return true
305
95
  else return false
306
96
  })
307
97
  attribs=attribs.map(attrib=>{
308
98
  let query=attrib
309
99
  attrib=attrib.replace('[','').replace(']','')
310
100
  let [name,value]=attrib.split(/[\~\|\^\$\*]?\=/)
311
101
  let sign=attrib.replace(name,'').replace(value,'')
312
102
  attrib={ query }
313
103
  if (name) attrib.name=name
314
104
  if (value) attrib.value=value.trim().replace(/^\"/,'').replace(/\"$/,'')
315
105
  if (sign){
316
106
  attrib.sign=sign
317
107
  attrib.check=this.getAttribFn(sign).bind(attrib)
318
108
  }
319
109
  return attrib
320
110
  });
321
111
  return attribs
322
112
  }
323
113
  getAttribFn(sign){
324
114
  if (sign=='=') return function (value){ return value===this.value }
325
115
  if (sign=='*=') return function (value){ return value.includes(this.value) }
326
116
  if (sign=='^=') return function (value){ return value.startsWith(this.value) }
327
117
  if (sign=='$=') return function (value){ return value.endsWith(this.value) }
328
118
  if (sign=='|=') return function (value){
329
119
  return value.trim().split(' ').length==1
330
120
  && (value.startsWith(this.value) || value.startsWith(this.value+'-'))
331
121
  ? true : false
332
122
  }
333
123
  if (sign=='~=') return function (value){
334
124
  return this.value.trim().split(' ').length==1 && value.includes(this.value) ? true : false
335
125
  }
336
126
  }
337
127
  removeSpaces(selector){
338
128
  selector=selector.replace(/\s{2}/g,' ')
339
129
  selector=selector.replace(/\s?\^?\$?\|?\~?\*?\=\s*/g,(m)=>m.trim())
340
130
  selector=selector.replace(/\s?(\+|\~|\>)\s?/g,(m)=>m.trim())
341
131
  return selector
342
132
  }
133
+ }
134
+ function checkElement(el,selector){
343
135
  if(selector==undefined) return true
344
136
  if(el==null) return false
345
137
  let{tag,classList,attribs:attributes,id,prev,ancestors,parents,prevAny}=selector
346
138
  if(typeof el==='string') return false
347
139
  if(id!==undefined && el.id===null) return false
348
140
  if(id && id!==el.id) return false
349
141
  if(tag && el.tagName===undefined) return false
350
142
  else if(tag && tag!==el.tagName) return false
351
143
  const clas=el.attributes.class
352
144
  if(classList!==undefined && (clas===undefined || clas==='')) return false
353
145
  else if(classList!==undefined){
354
146
  if(classList.every(e=>el.classList.contains(e))===false) return false
355
147
  }
356
148
  if(checkattributes(attributes,el)===false) return false
357
149
  if(checkElement(el.prev,prev)===false) return false
358
150
  if(checkAncestors(el.ancestors,ancestors)===false) return false
359
151
  if(checkParents(el.ancestors,parents)===false) return false
360
152
  if(el.parent){
361
153
  if(checkPrevAny(el.parent.children,el.childIndex,prevAny)==false) return false
362
154
  }
363
155
  return true
156
+ }
364
157
  function checkattributes(attributes=[],el){
365
158
  let elattributes=el.attributes
366
159
  let names=Object.keys(elattributes)
367
160
  let passedTests=0
368
161
  if(attributes) for(let i=0; i<attributes.length; i++){
369
162
  let{name,value,check}=attributes[i]
370
163
  if(name=='inner' && value!==undefined && check && el.inner){
371
164
  if(check(el.inner)) passedTests++
372
165
  }
373
166
  if(!names.includes(name)) continue
374
167
  else if(value==undefined) passedTests++
375
168
  else if(value && elattributes[name]){
376
169
  if(check(elattributes[name])==false) continue
377
170
  else passedTests++
378
171
  }
379
172
  }
380
173
  if(passedTests==attributes.length) return true
381
174
  else return false
175
+ }
382
176
  function checkPrevAny(children=[],index,prevAny){
383
177
  let size=children.length
384
178
  if((size==0 || index==0) && prevAny) return false
385
179
  for(let i=index; i>=0; i--){
386
180
  if(checkElement(children[i],prevAny)) return true
387
181
  }
388
182
  return false
183
+ }
389
184
  function checkAncestors(ancestors=[],selectorAncestors=[]){
390
185
  let count=0
391
186
  if(selectorAncestors.length==0) return true
392
187
  let endIndex=ancestors.length-1
393
188
  let selectorIndex=selectorAncestors.length-1
394
189
  while(selectorIndex>=0){
395
190
  for(let i=endIndex; i>=0; i--){
396
191
  endIndex=i-1
397
192
  if(checkElement(ancestors[i],selectorAncestors[selectorIndex])==true){
398
193
  count++
399
194
  break
400
195
  }
401
196
  }
402
197
  selectorIndex--
403
198
  }
404
199
  if(count==selectorAncestors.length) return true
405
200
  else return false
201
+ }
406
202
  function checkParents(ancestors=[],selectorParents=[]){
407
203
  if(selectorParents.length===0) return true
408
204
  if(ancestors.length< selectorParents.length) return false
409
205
  let index=ancestors.length-1
410
206
  for(let i=selectorParents.length-1; i>=0; i--){
411
207
  if(checkElement(ancestors[index],selectorParents[i])===false) return false
412
208
  index--
413
209
  }
414
210
  return true
211
+ }
415
212
  const getDataName=prop=>'data-'+prop.toLowerCase()
416
- function getDataset(element){
417
- return new Proxy(element.attributes,{
418
- get: (target,prop)=>{return target[getDataName(prop)]},set: (target,prop,value)=>{target[getDataName(prop)]=value; return true},deleteProperty: (target,prop)=>{
419
- const dataAttr=getDataName(prop)
420
- if (dataAttr in target){
421
- delete target[dataAttr];
422
- return true;
423
- }
424
- return false;
425
- }
426
- });
427
- }
428
-
429
- function find(selectors,element,collection,first=false,firstTime=true){
430
- for(let selector of selectors){
431
- if(checkElement(element,selector)) collection.add(element)
432
- }
433
- if(element.children)
434
- element.children.forEach(child=>{
435
- if(first && collection.size>0) return
436
- find(selectors,child,collection,first,false)
437
- })
438
- return firstTime ? [...collection] : collection
439
- }
440
- class TextNode{
441
- constructor(data){
442
- this.nodeName='#text';
443
- this.parent=null;
444
- this.textContent=data;
445
- }
446
- get nodeValue(){return this.textContent}
447
- get parentNode(){return this.parent}
448
- }
449
-
450
- function buildStyle(attributes){
451
- const styles=attributes.style || "";
452
- const camelToKebab=str=>str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g,'$1-$2').toLowerCase();
453
- const kebabToCamel=str=>str.replace(/-([a-z])/g,g=>g[1].toUpperCase());
454
- const baseStyleObj=styles.split(";").reduce((acc,style)=>{
455
- const [key,value]=style.split(":").map(s=>s.trim());
456
- if (key && value) acc[kebabToCamel(key)]=value;
457
- return acc;
458
- },{});
459
- return new Proxy(baseStyleObj,{
460
- get: (obj,prop)=>obj[camelToKebab(prop)] || obj[prop],set: (obj,prop,value)=>{
461
- obj[camelToKebab(prop)]=value;
462
- attributes.style=Object.entries(obj).map(([k,v])=>`${camelToKebab(k)}: ${v}`).join("; ");
463
- return true;
464
- },deleteProperty: (obj,prop)=>{
465
- delete obj[camelToKebab(prop)];
466
- attributes.style=Object.entries(obj).map(([k,v])=>`${camelToKebab(k)}: ${v}`).join("; ");
467
- return true;
468
- }
469
- });
470
- }
471
-
472
- class NodeClassList{
473
- constructor(node){ this.node=node }
474
- get classes(){ return (this.node.attributes.class || "").split(" ").filter(Boolean) }
475
- set classes(val){ this.node.attributes.class=val.join(" ") }
476
- contains(className){ return this.classes.includes(className) }
477
- add(className){
478
- const currentClasses=this.classes;
479
- if (!currentClasses.includes(className)) this.classes=[...currentClasses,className];
480
- }
481
- remove(className){ this.classes=this.classes.filter(cls=>cls!==className); }
482
- toggle(className){
483
- if (this.classes.includes(className)) this.remove(className);
484
- else this.add(className);
485
- }
486
- replace(oldClass,newClass){
487
- if (this.classes.includes(oldClass)){
488
- this.remove(oldClass);
489
- this.add(newClass);
490
- }
491
- }
492
- }
493
- class Node{
494
- constructor(tagName,attributes={},parent=null){
495
- this.isSingle=false;
496
- this.tagName=tagName;
497
- this.attributes=attributes;
498
- this.childNodes=[];
499
- if (parent!==null) parent.childNodes.push(this)
500
- this.parent=parent;
501
- this._classList=null;
502
- this.__style=null;
503
- this._dataset=null
504
- }
505
- get id(){ return this.attributes.id || null; }
506
- get className(){return this.attributes.class || null}
507
- get parentNode(){ return this.parent }
508
- get ancestors(){
509
- const ancestors=[]
510
- let element=this.parent
511
- while (element.tagName!=='ROOT'){
512
- ancestors.push(element)
513
- element=element.parent
514
- }
515
- return ancestors.reverse()
516
- }
517
- get childIndex(){ return this.parent.childNodes ? this.parent.childNodes.indexOf(this) : null }
518
- get previousElementSibling(){ return this.prev }
519
- get prev(){
520
- if (!this.childIndex) return null
521
- return this.parent.childNodes[this.childIndex-1]
522
- }
523
- get nextElementSibling(){ return this.next }
524
- get next(){
525
- if (!this.childIndex) return null
526
- return this.parent.childNodes[this.childIndex+1] || null
527
- }
528
- get dataset(){
529
- if (!this._dataset) this._dataset=getDataset(this);
530
- return this._dataset;
531
- }
532
- get classList(){
533
- if (!this._classList) this._classList=new NodeClassList(this);
534
- return this._classList;
535
- }
536
- get style(){
537
- if (!this.__style) this.__style=buildStyle(this.attributes)
538
- return this.__style
539
- }
540
- get outerHTML(){
541
- const attrs=Object.entries(this.attributes).map(([key,val])=>`${key}="${val}"`).join(" ");
542
- return `<${this.tagName} ${attrs}>${this.innerHTML}</${this.tagName}>`;
543
- }
544
- getAttribute(attrName){ return this.attributes[attrName] || null }
545
- setAttribute(attrName,value){ this.attributes[attrName]=value }
546
- removeAttribute(attrName){ delete this.attributes[attrName] }
547
- remove(){
548
- if (!this.parent) return
549
- const index=this.childIndex;
550
- if (index!==null) this.parent.childNodes.splice(index,1);
551
- }
552
- get innerHTML(){
553
- return this.childNodes.map(child=>{
554
- if (child instanceof Node || child instanceof SingleNode) return child.outerHTML;
555
- else if (child instanceof TextNode) return child.textContent;
556
- else return child
557
- }).join("");
558
- }
559
- $$(query){return this.querySelectorAll(query)}
560
- querySelectorAll(query){
561
- const selectors=Query.get(query)
562
- return find(selectors,this,new Set())
563
- }
564
- $(query){return this.querySelector(query)}
565
- querySelector(query){
566
- const selectors=Query.get(query)
567
- return find(selectors,this,new Set(),true)[0] || null
568
- }
569
- getElementsByClassName(query){ return this.querySelectorAll('.'+query) }
570
- getElementsByTagName(query){ return this.querySelectorAll(query) }
571
- getElementById(query){ return this.querySelector('#'+query) }
572
- get children(){
573
- return this.childNodes.filter(child=>{
574
- if (!(child instanceof Node)) return false
575
- if (child.tagName==='#comment') return false
576
- return true
577
- });
578
- }
579
- insertAdjacentElement(position,newElement){
580
- if(newElement.tagName==='ROOT' && newElement.childNodes.length>0) newElement=newElement.childNodes[0]
581
- const pos=position.toLowerCase();
582
- if (pos==="afterbegin") this.childNodes.unshift(newElement);
583
- else if (pos==="beforeend") this.childNodes.push(newElement);
584
- if (!this.parent) return newElement
585
- if (pos==="beforebegin") this.parent.childNodes.unshift(newElement);
586
- else if (pos==="afterend") this.parent.childNodes.splice(this.childIndex+1,0,newElement);
587
- return newElement
588
- }
589
- insertAdjacentHTML(position,html){
590
- const newNode=parseHTML(html);
591
- newNode.childNodes.reverse().forEach(node=>{
592
- this.insertAdjacentElement(position,node);
593
- });
594
- return newNode
595
- }
596
- insertAdjacentText(position,text){
597
- return this.insertAdjacentElement(position,new TextNode(text));
598
- }
599
- set innerHTML(html){
600
- const parsed=parseHTML(html);
601
- this.childNodes=parsed.childNodes;
602
- }
603
- set outerHTML(html){
604
- const parsed=parseHTML(html);
605
- if (!this.parent) return console.log('element has no parent node')
606
- const index=this.childIndex
607
- if (index!==null) this.parent.childNodes.splice(index,1,...parsed.childNodes);
608
- }
609
- appendChild(newChild){
610
- if (newChild instanceof Node || newChild instanceof TextNode || newChild instanceof SingleNode){
611
- if (newChild.parent) newChild.parent.childNodes=newChild.parent.childNodes.filter(child=>child!==newChild);
612
- } else if(typeof newChild==='string') newChild=new TextNode(newChild)
613
- else return newChild
614
- this.childNodes.push(newChild);
615
- newChild.parent=this;
616
- return newChild;
617
- }
618
- get textContent(){
619
- if (this.childNodes.length===0) return this.nodeName==='#text' ? this.nodeValue : '';
620
- return this.childNodes.map(child=>{
621
- if(child instanceof SingleNode) return ''
622
- if(child instanceof TextNode) return child.nodeValue
623
- if(child instanceof Node) return child.textContent;
624
- else return child;
625
- }).join(" ");
626
- }
627
- set textContent(value){
628
- this.childNodes=[];
629
- if (value!==null && value!==undefined){
630
- this.childNodes.push(value.toString());
631
- }
632
- }
633
- }
634
- class SingleNode extends Node{
635
- constructor(tagName,attributes={},parent=null){
636
- if(attributes['?'] && tagName==='?xml') delete attributes['?']
637
- super(tagName,attributes,parent);
638
- this.isSingle=true
639
- }
640
- get outerHTML(){
641
- if (this.tagName==="#cdata-section") return `<![CDATA[${this.nodeValue}]]>`;
642
- const attrs=Object.entries(this.attributes).map(([key,val])=>`${key}="${val}"`).join(" ");
643
- return `<${this.tagName} ${attrs}${this.tagName==='?xml' ? '?' : ''}>`;
644
- }
645
- get innerHTML(){ return ""; }
646
- set innerHTML(_){ }
647
- $(_){return null}
648
- $$(_){return []}
649
- querySelectorAll(_){ return []; }
650
- querySelector(_){ return null; }
651
- getElementsByClassName(_){ return []; }
652
- getElementsByTagName(_){ return []; }
653
- getElementById(_){ return null; }
654
- get children(){ return []; }
655
- insertAdjacentElement(_,__){ }
656
- insertAdjacentHTML(_,__){ }
657
- insertAdjacentText(_,__){ }
658
- appendChild(_){ }
659
- get textContent(){ return ""; }
660
- set textContent(_){ }
661
- }
662
- function parseAttributes(str){
663
- const attrs={};
664
- let key="";
665
- let value="";
666
- let isKey=true;
667
- let quoteChar=null;
668
- for (let i=0; i< str.length; i++){
669
- const char=str[i];
670
- if (isKey && (char==='=' || char===' ')){
671
- if (char==='=') isKey=false;
672
- else if (key.trim()){
673
- attrs[key.trim()]=true;
674
- key="";
675
- }
676
- continue;
677
- }
678
- if (!quoteChar && (char==='"' || char==="'")){
679
- quoteChar=char;
680
- continue;
681
- } else if (quoteChar && char===quoteChar){
682
- quoteChar=null;
683
- attrs[key.trim()]=value.trim();
684
- key=""; value=""; isKey=true;
685
- continue;
686
- }
687
- if (isKey) key+=char;
688
- else value+=char;
689
- }
690
- if (key.trim() &&!value) attrs[key.trim()]=true;
691
- return attrs;
692
- }
693
- const VOID_TAGS=new Set(["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr","!doctype",'?xml']);
694
- function parseHTML(html){
695
- const root=new Node("ROOT");
696
- const stack=[root];
697
- let currentText="",i=0;
698
- let max=0
699
- function parseScript(){
700
- if (!html.startsWith("<script",i)) return false;
701
- const openTagEnd=html.indexOf(">",i);
702
- if (openTagEnd===-1) return false;
703
- const attributesString=html.substring(i+7,openTagEnd).trim();
704
- const attributes=parseAttributes(attributesString);
705
- let closeTagStart=html.indexOf("</script>",openTagEnd);
706
- if (closeTagStart===-1) return false;
707
- const content=html.substring(openTagEnd+1,closeTagStart);
708
- const scriptNode=new Node('script',attributes,stack[stack.length-1]);
709
- if(content.length>0) scriptNode.childNodes.push(content);
710
- i=closeTagStart+9;
711
- return true;
712
- }
713
- function parseSpecial(startStr,endStr,n1,n2,tag){
714
- if (!html.startsWith(startStr,i)) return false
715
- const end=html.indexOf(endStr,i+n1);
716
- const strNode=new Node(tag,{},stack[stack.length-1]);
717
- strNode.childNodes.push(html.substring(i+n1,end));
718
- i=end+n2;
719
- return true
720
- }
721
- while (i< html.length){
722
- if(i>=max) max=i;
723
- else break;
724
- if (parseScript()) continue
725
- if (parseSpecial("<!--","-->",4,3,'#comment')) continue
726
- if (parseSpecial("<style","</style>",7,8,'style')) continue
727
- if (html.startsWith("<![CDATA[",i)){
728
- const end=html.indexOf("]]>",i+9);
729
- if (end===-1) break;
730
- const content=html.substring(i+9,end);
731
- const cdataNode=new SingleNode("#cdata-section",{},stack[stack.length-1]);
732
- cdataNode.nodeValue=content;
733
- i=end+3;
734
- continue;
735
- }
736
- if (html.startsWith("<",i)){
737
- if (currentText.trim()){
738
- stack[stack.length-1].childNodes.push(new TextNode(currentText.trim()));
739
- currentText="";
740
- }
741
- let tagEnd=i+1;
742
- let insideQuotes=false;
743
- let quoteChar=null;
744
- while (tagEnd< html.length){
745
- const char=html[tagEnd];
746
- if (!insideQuotes && (char==='"' || char==="'")){
747
- insideQuotes=true;
748
- quoteChar=char;
749
- } else if (insideQuotes && char===quoteChar){
750
- insideQuotes=false;
751
- quoteChar=null;
752
- }
753
- if (!insideQuotes && char==='>') break;
754
- tagEnd++;
755
- }
756
- const tagContent=html.substring(i+1,tagEnd);
757
- if (tagContent.startsWith("/")) stack.pop();
758
- else{
759
- let isSelfClosing=tagContent.endsWith('/');
760
- const tagNameEnd=tagContent.search(/\s|>|\//);
761
- const tagName=tagContent.substring(0,tagNameEnd>0 ? tagNameEnd : tagEnd-i-1);
762
- const attributesString=tagContent.substring(tagName.length,isSelfClosing ? tagContent.length-1 : tagContent.length).trim();
763
- const attributes=parseAttributes(attributesString);
764
- if (VOID_TAGS.has(tagName.toLowerCase()) || isSelfClosing) new SingleNode(tagName,attributes,stack[stack.length-1])
765
- else stack.push(new Node(tagName,attributes,stack[stack.length-1]));
766
- }
767
- i=tagEnd+1;
768
- } else{
769
- currentText+=html[i];
770
- i++;
771
- }
772
- }
773
- if (currentText.trim()) stack[stack.length-1].childNodes.push(new TextNode(currentText.trim()));
774
- return root;
775
- }
213
+ function getDataset(element){
776
214
  return new Proxy(element.attributes,{
777
215
  get: (target,prop)=>{return target[getDataName(prop)]},set: (target,prop,value)=>{target[getDataName(prop)]=value; return true},deleteProperty: (target,prop)=>{
778
216
  const dataAttr=getDataName(prop)
779
217
  if (dataAttr in target){
780
218
  delete target[dataAttr];
781
219
  return true;
782
220
  }
783
221
  return false;
784
222
  }
785
223
  });
224
+ }
225
+
226
+ function find(selectors,element,collection,first=false,firstTime=true){
786
227
  for(let selector of selectors){
787
228
  if(checkElement(element,selector)) collection.add(element)
788
229
  }
789
230
  if(element.children)
790
231
  element.children.forEach(child=>{
791
232
  if(first && collection.size>0) return
792
233
  find(selectors,child,collection,first,false)
793
234
  })
794
235
  return firstTime ? [...collection] : collection
236
+ }
237
+ class TextNode{
795
238
  constructor(data){
796
239
  this.nodeName='#text';
797
240
  this.parent=null;
798
241
  this.textContent=data;
799
242
  }
800
243
  get nodeValue(){return this.textContent}
801
244
  get parentNode(){return this.parent}
245
+ }
246
+
247
+ function buildStyle(attributes){
802
248
  const styles=attributes.style || "";
803
249
  const camelToKebab=str=>str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g,'$1-$2').toLowerCase();
804
250
  const kebabToCamel=str=>str.replace(/-([a-z])/g,g=>g[1].toUpperCase());
805
251
  const baseStyleObj=styles.split(";").reduce((acc,style)=>{
806
252
  const [key,value]=style.split(":").map(s=>s.trim());
807
253
  if (key && value) acc[kebabToCamel(key)]=value;
808
254
  return acc;
809
255
  },{});
810
256
  return new Proxy(baseStyleObj,{
811
257
  get: (obj,prop)=>obj[camelToKebab(prop)] || obj[prop],set: (obj,prop,value)=>{
812
258
  obj[camelToKebab(prop)]=value;
813
259
  attributes.style=Object.entries(obj).map(([k,v])=>`${camelToKebab(k)}: ${v}`).join("; ");
814
260
  return true;
815
261
  },deleteProperty: (obj,prop)=>{
816
262
  delete obj[camelToKebab(prop)];
817
263
  attributes.style=Object.entries(obj).map(([k,v])=>`${camelToKebab(k)}: ${v}`).join("; ");
818
264
  return true;
819
265
  }
820
266
  });
267
+ }
268
+
269
+ class NodeClassList{
821
270
  constructor(node){ this.node=node }
822
271
  get classes(){ return (this.node.attributes.class || "").split(" ").filter(Boolean) }
823
272
  set classes(val){ this.node.attributes.class=val.join(" ") }
824
273
  contains(className){ return this.classes.includes(className) }
825
274
  add(className){
826
275
  const currentClasses=this.classes;
827
276
  if (!currentClasses.includes(className)) this.classes=[...currentClasses,className];
828
277
  }
829
278
  remove(className){ this.classes=this.classes.filter(cls=>cls!==className); }
830
279
  toggle(className){
831
280
  if (this.classes.includes(className)) this.remove(className);
832
281
  else this.add(className);
833
282
  }
834
283
  replace(oldClass,newClass){
835
284
  if (this.classes.includes(oldClass)){
836
285
  this.remove(oldClass);
837
286
  this.add(newClass);
838
287
  }
839
288
  }
289
+ }
290
+ function insertBefore(arr,index,newItem){
840
291
  const existingIndex=arr.indexOf(newItem);
841
292
  if (existingIndex!==-1) arr.splice(existingIndex,1);
842
293
  arr.splice(index,0,newItem);
294
+ }
843
295
  class Node{
844
296
  constructor(tagName,attributes={},parent=null){
845
297
  this.isSingle=false;
846
298
  this.tagName=tagName;
847
299
  this.attributes=attributes;
848
300
  this.childNodes=[];
849
301
  if (parent!==null) parent.childNodes.push(this)
850
302
  this.parent=parent;
851
303
  this._classList=null;
852
304
  this.__style=null;
853
305
  this._dataset=null
854
306
  }
855
307
  get id(){ return this.attributes.id ? this.attributes.id : null; }
856
308
  set id(newValue){ this.attributes.id=newValue; }
857
309
  get className(){return this.attributes.class || null}
858
310
  get parentNode(){ return this.parent }
859
311
  get ancestors(){
860
312
  if(!this.parent) return []
861
313
  const ancestors=[]
862
314
  let element=this.parent
863
315
  while (element.tagName!=='ROOT'){
864
316
  ancestors.push(element)
865
317
  element=element.parent
866
318
  }
867
319
  return ancestors.reverse()
868
320
  }
869
321
  get childNodeIndex(){
870
322
  if(!this.parent) return null
871
323
  return this.parent.childNodes ? this.parent.childNodes.indexOf(this) : null
872
324
  }
873
325
  get childIndex(){
874
326
  if(!this.parent) return null
875
327
  return this.parent.children ? this.parent.children.indexOf(this) : null
876
328
  }
877
329
  get previousElementSibling(){ return this.prev }
878
330
  get prev(){
879
331
  if (!this.childIndex) return null
880
332
  return this.parent.children[this.childIndex-1]
881
333
  }
882
334
  get nextElementSibling(){ return this.next }
883
335
  get next(){
884
336
  if (!this.childIndex) return null
885
337
  return this.parent.children[this.childIndex+1] || null
886
338
  }
887
339
  get dataset(){
888
340
  if (!this._dataset) this._dataset=getDataset(this);
889
341
  return this._dataset;
890
342
  }
891
343
  get classList(){
892
344
  if (!this._classList) this._classList=new NodeClassList(this);
893
345
  return this._classList;
894
346
  }
895
347
  get style(){
896
348
  if (!this.__style) this.__style=buildStyle(this.attributes)
897
349
  return this.__style
898
350
  }
899
351
  get outerHTML(){
900
352
  const attrs=Object.entries(this.attributes).map(([key,val])=>`${key}="${val}"`).join(" ");
901
353
  return `<${this.tagName}${attrs ? ' '+attrs : ''}>${this.innerHTML}</${this.tagName}>`;
902
354
  }
903
355
  getAttribute(attrName){ return this.attributes[attrName] || null }
904
356
  setAttribute(attrName,value){ this.attributes[attrName]=value }
905
357
  removeAttribute(attrName){ delete this.attributes[attrName] }
906
358
  remove(){
907
359
  if (!this.parent) return
908
360
  const index=this.childIndex;
909
361
  if (index!==null) this.parent.childNodes.splice(index,1);
910
362
  }
911
363
  get innerHTML(){
912
364
  return this.childNodes.map(child=>{
913
365
  if (child instanceof Node || child instanceof SingleNode) return child.outerHTML;
914
366
  else if (child instanceof TextNode) return child.textContent;
915
367
  else return child
916
368
  }).join("");
917
369
  }
918
370
  $$(query){return this.querySelectorAll(query)}
919
371
  querySelectorAll(query){
920
372
  const selectors=Query.get(query)
921
373
  return find(selectors,this,new Set())
922
374
  }
923
375
  $(query){return this.querySelector(query)}
924
376
  querySelector(query){
925
377
  const selectors=Query.get(query)
926
378
  return find(selectors,this,new Set(),true)[0] || null
927
379
  }
928
380
  getElementsByClassName(query){ return this.querySelectorAll('.'+query) }
929
381
  getElementsByTagName(query){ return this.querySelectorAll(query) }
930
382
  getElementById(query){ return this.querySelector('#'+query) }
931
383
  get children(){
932
384
  return this.childNodes.filter(child=>{
933
385
  if (!(child instanceof Node)) return false
934
386
  if (child.tagName==='#comment') return false
935
387
  return true
936
388
  });
937
389
  }
938
390
  insertAdjacentElement(position,newElement){
939
391
  if(newElement.tagName==='ROOT' && newElement.childNodes.length>0) newElement=newElement.childNodes[0]
940
392
  const pos=position.toLowerCase();
941
393
  if (pos==="afterbegin") this.childNodes.unshift(newElement);
942
394
  else if (pos==="beforeend") this.childNodes.push(newElement);
943
395
  newElement.parent=this
944
396
  if (!this.parent) return newElement
945
397
  if (pos==="beforebegin") insertBefore(this.parent.childNodes,this.childNodeIndex,newElement)
946
398
  else if (pos==="afterend") this.parent.childNodes.splice(this.childNodeIndex+1,0,newElement);
947
399
  newElement.parent=this.parent
948
400
  return newElement
949
401
  }
950
402
  insertAdjacentHTML(position,html){
951
403
  const newNode=parseHTML(html);
952
404
  newNode.childNodes.reverse().forEach(node=>{
953
405
  this.insertAdjacentElement(position,node);
954
406
  });
955
407
  return newNode
956
408
  }
957
409
  insertAdjacentText(position,text){
958
410
  return this.insertAdjacentElement(position,new TextNode(text));
959
411
  }
960
412
  set innerHTML(html){
961
413
  const parsed=parseHTML(html);
962
414
  this.childNodes=parsed.childNodes;
963
415
  }
964
416
  set outerHTML(html){
965
417
  const parsed=parseHTML(html);
966
418
  if (!this.parent) return console.log('element has no parent node')
967
419
  const index=this.childIndex
968
420
  if (index!==null) this.parent.childNodes.splice(index,1,...parsed.childNodes);
969
421
  }
970
422
  appendChild(newChild){
971
423
  if (newChild instanceof Node || newChild instanceof TextNode || newChild instanceof SingleNode){
972
424
  if (newChild.parent) newChild.parent.childNodes=newChild.parent.childNodes.filter(child=>child!==newChild);
973
425
  } else if(typeof newChild==='string') newChild=new TextNode(newChild)
974
426
  else return newChild
975
427
  this.childNodes.push(newChild);
976
428
  newChild.parent=this;
977
429
  return newChild;
978
430
  }
979
431
  get textContent(){
980
432
  if (this.childNodes.length===0) return this.nodeName==='#text' ? this.nodeValue : '';
981
433
  return this.childNodes.map(child=>{
982
434
  if(child instanceof SingleNode) return ''
983
435
  if(child instanceof TextNode) return child.nodeValue
984
436
  if(child instanceof Node) return child.textContent;
985
437
  else return child;
986
438
  }).join(" ");
987
439
  }
988
440
  set textContent(value){
989
441
  this.childNodes=[];
990
442
  if (value!==null && value!==undefined){
991
443
  this.childNodes.push(value.toString());
992
444
  }
993
445
  }
446
+ }
447
+ class SingleNode extends Node{
994
448
  constructor(tagName,attributes={},parent=null){
995
449
  if(attributes['?'] && tagName==='?xml') delete attributes['?']
996
450
  super(tagName,attributes,parent);
997
451
  this.isSingle=true
998
452
  }
999
453
  get outerHTML(){
1000
454
  if (this.tagName==="#cdata-section") return `<![CDATA[${this.nodeValue}]]>`;
1001
455
  const attrs=Object.entries(this.attributes).map(([key,val])=>`${key}="${val}"`).join(" ");
1002
456
  return `<${this.tagName} ${attrs}${this.tagName==='?xml' ? '?' : ''}>`;
1003
457
  }
1004
458
  get innerHTML(){ return ""; }
1005
459
  set innerHTML(_){ }
1006
460
  $(_){return null}
1007
461
  $$(_){return []}
1008
462
  querySelectorAll(_){ return []; }
1009
463
  querySelector(_){ return null; }
1010
464
  getElementsByClassName(_){ return []; }
1011
465
  getElementsByTagName(_){ return []; }
1012
466
  getElementById(_){ return null; }
1013
467
  get children(){ return []; }
1014
468
  insertAdjacentElement(_,__){ }
1015
469
  insertAdjacentHTML(_,__){ }
1016
470
  insertAdjacentText(_,__){ }
1017
471
  appendChild(_){ }
1018
472
  get textContent(){ return ""; }
1019
473
  set textContent(_){ }
474
+ }
475
+ function parseAttributes(str){
1020
476
  const attrs={};
1021
477
  let key="";
1022
478
  let value="";
1023
479
  let isKey=true;
1024
480
  let quoteChar=null;
1025
481
  for (let i=0; i< str.length; i++){
1026
482
  const char=str[i];
1027
483
  if (isKey && (char==='=' || char===' ')){
1028
484
  if (char==='=') isKey=false;
1029
485
  else if (key.trim()){
1030
486
  attrs[key.trim()]=true;
1031
487
  key="";
1032
488
  }
1033
489
  continue;
1034
490
  }
1035
491
  if (!quoteChar && (char==='"' || char==="'")){
1036
492
  quoteChar=char;
1037
493
  continue;
1038
494
  } else if (quoteChar && char===quoteChar){
1039
495
  quoteChar=null;
1040
496
  attrs[key.trim()]=value.trim();
1041
497
  key=""; value=""; isKey=true;
1042
498
  continue;
1043
499
  }
1044
500
  if (isKey) key+=char;
1045
501
  else value+=char;
1046
502
  }
1047
503
  if (key.trim() &&!value) attrs[key.trim()]=true;
1048
504
  return attrs;
505
+ }
506
+ const VOID_TAGS=new Set(["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr","!doctype",'?xml']);
507
+ function parseHTML(html){
1049
508
  const root=new Node("ROOT");
1050
509
  const stack=[root];
1051
510
  let currentText="",i=0;
1052
511
  let max=0
1053
512
  function parseScript(){
1054
513
  if (!html.startsWith("<script",i)) return false;
1055
514
  const openTagEnd=html.indexOf(">",i);
1056
515
  if (openTagEnd===-1) return false;
1057
516
  const attributesString=html.substring(i+7,openTagEnd).trim();
1058
517
  const attributes=parseAttributes(attributesString);
1059
518
  let closeTagStart=html.indexOf("</script>",openTagEnd);
1060
519
  if (closeTagStart===-1) return false;
1061
520
  const content=html.substring(openTagEnd+1,closeTagStart);
1062
521
  const scriptNode=new Node('script',attributes,stack[stack.length-1]);
1063
522
  if(content.length>0) scriptNode.childNodes.push(content);
1064
523
  i=closeTagStart+9;
1065
524
  return true;
1066
525
  }
1067
526
  function parseSpecial(startStr,endStr,n1,n2,tag){
1068
527
  if (!html.startsWith(startStr,i)) return false
1069
528
  const end=html.indexOf(endStr,i+n1);
1070
529
  const strNode=new Node(tag,{},stack[stack.length-1]);
1071
530
  strNode.childNodes.push(html.substring(i+n1,end));
1072
531
  i=end+n2;
1073
532
  return true
1074
533
  }
1075
534
  while (i< html.length){
1076
535
  if(i>=max) max=i;
1077
536
  else break;
1078
537
  if (parseScript()) continue
1079
538
  if (parseSpecial("<!--","-->",4,3,'#comment')) continue
1080
539
  if (parseSpecial("<style","</style>",7,8,'style')) continue
1081
540
  if (html.startsWith("<![CDATA[",i)){
1082
541
  const end=html.indexOf("]]>",i+9);
1083
542
  if (end===-1) break;
1084
543
  const content=html.substring(i+9,end);
1085
544
  const cdataNode=new SingleNode("#cdata-section",{},stack[stack.length-1]);
1086
545
  cdataNode.nodeValue=content;
1087
546
  i=end+3;
1088
547
  continue;
1089
548
  }
1090
549
  if (html.startsWith("<",i)){
1091
550
  if (currentText){
1092
551
  stack[stack.length-1].childNodes.push(new TextNode(currentText));
1093
552
  currentText="";
1094
553
  }
1095
554
  let tagEnd=i+1;
1096
555
  let insideQuotes=false;
1097
556
  let quoteChar=null;
1098
557
  while (tagEnd< html.length){
1099
558
  const char=html[tagEnd];
1100
559
  if (!insideQuotes && (char==='"' || char==="'")){
1101
560
  insideQuotes=true;
1102
561
  quoteChar=char;
1103
562
  } else if (insideQuotes && char===quoteChar){
1104
563
  insideQuotes=false;
1105
564
  quoteChar=null;
1106
565
  }
1107
566
  if (!insideQuotes && char==='>') break;
1108
567
  tagEnd++;
1109
568
  }
1110
569
  const tagContent=html.substring(i+1,tagEnd);
1111
570
  if (tagContent.startsWith("/")) stack.pop();
1112
571
  else{
1113
572
  let isSelfClosing=tagContent.endsWith('/');
1114
573
  const tagNameEnd=tagContent.search(/\s|>|\//);
1115
574
  const tagName=tagContent.substring(0,tagNameEnd>0 ? tagNameEnd : tagEnd-i-1);
1116
575
  const attributesString=tagContent.substring(tagName.length,isSelfClosing ? tagContent.length-1 : tagContent.length).trim();
1117
576
  const attributes=parseAttributes(attributesString);
1118
577
  if (VOID_TAGS.has(tagName.toLowerCase()) || isSelfClosing) new SingleNode(tagName,attributes,stack[stack.length-1])
1119
578
  else stack.push(new Node(tagName,attributes,stack[stack.length-1]));
1120
579
  }
1121
580
  i=tagEnd+1;
1122
581
  } else{
1123
582
  currentText+=html[i];
1124
583
  i++;
1125
584
  }
1126
585
  }
1127
586
  if (currentText.trim()) stack[stack.length-1].childNodes.push(new TextNode(currentText));
1128
587
  return root;
588
+ }
1129
589
  module.exports = { parseHTML, Node, Query, TextNode, SingleNode }