1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 | var PolyMap =
|
15 |
|
16 | function () {
|
17 | function PolyMap() {
|
18 | this.keys = [];
|
19 | this.values = [];
|
20 | }
|
21 |
|
22 | var __proto = PolyMap.prototype;
|
23 |
|
24 | __proto.get = function (key) {
|
25 | return this.values[this.keys.indexOf(key)];
|
26 | };
|
27 |
|
28 | __proto.set = function (key, value) {
|
29 | var keys = this.keys;
|
30 | var values = this.values;
|
31 | var prevIndex = keys.indexOf(key);
|
32 | var index = prevIndex === -1 ? keys.length : prevIndex;
|
33 | keys[index] = key;
|
34 | values[index] = value;
|
35 | };
|
36 |
|
37 | return PolyMap;
|
38 | }();
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 | var HashMap =
|
46 |
|
47 | function () {
|
48 | function HashMap() {
|
49 | this.object = {};
|
50 | }
|
51 |
|
52 | var __proto = HashMap.prototype;
|
53 |
|
54 | __proto.get = function (key) {
|
55 | return this.object[key];
|
56 | };
|
57 |
|
58 | __proto.set = function (key, value) {
|
59 | this.object[key] = value;
|
60 | };
|
61 |
|
62 | return HashMap;
|
63 | }();
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 | var SUPPORT_MAP = typeof Map === "function";
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 | var Link =
|
78 |
|
79 | function () {
|
80 | function Link() {}
|
81 |
|
82 | var __proto = Link.prototype;
|
83 |
|
84 | __proto.connect = function (prevLink, nextLink) {
|
85 | this.prev = prevLink;
|
86 | this.next = nextLink;
|
87 | prevLink && (prevLink.next = this);
|
88 | nextLink && (nextLink.prev = this);
|
89 | };
|
90 |
|
91 | __proto.disconnect = function () {
|
92 |
|
93 | var prevLink = this.prev;
|
94 | var nextLink = this.next;
|
95 | prevLink && (prevLink.next = nextLink);
|
96 | nextLink && (nextLink.prev = prevLink);
|
97 | };
|
98 |
|
99 | __proto.getIndex = function () {
|
100 | var link = this;
|
101 | var index = -1;
|
102 |
|
103 | while (link) {
|
104 | link = link.prev;
|
105 | ++index;
|
106 | }
|
107 |
|
108 | return index;
|
109 | };
|
110 |
|
111 | return Link;
|
112 | }();
|
113 |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 | function orderChanged(changed, fixed) {
|
121 |
|
122 |
|
123 | var fromLinks = [];
|
124 |
|
125 | var toLinks = [];
|
126 | changed.forEach(function (_a) {
|
127 | var from = _a[0],
|
128 | to = _a[1];
|
129 | var link = new Link();
|
130 | fromLinks[from] = link;
|
131 | toLinks[to] = link;
|
132 | });
|
133 |
|
134 | fromLinks.forEach(function (link, i) {
|
135 | link.connect(fromLinks[i - 1]);
|
136 | });
|
137 | return changed.filter(function (_, i) {
|
138 | return !fixed[i];
|
139 | }).map(function (_a, i) {
|
140 | var from = _a[0],
|
141 | to = _a[1];
|
142 |
|
143 | if (from === to) {
|
144 | return [0, 0];
|
145 | }
|
146 |
|
147 | var fromLink = fromLinks[from];
|
148 | var toLink = toLinks[to - 1];
|
149 | var fromIndex = fromLink.getIndex();
|
150 |
|
151 | fromLink.disconnect();
|
152 |
|
153 | if (!toLink) {
|
154 | fromLink.connect(undefined, fromLinks[0]);
|
155 | } else {
|
156 | fromLink.connect(toLink, toLink.next);
|
157 | }
|
158 |
|
159 | var toIndex = fromLink.getIndex();
|
160 | return [fromIndex, toIndex];
|
161 | });
|
162 | }
|
163 |
|
164 | var Result =
|
165 |
|
166 | function () {
|
167 | function Result(prevList, list, added, removed, changed, maintained, changedBeforeAdded, fixed) {
|
168 | this.prevList = prevList;
|
169 | this.list = list;
|
170 | this.added = added;
|
171 | this.removed = removed;
|
172 | this.changed = changed;
|
173 | this.maintained = maintained;
|
174 | this.changedBeforeAdded = changedBeforeAdded;
|
175 | this.fixed = fixed;
|
176 | }
|
177 |
|
178 | var __proto = Result.prototype;
|
179 | Object.defineProperty(__proto, "ordered", {
|
180 | get: function () {
|
181 | if (!this.cacheOrdered) {
|
182 | this.caculateOrdered();
|
183 | }
|
184 |
|
185 | return this.cacheOrdered;
|
186 | },
|
187 | enumerable: true,
|
188 | configurable: true
|
189 | });
|
190 | Object.defineProperty(__proto, "pureChanged", {
|
191 | get: function () {
|
192 | if (!this.cachePureChanged) {
|
193 | this.caculateOrdered();
|
194 | }
|
195 |
|
196 | return this.cachePureChanged;
|
197 | },
|
198 | enumerable: true,
|
199 | configurable: true
|
200 | });
|
201 |
|
202 | __proto.caculateOrdered = function () {
|
203 | var ordered = orderChanged(this.changedBeforeAdded, this.fixed);
|
204 | var changed = this.changed;
|
205 | var pureChanged = [];
|
206 | this.cacheOrdered = ordered.filter(function (_a, i) {
|
207 | var from = _a[0],
|
208 | to = _a[1];
|
209 | var _b = changed[i],
|
210 | fromBefore = _b[0],
|
211 | toBefore = _b[1];
|
212 |
|
213 | if (from !== to) {
|
214 | pureChanged.push([fromBefore, toBefore]);
|
215 | return true;
|
216 | }
|
217 | });
|
218 | this.cachePureChanged = pureChanged;
|
219 | };
|
220 |
|
221 | return Result;
|
222 | }();
|
223 |
|
224 |
|
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 |
|
231 |
|
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 |
|
248 |
|
249 |
|
250 |
|
251 |
|
252 |
|
253 |
|
254 |
|
255 |
|
256 |
|
257 |
|
258 |
|
259 |
|
260 |
|
261 |
|
262 |
|
263 | function diff(prevList, list, findKeyCallback) {
|
264 | var mapClass = SUPPORT_MAP ? Map : findKeyCallback ? HashMap : PolyMap;
|
265 |
|
266 | var callback = findKeyCallback || function (e) {
|
267 | return e;
|
268 | };
|
269 |
|
270 | var added = [];
|
271 | var removed = [];
|
272 | var maintained = [];
|
273 | var prevKeys = prevList.map(callback);
|
274 | var keys = list.map(callback);
|
275 | var prevKeyMap = new mapClass();
|
276 | var keyMap = new mapClass();
|
277 | var changedBeforeAdded = [];
|
278 | var fixed = [];
|
279 | var removedMap = {};
|
280 | var changed = [];
|
281 | var addedCount = 0;
|
282 | var removedCount = 0;
|
283 |
|
284 | prevKeys.forEach(function (key, prevListIndex) {
|
285 | prevKeyMap.set(key, prevListIndex);
|
286 | });
|
287 | keys.forEach(function (key, listIndex) {
|
288 | keyMap.set(key, listIndex);
|
289 | });
|
290 |
|
291 | prevKeys.forEach(function (key, prevListIndex) {
|
292 | var listIndex = keyMap.get(key);
|
293 |
|
294 | if (typeof listIndex === "undefined") {
|
295 | ++removedCount;
|
296 | removed.push(prevListIndex);
|
297 | } else {
|
298 | removedMap[listIndex] = removedCount;
|
299 | }
|
300 | });
|
301 |
|
302 | keys.forEach(function (key, listIndex) {
|
303 | var prevListIndex = prevKeyMap.get(key);
|
304 |
|
305 | if (typeof prevListIndex === "undefined") {
|
306 | added.push(listIndex);
|
307 | ++addedCount;
|
308 | } else {
|
309 | maintained.push([prevListIndex, listIndex]);
|
310 | removedCount = removedMap[listIndex] || 0;
|
311 | changedBeforeAdded.push([prevListIndex - removedCount, listIndex - addedCount]);
|
312 | fixed.push(listIndex === prevListIndex);
|
313 |
|
314 | if (prevListIndex !== listIndex) {
|
315 | changed.push([prevListIndex, listIndex]);
|
316 | }
|
317 | }
|
318 | });
|
319 |
|
320 | removed.reverse();
|
321 | return new Result(prevList, list, added, removed, changed, maintained, changedBeforeAdded, fixed);
|
322 | }
|
323 |
|
324 |
|
325 |
|
326 |
|
327 |
|
328 |
|
329 |
|
330 | var ListDiffer =
|
331 |
|
332 | function () {
|
333 | |
334 |
|
335 |
|
336 |
|
337 |
|
338 |
|
339 |
|
340 |
|
341 |
|
342 |
|
343 |
|
344 |
|
345 |
|
346 |
|
347 |
|
348 |
|
349 |
|
350 |
|
351 |
|
352 |
|
353 |
|
354 |
|
355 |
|
356 |
|
357 |
|
358 |
|
359 |
|
360 |
|
361 |
|
362 |
|
363 |
|
364 |
|
365 |
|
366 | function ListDiffer(list, findKeyCallback) {
|
367 | if (list === void 0) {
|
368 | list = [];
|
369 | }
|
370 |
|
371 | this.findKeyCallback = findKeyCallback;
|
372 | this.list = [].slice.call(list);
|
373 | }
|
374 | |
375 |
|
376 |
|
377 |
|
378 |
|
379 |
|
380 |
|
381 |
|
382 | var __proto = ListDiffer.prototype;
|
383 |
|
384 | __proto.update = function (list) {
|
385 | var newData = [].slice.call(list);
|
386 | var result = diff(this.list, newData, this.findKeyCallback);
|
387 | this.list = newData;
|
388 | return result;
|
389 | };
|
390 |
|
391 | return ListDiffer;
|
392 | }();
|
393 |
|
394 |
|
395 |
|
396 |
|
397 |
|
398 |
|
399 |
|
400 | export default ListDiffer;
|
401 | export { diff };
|
402 |
|