als-document 1.0.5-alpha → 1.0.7-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
@@ -22,14 +22,14 @@ function buildStyle(attributes){
22
22
  const styles=attributes.style || "";
23
23
  con
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
45
  function insertBefore(arr,index,newItem){
46
46
  const existingIndex=arr.indexOf(newItem);
47
47
  if (existingIndex!==-1) arr.splice(existingIndex,1);
48
48
  arr.splice(index,0,newItem);
49
- }
50
49
  class Node{
51
50
  constructor(tagName,attributes={},parent=null){
52
51
  this.isSingle=false;
53
52
  this.tagName=tagName;
54
53
  this.attributes=attributes;
55
54
  this.childNodes=[];
56
55
  if (parent!==null) parent.childNodes.push(this)
57
56
  this.parent=parent;
58
57
  this._classList=null;
59
58
  this.__style=null;
60
59
  this._dataset=null
61
60
  }
62
61
  get id(){ return this.attributes.id ? this.attributes.id : null; }
63
62
  set id(newValue){ this.attributes.id=newValue; }
64
63
  get className(){return this.attributes.class || null}
65
64
  get parentNode(){ return this.parent }
66
65
  get ancestors(){
67
66
  if(!this.parent) return []
68
67
  const ancestors=[]
69
68
  let element=this.parent
70
69
  while (element.tagName!=='ROOT'){
71
70
  ancestors.push(element)
72
71
  element=element.parent
73
72
  }
74
73
  return ancestors.reverse()
75
74
  }
76
75
  get childNodeIndex(){
77
76
  if(!this.parent) return null
78
77
  return this.parent.childNodes ? this.parent.childNodes.indexOf(this) : null
79
78
  }
80
79
  get childIndex(){
81
80
  if(!this.parent) return null
82
81
  return this.parent.children ? this.parent.children.indexOf(this) : null
83
82
  }
84
83
  get previousElementSibling(){ return this.prev }
85
84
  get prev(){
86
85
  if (!this.childIndex) return null
87
86
  return this.parent.children[this.childIndex-1]
88
87
  }
89
88
  get nextElementSibling(){ return this.next }
90
89
  get next(){
91
90
  if (!this.childIndex) return null
92
91
  return this.parent.children[this.childIndex+1] || null
93
92
  }
94
93
  get dataset(){
95
94
  if (!this._dataset) this._dataset=getDataset(this);
96
95
  return this._dataset;
97
96
  }
98
97
  get classList(){
99
98
  if (!this._classList) this._classList=new NodeClassList(this);
100
99
  return this._classList;
101
100
  }
102
101
  get style(){
103
102
  if (!this.__style) this.__style=buildStyle(this.attributes)
104
103
  return this.__style
105
104
  }
106
105
  get outerHTML(){
107
106
  const attrs=Object.entries(this.attributes).map(([key,val])=>`${key}="${val}"`).join(" ");
108
107
  return `<${this.tagName}${attrs ? ' '+attrs : ''}>${this.innerHTML}</${this.tagName}>`;
109
108
  }
110
109
  getAttribute(attrName){ return this.attributes[attrName] || null }
111
110
  setAttribute(attrName,value){ this.attributes[attrName]=value }
112
111
  removeAttribute(attrName){ delete this.attributes[attrName] }
113
112
  remove(){
114
113
  if (!this.parent) return
115
114
  const index=this.childIndex;
116
115
  if (index!==null) this.parent.childNodes.splice(index,1);
117
116
  }
118
117
  get innerHTML(){
119
118
  return this.childNodes.map(child=>{
120
119
  if (child instanceof Node || child instanceof SingleNode) return child.outerHTML;
121
120
  else if (child instanceof TextNode) return child.textContent;
122
121
  else return child
123
122
  }).join("");
124
123
  }
125
124
  $$(query){return this.querySelectorAll(query)}
126
125
  querySelectorAll(query){
127
126
  const selectors=Query.get(query)
128
127
  return find(selectors,this,new Set())
129
128
  }
130
129
  $(query){return this.querySelector(query)}
131
130
  querySelector(query){
132
131
  const selectors=Query.get(query)
133
132
  return find(selectors,this,new Set(),true)[0] || null
134
133
  }
135
134
  getElementsByClassName(query){ return this.querySelectorAll('.'+query) }
136
135
  getElementsByTagName(query){ return this.querySelectorAll(query) }
137
136
  getElementById(query){ return this.querySelector('#'+query) }
138
137
  get children(){
139
138
  return this.childNodes.filter(child=>{
140
139
  if (!(child instanceof Node)) return false
141
140
  if (child.tagName==='#comment') return false
142
141
  return true
143
142
  });
144
143
  }
145
144
  insertAdjacentElement(position,newElement){
146
145
  if(newElement.tagName==='ROOT' && newElement.childNodes.length>0) newElement=newElement.childNodes[0]
147
146
  const pos=position.toLowerCase();
148
147
  if (pos==="afterbegin") this.childNodes.unshift(newElement);
149
148
  else if (pos==="beforeend") this.childNodes.push(newElement);
150
149
  newElement.parent=this
151
150
  if (!this.parent) return newElement
152
151
  if (pos==="beforebegin") insertBefore(this.parent.childNodes,this.childNodeIndex,newElement)
153
152
  else if (pos==="afterend") this.parent.childNodes.splice(this.childNodeIndex+1,0,newElement);
154
153
  newElement.parent=this.parent
155
154
  return newElement
156
155
  }
157
156
  insertAdjacentHTML(position,html){
158
157
  const newNode=parseHTML(html);
159
158
  newNode.childNodes.reverse().forEach(node=>{
160
159
  this.insertAdjacentElement(position,node);
161
160
  });
162
161
  return newNode
163
162
  }
164
163
  insertAdjacentText(position,text){
165
164
  return this.insertAdjacentElement(position,new TextNode(text));
166
165
  }
167
166
  set innerHTML(html){
168
167
  const parsed=parseHTML(html);
169
168
  this.childNodes=parsed.childNodes;
170
169
  }
171
170
  set outerHTML(html){
172
171
  const parsed=parseHTML(html);
173
172
  if (!this.parent) return console.log('element has no parent node')
174
173
  const index=this.childIndex
175
174
  if (index!==null) this.parent.childNodes.splice(index,1,...parsed.childNodes);
176
175
  }
177
176
  appendChild(newChild){
178
177
  if (newChild instanceof Node || newChild instanceof TextNode || newChild instanceof SingleNode){
179
178
  if (newChild.parent) newChild.parent.childNodes=newChild.parent.childNodes.filter(child=>child!==newChild);
180
179
  } else if(typeof newChild==='string') newChild=new TextNode(newChild)
181
180
  else return newChild
182
181
  this.childNodes.push(newChild);
183
182
  newChild.parent=this;
184
183
  return newChild;
185
184
  }
186
185
  get textContent(){
187
186
  if (this.childNodes.length===0) return this.nodeName==='#text' ? this.nodeValue : '';
188
187
  return this.childNodes.map(child=>{
189
188
  if(child instanceof SingleNode) return ''
190
189
  if(child instanceof TextNode) return child.nodeValue
191
190
  if(child instanceof Node) return child.textContent;
192
191
  else return child;
193
192
  }).join(" ");
194
193
  }
195
194
  set textContent(value){
196
195
  this.childNodes=[];
197
196
  if (value!==null && value!==undefined){
198
197
  this.childNodes.push(value.toString());
199
198
  }
200
199
  }
200
+ }
201
201
  class Node{
202
202
  constructor(tagName,attributes={},parent=null){
203
203
  this.isSingle=false;
204
204
  this.tagName=tagName;
205
205
  this.attributes=attributes;
206
206
  this.childNodes=[];
207
207
  if (parent!==null) parent.childNodes.push(this)
208
208
  this.parent=parent;
209
209
  this._classList=null;
210
210
  this.__style=null;
211
211
  this._dataset=null
212
212
  }
213
213
  get id(){ return this.attributes.id ? this.attributes.id : null; }
214
214
  set id(newValue){ this.attributes.id=newValue; }
215
215
  get className(){return this.attributes.class || null}
216
216
  get parentNode(){ return this.parent }
217
217
  get ancestors(){
218
218
  if(!this.parent) return []
219
219
  const ancestors=[]
220
220
  let element=this.parent
221
221
  while (element.tagName!=='ROOT'){
222
222
  ancestors.push(element)
223
223
  element=element.parent
224
224
  }
225
225
  return ancestors.reverse()
226
226
  }
227
227
  get childNodeIndex(){
228
228
  if(!this.parent) return null
229
229
  return this.parent.childNodes ? this.parent.childNodes.indexOf(this) : null
230
230
  }
231
231
  get childIndex(){
232
232
  if(!this.parent) return null
233
233
  return this.parent.children ? this.parent.children.indexOf(this) : null
234
234
  }
235
235
  get previousElementSibling(){ return this.prev }
236
236
  get prev(){
237
237
  if (!this.childIndex) return null
238
238
  return this.parent.children[this.childIndex-1]
239
239
  }
240
240
  get nextElementSibling(){ return this.next }
241
241
  get next(){
242
242
  if (!this.childIndex) return null
243
243
  return this.parent.children[this.childIndex+1] || null
244
244
  }
245
245
  get dataset(){
246
246
  if (!this._dataset) this._dataset=getDataset(this);
247
247
  return this._dataset;
248
248
  }
249
249
  get classList(){
250
250
  if (!this._classList) this._classList=new NodeClassList(this);
251
251
  return this._classList;
252
252
  }
253
253
  get style(){
254
254
  if (!this.__style) this.__style=buildStyle(this.attributes)
255
255
  return this.__style
256
256
  }
257
257
  get outerHTML(){
258
258
  const attrs=Object.entries(this.attributes).map(([key,val])=>`${key}="${val}"`).join(" ");
259
259
  return `<${this.tagName}${attrs ? ' '+attrs : ''}>${this.innerHTML}</${this.tagName}>`;
260
260
  }
261
261
  getAttribute(attrName){ return this.attributes[attrName] || null }
262
262
  setAttribute(attrName,value){ this.attributes[attrName]=value }
263
263
  removeAttribute(attrName){ delete this.attributes[attrName] }
264
264
  remove(){
265
265
  if (!this.parent) return
266
266
  const index=this.childNodeIndex;
267
267
  if (index!==null) this.parent.childNodes.splice(index,1);
268
268
  }
269
269
  get innerHTML(){
270
270
  return this.childNodes.map(child=>{
271
271
  if (child instanceof Node || child instanceof SingleNode) return child.outerHTML;
272
272
  else if (child instanceof TextNode) return child.textContent;
273
273
  else return child
274
274
  }).join("");
275
275
  }
276
276
  $$(query){return this.querySelectorAll(query)}
277
277
  querySelectorAll(query){
278
278
  const selectors=Query.get(query)
279
279
  return find(selectors,this,new Set())
280
280
  }
281
281
  $(query){return this.querySelector(query)}
282
282
  querySelector(query){
283
283
  const selectors=Query.get(query)
284
284
  return find(selectors,this,new Set(),true)[0] || null
285
285
  }
286
286
  getElementsByClassName(query){ return this.querySelectorAll('.'+query) }
287
287
  getElementsByTagName(query){ return this.querySelectorAll(query) }
288
288
  getElementById(query){ return this.querySelector('#'+query) }
289
289
  get children(){
290
290
  return this.childNodes.filter(child=>{
291
291
  if (!(child instanceof Node)) return false
292
292
  if (child.tagName==='#comment') return false
293
293
  return true
294
294
  });
295
295
  }
296
296
  insertAdjacentElement(position,newElement){
297
297
  if(newElement.tagName==='ROOT' && newElement.childNodes.length>0) newElement=newElement.childNodes[0]
298
298
  const pos=position.toLowerCase();
299
299
  if (pos==="afterbegin") this.childNodes.unshift(newElement);
300
300
  else if (pos==="beforeend") this.childNodes.push(newElement);
301
301
  newElement.parent=this
302
302
  if (!this.parent) return newElement
303
303
  if (pos==="beforebegin") insertBefore(this.parent.childNodes,this.childNodeIndex,newElement)
304
304
  else if (pos==="afterend") this.parent.childNodes.splice(this.childNodeIndex+1,0,newElement);
305
305
  newElement.parent=this.parent
306
306
  return newElement
307
307
  }
308
308
  insertAdjacentHTML(position,html){
309
309
  const newNode=parseHTML(html);
310
310
  newNode.childNodes.reverse().forEach(node=>{
311
311
  this.insertAdjacentElement(position,node);
312
312
  });
313
313
  return newNode
314
314
  }
315
315
  insertAdjacentText(position,text){
316
316
  return this.insertAdjacentElement(position,new TextNode(text));
317
317
  }
318
318
  set innerHTML(html){
319
319
  const parsed=parseHTML(html);
320
320
  this.childNodes=parsed.childNodes;
321
321
  }
322
322
  set outerHTML(html){
323
323
  const parsed=parseHTML(html);
324
324
  if (!this.parent) return console.log('element has no parent node')
325
325
  const index=this.childIndex
326
326
  if (index!==null) this.parent.childNodes.splice(index,1,...parsed.childNodes);
327
327
  }
328
328
  appendChild(newChild){
329
329
  if (newChild instanceof Node || newChild instanceof TextNode || newChild instanceof SingleNode){
330
330
  if (newChild.parent) newChild.parent.childNodes=newChild.parent.childNodes.filter(child=>child!==newChild);
331
331
  } else if(typeof newChild==='string') newChild=new TextNode(newChild)
332
332
  else return newChild
333
333
  this.childNodes.push(newChild);
334
334
  newChild.parent=this;
335
335
  return newChild;
336
336
  }
337
337
  get textContent(){
338
338
  if (this.childNodes.length===0) return this.nodeName==='#text' ? this.nodeValue : '';
339
339
  return this.childNodes.map(child=>{
340
340
  if(child instanceof SingleNode) return ''
341
341
  if(child instanceof TextNode) return child.nodeValue
342
342
  if(child instanceof Node) return child.textContent;
343
343
  else return child;
344
344
  }).join(" ");
345
345
  }
346
346
  set textContent(value){
347
347
  this.childNodes=[];
348
348
  if (value!==null && value!==undefined){
349
349
  this.childNodes.push(value.toString());
350
350
  }
351
351
  }
352
352
  }
353
353
  class SingleNode extends Node{
354
354
  constructor(tagName,attributes={},parent=null){
355
355
  if(attributes['?'] && tagName==='?xml') delete attributes['?']
356
356
  super(tagName,attributes,parent);
357
357
  this.isSingle=true
358
358
  }
359
359
  get outerHTML(){
360
360
  if (this.tagName==="#cdata-section") return `<![CDATA[${this.nodeValue}]]>`;
361
361
  const attrs=Object.entries(this.attributes).map(([key,val])=>`${key}="${val}"`).join(" ");
362
362
  return `<${this.tagName} ${attrs}${this.tagName==='?xml' ? '?' : ''}>`;
363
363
  }
364
364
  get innerHTML(){ return ""; }
365
365
  set innerHTML(_){ }
366
366
  $(_){return null}
367
367
  $$(_){return []}
368
368
  querySelectorAll(_){ return []; }
369
369
  querySelector(_){ return null; }
370
370
  getElementsByClassName(_){ return []; }
371
371
  getElementsByTagName(_){ return []; }
372
372
  getElementById(_){ return null; }
373
373
  get children(){ return []; }
374
374
  insertAdjacentElement(_,__){ }
375
375
  insertAdjacentHTML(_,__){ }
376
376
  insertAdjacentText(_,__){ }
377
377
  appendChild(_){ }
378
378
  get textContent(){ return ""; }
379
379
  set textContent(_){ }
380
380
  }
381
381
  function parseAttributes(str){
382
382
  const attrs={};
383
383
  let key="";
384
384
  let value="";
385
385
  let isKey=true;
386
386
  let quoteChar=null;
387
387
  for (let i=0; i< str.length; i++){
388
388
  const char=str[i];
389
389
  if (isKey && (char==='=' || char===' ')){
390
390
  if (char==='=') isKey=false;
391
391
  else if (key.trim()){
392
392
  attrs[key.trim()]=true;
393
393
  key="";
394
394
  }
395
395
  continue;
396
396
  }
397
397
  if (!quoteChar && (char==='"' || char==="'")){
398
398
  quoteChar=char;
399
399
  continue;
400
400
  } else if (quoteChar && char===quoteChar){
401
401
  quoteChar=null;
402
402
  attrs[key.trim()]=value.trim();
403
403
  key=""; value=""; isKey=true;
404
404
  continue;
405
405
  }
406
406
  if (isKey) key+=char;
407
407
  else value+=char;
408
408
  }
409
409
  if (key.trim() &&!value) attrs[key.trim()]=true;
410
410
  return attrs;
411
411
  }
412
412
  const VOID_TAGS=new Set(["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr","!doctype",'?xml']);
413
- function parseHTML(html){
414
413
  const root=new Node("ROOT");
415
414
  const stack=[root];
416
415
  let currentText="",i=0;
417
416
  let max=0
418
417
  function parseScript(){
419
418
  if (!html.startsWith("<script",i)) return false;
420
419
  const openTagEnd=html.indexOf(">",i);
421
420
  if (openTagEnd===-1) return false;
422
421
  const attributesString=html.substring(i+7,openTagEnd).trim();
423
422
  const attributes=parseAttributes(attributesString);
424
423
  let closeTagStart=html.indexOf("</script>",openTagEnd);
425
424
  if (closeTagStart===-1) return false;
426
425
  const content=html.substring(openTagEnd+1,closeTagStart);
427
426
  const scriptNode=new Node('script',attributes,stack[stack.length-1]);
428
427
  if(content.length>0) scriptNode.childNodes.push(content);
429
428
  i=closeTagStart+9;
430
429
  return true;
431
430
  }
432
431
  function parseSpecial(startStr,endStr,n1,n2,tag){
433
432
  if (!html.startsWith(startStr,i)) return false
434
433
  const end=html.indexOf(endStr,i+n1);
435
434
  const strNode=new Node(tag,{},stack[stack.length-1]);
436
435
  strNode.childNodes.push(html.substring(i+n1,end));
437
436
  i=end+n2;
438
437
  return true
439
438
  }
440
439
  while (i< html.length){
441
440
  if(i>=max) max=i;
442
441
  else break;
443
442
  if (parseScript()) continue
444
443
  if (parseSpecial("<!--","-->",4,3,'#comment')) continue
445
444
  if (parseSpecial("<style","</style>",7,8,'style')) continue
446
445
  if (html.startsWith("<![CDATA[",i)){
447
446
  const end=html.indexOf("]]>",i+9);
448
447
  if (end===-1) break;
449
448
  const content=html.substring(i+9,end);
450
449
  const cdataNode=new SingleNode("#cdata-section",{},stack[stack.length-1]);
451
450
  cdataNode.nodeValue=content;
452
451
  i=end+3;
453
452
  continue;
454
453
  }
455
454
  if (html.startsWith("<",i)){
456
455
  if (currentText && stack[stack.length-1]){
457
456
  stack[stack.length-1].childNodes.push(new TextNode(currentText));
458
457
  currentText="";
459
458
  }
460
459
  let tagEnd=i+1;
461
460
  let insideQuotes=false;
462
461
  let quoteChar=null;
463
462
  while (tagEnd< html.length){
464
463
  const char=html[tagEnd];
465
464
  if (!insideQuotes && (char==='"' || char==="'")){
466
465
  insideQuotes=true;
467
466
  quoteChar=char;
468
467
  } else if (insideQuotes && char===quoteChar){
469
468
  insideQuotes=false;
470
469
  quoteChar=null;
471
470
  }
472
471
  if (!insideQuotes && char==='>') break;
473
472
  tagEnd++;
474
473
  }
475
474
  const tagContent=html.substring(i+1,tagEnd);
476
475
  if (tagContent.startsWith("/")) stack.pop();
477
476
  else{
478
477
  let isSelfClosing=tagContent.endsWith('/');
479
478
  const tagNameEnd=tagContent.search(/\s|>|\//);
480
479
  const tagName=tagContent.substring(0,tagNameEnd>0 ? tagNameEnd : tagEnd-i-1);
481
480
  const attributesString=tagContent.substring(tagName.length,isSelfClosing ? tagContent.length-1 : tagContent.length).trim();
482
481
  const attributes=parseAttributes(attributesString);
483
482
  if (VOID_TAGS.has(tagName.toLowerCase()) || isSelfClosing) new SingleNode(tagName,attributes,stack[stack.length-1])
484
483
  else stack.push(new Node(tagName,attributes,stack[stack.length-1]));
485
484
  }
486
485
  i=tagEnd+1;
487
486
  } else{
488
487
  currentText+=html[i];
489
488
  i++;
490
489
  }
491
490
  }
492
491
  if (currentText.trim() && stack[stack.length-1]) stack[stack.length-1].childNodes.push(new TextNode(currentText));
493
492
  return root;
493
+ function parseHTML(html){
494
494
  const root=new Node("ROOT");
495
495
  const stack=[root];
496
496
  let currentText="",i=0;
497
497
  let max=0
498
498
  function parseScript(){
499
499
  if (!html.startsWith("<script",i)) return false;
500
500
  const openTagEnd=html.indexOf(">",i);
501
501
  if (openTagEnd===-1) return false;
502
502
  const attributesString=html.substring(i+7,openTagEnd).trim();
503
503
  const attributes=parseAttributes(attributesString);
504
504
  let closeTagStart=html.indexOf("</script>",openTagEnd);
505
505
  if (closeTagStart===-1) return false;
506
506
  const content=html.substring(openTagEnd+1,closeTagStart);
507
507
  const scriptNode=new Node('script',attributes,stack[stack.length-1]);
508
508
  if(content.length>0) scriptNode.childNodes.push(content);
509
509
  i=closeTagStart+9;
510
510
  return true;
511
511
  }
512
512
  function parseSpecial(startStr,endStr,n1,n2,tag){
513
513
  if (!html.startsWith(startStr,i)) return false
514
514
  const end=html.indexOf(endStr,i+n1);
515
515
  const strNode=new Node(tag,{},stack[stack.length-1]);
516
516
  strNode.childNodes.push(html.substring(i+n1,end));
517
517
  i=end+n2;
518
518
  return true
519
519
  }
520
520
  while (i< html.length){
521
521
  if(i>=max) max=i;
522
522
  else break;
523
523
  if (parseScript()) continue
524
524
  if (parseSpecial("<!--","-->",4,3,'#comment')) continue
525
525
  if (parseSpecial("<style","</style>",7,8,'style')) continue
526
526
  if (html.startsWith("<![CDATA[",i)){
527
527
  const end=html.indexOf("]]>",i+9);
528
528
  if (end===-1) break;
529
529
  const content=html.substring(i+9,end);
530
530
  const cdataNode=new SingleNode("#cdata-section",{},stack[stack.length-1]);
531
531
  cdataNode.nodeValue=content;
532
532
  i=end+3;
533
533
  continue;
534
534
  }
535
535
  if (html.startsWith("<",i)){
536
536
  if (currentText && stack[stack.length-1]){
537
537
  const textNode=new TextNode(currentText)
538
538
  stack[stack.length-1].childNodes.push(textNode);
539
539
  textNode.parent=stack[stack.length-1]
540
540
  currentText="";
541
541
  }
542
542
  let tagEnd=i+1;
543
543
  let insideQuotes=false;
544
544
  let quoteChar=null;
545
545
  while (tagEnd< html.length){
546
546
  const char=html[tagEnd];
547
547
  if (!insideQuotes && (char==='"' || char==="'")){
548
548
  insideQuotes=true;
549
549
  quoteChar=char;
550
550
  } else if (insideQuotes && char===quoteChar){
551
551
  insideQuotes=false;
552
552
  quoteChar=null;
553
553
  }
554
554
  if (!insideQuotes && char==='>') break;
555
555
  tagEnd++;
556
556
  }
557
557
  const tagContent=html.substring(i+1,tagEnd);
558
558
  if (tagContent.startsWith("/")) stack.pop();
559
559
  else{
560
560
  let isSelfClosing=tagContent.endsWith('/');
561
561
  const tagNameEnd=tagContent.search(/\s|>|\//);
562
562
  const tagName=tagContent.substring(0,tagNameEnd>0 ? tagNameEnd : tagEnd-i-1);
563
563
  const attributesString=tagContent.substring(tagName.length,isSelfClosing ? tagContent.length-1 : tagContent.length).trim();
564
564
  const attributes=parseAttributes(attributesString);
565
565
  if (VOID_TAGS.has(tagName.toLowerCase()) || isSelfClosing) new SingleNode(tagName,attributes,stack[stack.length-1])
566
566
  else stack.push(new Node(tagName,attributes,stack[stack.length-1]));
567
567
  }
568
568
  i=tagEnd+1;
569
569
  } else{
570
570
  currentText+=html[i];
571
571
  i++;
572
572
  }
573
573
  }
574
574
  if (currentText.trim() && stack[stack.length-1]) stack[stack.length-1].childNodes.push(new TextNode(currentText));
575
575
  return root;
576
576
  }
577
577
  return { parseHTML, Node, Query, TextNode, SingleNode }
578
578
  })()