-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrepeat.js
55 lines (53 loc) · 1.74 KB
/
repeat.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
const { autorun } = require("kobs")
module.exports = (getValue, createCmp) => parentNode => {
const domNodes = new Map()
const cmps = new Map()
const prevIds = []
const cancelObservation = autorun(() => {
const ids = getValue() || []
// TODO: est-il possible de faire ça meiux pour limiter les opérations sur le DOM ? reprendre l'implémentation de react/preact/inferno ?
for (let i = prevIds.length - 1; i >= 0; i--) {
const id = prevIds[i]
const newIndex = ids.indexOf(id)
// remove ids no more in use
if (newIndex < 0) {
const unmount = cmps.get(id)
unmount()
cmps.delete(id)
const domNode = domNodes.get(id)
parentNode.removeChild(domNode)
domNodes.delete(id)
prevIds.splice(i, 1)
}
}
// move current ids and add new ones
ids.forEach((id, i) => {
if (prevIds[i] === id) return // nothing to do
const prevIndex = prevIds.indexOf(id)
if (prevIndex >= 0) {
//move
const domeNode = domNodes.get(id)
const refId = prevIds[i]
const refNode = domNodes.get(refId)
parentNode.insertBefore(domeNode, refNode)
prevIds.splice(prevIndex, 1)
prevIds.splice(i, 0, id)
} else {
// add
const domNode = document.createElement("div")
const refId = prevIds[i]
const refNode = domNodes.get(refId)
parentNode.insertBefore(domNode, refNode)
const cmp = createCmp(id)
cmps.set(id, cmp(domNode))
domNodes.set(id, domNode)
prevIds.splice(i, 0, id)
}
})
}, "repeat")
return () => {
cancelObservation()
cmps.forEach(unmount => unmount())
domNodes.forEach(domNode => parentNode.removeChild(domNode))
}
}