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