tangled
alpha
login
or
join now
yippee.fun
/
morphlex
0
fork
atom
Precise DOM morphing
morphing
typescript
dom
0
fork
atom
overview
issues
pulls
pipelines
Use an array for matches
joel.drapper.me
4 months ago
44905d1c
48092d3b
+41
-31
1 changed file
expand all
collapse all
unified
split
src
morphlex.ts
+41
-31
src/morphlex.ts
···
286
286
const candidateNodes: Set<ChildNode> = new Set()
287
287
const candidateElements: Set<Element> = new Set()
288
288
289
289
-
const unmatchedNodes: Set<ChildNode> = new Set()
290
290
-
const unmatchedElements: Set<Element> = new Set()
291
291
-
292
292
-
const matches: Map<ChildNode, ChildNode> = new Map()
289
289
+
const matches: Array<ChildNode | null> = new Array(toChildNodes.length).fill(null)
293
290
294
291
for (const candidate of fromChildNodes) {
295
292
if (isElement(candidate)) candidateElements.add(candidate)
296
293
else candidateNodes.add(candidate)
297
294
}
298
295
299
299
-
for (const node of toChildNodes) {
300
300
-
if (isElement(node)) unmatchedElements.add(node)
301
301
-
else unmatchedNodes.add(node)
302
302
-
}
296
296
+
// Match elements by isEqualNode
297
297
+
for (let i = 0; i < toChildNodes.length; i++) {
298
298
+
const element = toChildNodes[i]!
299
299
+
if (!isElement(element)) continue
303
300
304
304
-
// Match elements by isEqualNode
305
305
-
for (const element of unmatchedElements) {
306
301
for (const candidate of candidateElements) {
307
302
if (candidate.isEqualNode(element)) {
308
308
-
matches.set(element, candidate)
309
309
-
unmatchedElements.delete(element)
303
303
+
matches[i] = candidate
310
304
candidateElements.delete(candidate)
311
305
break
312
306
}
···
314
308
}
315
309
316
310
// Match by exact id
317
317
-
for (const element of unmatchedElements) {
311
311
+
for (let i = 0; i < toChildNodes.length; i++) {
312
312
+
if (matches[i]) continue
313
313
+
const element = toChildNodes[i]!
314
314
+
if (!isElement(element)) continue
315
315
+
318
316
const id = element.id
319
317
if (id === "") continue
320
318
321
319
for (const candidate of candidateElements) {
322
320
if (element.localName === candidate.localName && id === candidate.id) {
323
323
-
matches.set(element, candidate)
324
324
-
unmatchedElements.delete(element)
321
321
+
matches[i] = candidate
325
322
candidateElements.delete(candidate)
326
323
break
327
324
}
···
329
326
}
330
327
331
328
// Match by idSet
332
332
-
for (const element of unmatchedElements) {
329
329
+
for (let i = 0; i < toChildNodes.length; i++) {
330
330
+
if (matches[i]) continue
331
331
+
const element = toChildNodes[i]!
333
332
if (!isElement(element)) continue
333
333
+
334
334
const idSet = this.idMap.get(element)
335
335
if (!idSet) continue
336
336
···
340
340
if (candidateIdSet) {
341
341
for (const id of idSet) {
342
342
if (candidateIdSet.has(id)) {
343
343
-
matches.set(element, candidate)
344
344
-
unmatchedElements.delete(element)
343
343
+
matches[i] = candidate
345
344
candidateElements.delete(candidate)
346
345
break candidateLoop
347
346
}
···
352
351
}
353
352
354
353
// Match by huristics
355
355
-
for (const element of unmatchedElements) {
354
354
+
for (let i = 0; i < toChildNodes.length; i++) {
355
355
+
if (matches[i]) continue
356
356
+
const element = toChildNodes[i]!
356
357
if (!isElement(element)) continue
358
358
+
357
359
const name = element.getAttribute("name")
358
360
const href = element.getAttribute("href")
359
361
const src = element.getAttribute("src")
···
366
368
(href !== "" && href === candidate.getAttribute("href")) ||
367
369
(src !== "" && src === candidate.getAttribute("src")))
368
370
) {
369
369
-
matches.set(element, candidate)
370
370
-
unmatchedElements.delete(element)
371
371
+
matches[i] = candidate
371
372
candidateElements.delete(candidate)
372
373
break
373
374
}
···
375
376
}
376
377
377
378
// Match by tagName
378
378
-
for (const element of unmatchedElements) {
379
379
+
for (let i = 0; i < toChildNodes.length; i++) {
380
380
+
if (matches[i]) continue
381
381
+
const element = toChildNodes[i]!
382
382
+
if (!isElement(element)) continue
383
383
+
379
384
const localName = element.localName
380
385
381
386
for (const candidate of candidateElements) {
···
384
389
// Treat inputs with different type as though they are different tags.
385
390
continue
386
391
}
387
387
-
matches.set(element, candidate)
388
388
-
unmatchedElements.delete(element)
392
392
+
matches[i] = candidate
389
393
candidateElements.delete(candidate)
390
394
break
391
395
}
···
393
397
}
394
398
395
399
// Match nodes by isEqualNode
396
396
-
for (const node of unmatchedNodes) {
400
400
+
for (let i = 0; i < toChildNodes.length; i++) {
401
401
+
if (matches[i]) continue
402
402
+
const node = toChildNodes[i]!
403
403
+
if (isElement(node)) continue
404
404
+
397
405
for (const candidate of candidateNodes) {
398
406
if (candidate.isEqualNode(node)) {
399
399
-
matches.set(node, candidate)
400
400
-
unmatchedNodes.delete(node)
407
407
+
matches[i] = candidate
401
408
candidateNodes.delete(candidate)
402
409
break
403
410
}
···
405
412
}
406
413
407
414
// Match by nodeType
408
408
-
for (const node of unmatchedNodes) {
415
415
+
for (let i = 0; i < toChildNodes.length; i++) {
416
416
+
if (matches[i]) continue
417
417
+
const node = toChildNodes[i]!
418
418
+
if (isElement(node)) continue
419
419
+
409
420
const nodeType = node.nodeType
410
421
411
422
for (const candidate of candidateNodes) {
412
423
if (nodeType === candidate.nodeType) {
413
413
-
matches.set(node, candidate)
414
414
-
unmatchedNodes.delete(node)
424
424
+
matches[i] = candidate
415
425
candidateNodes.delete(candidate)
416
426
break
417
427
}
···
422
432
let insertionPoint: ChildNode | null = parent.firstChild
423
433
for (let i = 0; i < toChildNodes.length; i++) {
424
434
const node = toChildNodes[i]!
425
425
-
const match = matches.get(node)
435
435
+
const match = matches[i]
426
436
if (match) {
427
437
moveBefore(parent, match, insertionPoint)
428
438
this.morphOneToOne(match, node)