-
Notifications
You must be signed in to change notification settings - Fork 10
/
diff.cljs
178 lines (171 loc) · 7.93 KB
/
diff.cljs
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
(ns respo.render.diff
(:require [clojure.string :as string]
[respo.util.format :refer [purify-element]]
[respo.util.detect :refer [component?]]
[clojure.set :refer [difference]]
[respo.schema.op :as op]))
(declare find-children-diffs)
(declare find-element-diffs)
(defn find-props-diffs [collect! coord old-props new-props svg?]
(comment
.log
js/console
"find props:"
coord
old-props
new-props
(count old-props)
(count new-props))
(let [was-empty? (empty? old-props), now-empty? (empty? new-props)]
(cond
(and was-empty? now-empty?) nil
(and was-empty? (not now-empty?))
(do
(collect! [op/add-prop coord (first new-props) svg?])
(recur collect! coord old-props (rest new-props) svg?))
(and (not was-empty?) now-empty?)
(do
(collect! [op/rm-prop coord (key (first old-props)) svg?])
(recur collect! coord (rest old-props) new-props svg?))
:else
(let [old-entry (first old-props)
new-entry (first new-props)
[old-k old-v] (first old-props)
[new-k new-v] (first new-props)
old-follows (rest old-props)
new-follows (rest new-props)]
(comment .log js/console old-k new-k old-v new-v)
(case (compare old-k new-k)
-1
(do
(collect! [op/rm-prop coord old-k svg?])
(recur collect! coord old-follows new-props svg?))
1
(do
(collect! [op/add-prop coord new-entry svg?])
(recur collect! coord old-props new-follows svg?))
(do
(if (not= old-v new-v) (collect! [op/replace-prop coord new-entry svg?]))
(recur collect! coord old-follows new-follows svg?)))))))
(defn find-style-diffs [collect! coord old-style new-style svg?]
(let [was-empty? (empty? old-style), now-empty? (empty? new-style)]
(if (identical? old-style new-style)
nil
(cond
(and was-empty? now-empty?) nil
(and was-empty? (not now-empty?))
(let [entry (first new-style), follows (rest new-style)]
(collect! [op/add-style coord entry svg?])
(recur collect! coord old-style follows svg?))
(and (not was-empty?) now-empty?)
(let [entry (first old-style), follows (rest old-style)]
(collect! [op/rm-style coord (key entry) svg?])
(recur collect! coord follows new-style svg?))
:else
(let [old-entry (first old-style)
new-entry (first new-style)
old-follows (rest old-style)
new-follows (rest new-style)]
(case (compare (key old-entry) (key new-entry))
-1
(do
(collect! [op/rm-style coord (key old-entry) svg?])
(recur collect! coord old-follows new-style svg?))
1
(do
(collect! [op/add-style coord new-entry svg?])
(recur collect! coord old-style new-follows svg?))
(do
(if (not (identical? (val old-entry) (val new-entry)))
(collect! [op/replace-style coord new-entry svg?]))
(recur collect! coord old-follows new-follows svg?))))))))
(defn find-element-diffs [collect! n-coord old-tree new-tree]
(comment .log js/console "element diffing:" n-coord old-tree new-tree)
(if (identical? old-tree new-tree)
nil
(cond
(component? old-tree) (recur collect! n-coord (get old-tree :tree) new-tree)
(component? new-tree) (recur collect! n-coord old-tree (get new-tree :tree))
:else
(let [old-children (:children old-tree)
new-children (:children new-tree)
svg? (:svg? old-tree)]
(if (or (not= (:coord old-tree) (:coord new-tree))
(not= (:name old-tree) (:name new-tree))
(not= (:c-name old-tree) (:c-name new-tree)))
(do (collect! [op/replace-element n-coord (purify-element new-tree) svg?]) nil)
(do
(find-props-diffs collect! n-coord (:attrs old-tree) (:attrs new-tree) svg?)
(let [old-style (:style old-tree), new-style (:style new-tree)]
(if (not (identical? old-style new-style))
(find-style-diffs collect! n-coord old-style new-style svg?)))
(let [old-events (into #{} (keys (:event old-tree)))
new-events (into #{} (keys (:event new-tree)))
added-events (difference new-events old-events)
removed-events (difference old-events new-events)]
(doseq [event-name added-events]
(collect! [op/set-event n-coord [event-name (:coord new-tree)] svg?]))
(doseq [event-name removed-events]
(collect! [op/rm-event n-coord event-name svg?])))
(find-children-diffs collect! n-coord 0 old-children new-children)))))))
(defn find-children-diffs [collect! n-coord index old-children new-children]
(comment .log js/console "diff children:" n-coord index old-children new-children)
(let [was-empty? (empty? old-children), now-empty? (empty? new-children)]
(cond
(and was-empty? now-empty?) nil
(and was-empty? (not now-empty?))
(let [element (last (first new-children))]
(collect! [op/append-element n-coord (purify-element element) (:svg? element)])
(recur collect! n-coord (inc index) [] (rest new-children)))
(and (not was-empty?) now-empty?)
(do
(collect! [op/rm-element (conj n-coord index) nil false])
(recur collect! n-coord index (rest old-children) []))
:else
(let [old-keys (map first (take 16 old-children))
new-keys (map first (take 16 new-children))
x1 (first old-keys)
y1 (first new-keys)
match-x1 (fn [x] (= x x1))
match-y1 (fn [x] (= x y1))
x1-remains? (some match-x1 new-keys)
y1-existed? (some match-y1 old-keys)
old-follows (rest old-children)
new-follows (rest new-children)]
(comment println "compare:" x1 new-keys x1-remains? y1 y1-existed? old-keys)
(cond
(= x1 y1)
(let [old-element (last (first old-children))
new-element (last (first new-children))]
(find-element-diffs collect! (conj n-coord index) old-element new-element)
(recur collect! n-coord (inc index) old-follows new-follows))
(and x1-remains? (not y1-existed?))
(do
(collect!
(let [element (last (first new-children))]
[op/add-element
(conj n-coord index)
(purify-element element)
(:svg? element)]))
(recur collect! n-coord (inc index) old-children new-follows))
(and (not x1-remains?) y1-existed?)
(do
(collect! [op/rm-element (conj n-coord index) nil false])
(recur collect! n-coord index old-follows new-children))
:else
(let [xi (.indexOf new-keys x1)
yi (.indexOf old-keys y1)
first-old-entry (first old-children)
first-new-entry (first new-children)]
(comment println "index:" xi yi)
(if (<= xi yi)
(let [new-element (last (first new-children))]
(collect!
[op/add-element
(conj n-coord index)
(purify-element new-element)
(:svg? new-element)])
(recur collect! n-coord (inc index) old-children new-follows))
(do
(collect! [op/rm-element (conj n-coord index) nil false])
(recur collect! n-coord index old-follows new-children)))))))))