forked from Matt-Esch/virtual-dom
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdiff.js
132 lines (106 loc) · 3.09 KB
/
diff.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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
var createPatch = require("./lib/patch-op")
var indexTree = require("./lib/vtree-index")
var isArray = require("./lib/is-array")
var isVDOMNode = require("./lib/is-virtual-dom")
var isVTextNode = require("./lib/is-virtual-text")
var isWidget = require("./lib/is-widget")
module.exports = diff
function diff(a, b) {
var patch = { a: a }
// index a so we can implicitly reference
indexTree(a)
walk(a, b, patch)
return patch
}
function walk(a, b, patch) {
if (a === b) {
return b
}
var apply = patch[a.index]
if (isWidget(a)) {
apply = appendPatch(apply, createPatch(a, b))
b = a // replaces the widget in b with the stateful a widget
} else if (isWidget(b)) {
apply = appendPatch(apply, createPatch(a, b))
} else if (isVTextNode(a) && isVTextNode(b)) {
if (a.text !== b.text) {
apply = appendPatch(apply, createPatch(a.text, b.text))
}
} else if (isVDOMNode(a) && isVDOMNode(b) && a.tagName === b.tagName) {
var propsPatch = diffProps(a.properties, b.properties)
if (propsPatch) {
apply = appendPatch(apply, createPatch(a.properties, b.properties))
}
apply = diffChildren(a, b, patch, apply)
} else if (a !== b) {
apply = appendPatch(apply, createPatch(a, b))
}
if (apply) {
patch[a.index] = apply
}
return b
}
var nullProps = {}
function diffProps(a, b) {
var diff
for (var aKey in a) {
if (aKey === "style") {
var styleDiff = diffProps(a.style, b.style || nullProps)
if (styleDiff) {
diff = diff || {}
diff.style = styleDiff
}
} else {
var aValue = a[aKey]
var bValue = b[aKey]
if (typeof aValue === "function" || aValue !== bValue) {
diff = diff || {}
diff[aKey] = bValue
}
}
}
for (var bKey in b) {
if (!(bKey in a)) {
diff = diff || {}
diff[bKey] = b[bKey]
}
}
return diff
}
function diffChildren(a, b, patch, apply) {
var aChildren = a.children
var bChildren = b.children
var aLen = aChildren.length
var bLen = bChildren.length
var len = aLen < bLen ? aLen : bLen
for (var i = 0; i < len; i++) {
var rightNode = bChildren[i]
var newRight = walk(aChildren[i], rightNode, patch)
if (rightNode !== newRight) {
bChildren[i] = newRight
}
}
// Excess nodes in a need to be removed
for (; i < aLen; i++) {
var excess = aChildren[i]
patch[excess.index] = createPatch(excess, null)
}
// Excess nodes in b need to be added
for (; i < bLen; i++) {
var addition = bChildren[i]
apply = appendPatch(apply, createPatch(null, addition))
}
return apply
}
function appendPatch(apply, patch) {
if (apply) {
if (isArray(apply)) {
apply.push(patch)
} else {
apply = [apply, patch]
}
return apply
} else {
return patch
}
}