1 | /*
|
2 | Copyright (c) 2019-present NAVER Corp.
|
3 | name: @egjs/list-differ
|
4 | license: MIT
|
5 | author: NAVER Corp.
|
6 | repository: https://github.com/naver/egjs-list-differ
|
7 | version: 1.0.0
|
8 | */
|
9 | (function (global, factory) {
|
10 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
11 | typeof define === 'function' && define.amd ? define(factory) :
|
12 | (global = global || self, (global.eg = global.eg || {}, global.eg.ListDiffer = factory()));
|
13 | }(this, function () { 'use strict';
|
14 |
|
15 | /*
|
16 | egjs-list-differ
|
17 | Copyright (c) 2019-present NAVER Corp.
|
18 | MIT license
|
19 | */
|
20 | var PolyMap =
|
21 | /*#__PURE__*/
|
22 | function () {
|
23 | function PolyMap() {
|
24 | this.keys = [];
|
25 | this.values = [];
|
26 | }
|
27 |
|
28 | var __proto = PolyMap.prototype;
|
29 |
|
30 | __proto.get = function (key) {
|
31 | return this.values[this.keys.indexOf(key)];
|
32 | };
|
33 |
|
34 | __proto.set = function (key, value) {
|
35 | var keys = this.keys;
|
36 | var values = this.values;
|
37 | var prevIndex = keys.indexOf(key);
|
38 | var index = prevIndex === -1 ? keys.length : prevIndex;
|
39 | keys[index] = key;
|
40 | values[index] = value;
|
41 | };
|
42 |
|
43 | return PolyMap;
|
44 | }();
|
45 |
|
46 | /*
|
47 | egjs-list-differ
|
48 | Copyright (c) 2019-present NAVER Corp.
|
49 | MIT license
|
50 | */
|
51 | var HashMap =
|
52 | /*#__PURE__*/
|
53 | function () {
|
54 | function HashMap() {
|
55 | this.object = {};
|
56 | }
|
57 |
|
58 | var __proto = HashMap.prototype;
|
59 |
|
60 | __proto.get = function (key) {
|
61 | return this.object[key];
|
62 | };
|
63 |
|
64 | __proto.set = function (key, value) {
|
65 | this.object[key] = value;
|
66 | };
|
67 |
|
68 | return HashMap;
|
69 | }();
|
70 |
|
71 | /*
|
72 | egjs-list-differ
|
73 | Copyright (c) 2019-present NAVER Corp.
|
74 | MIT license
|
75 | */
|
76 | var SUPPORT_MAP = typeof Map === "function";
|
77 |
|
78 | /*
|
79 | egjs-list-differ
|
80 | Copyright (c) 2019-present NAVER Corp.
|
81 | MIT license
|
82 | */
|
83 | var Link =
|
84 | /*#__PURE__*/
|
85 | function () {
|
86 | function Link() {}
|
87 |
|
88 | var __proto = Link.prototype;
|
89 |
|
90 | __proto.connect = function (prevLink, nextLink) {
|
91 | this.prev = prevLink;
|
92 | this.next = nextLink;
|
93 | prevLink && (prevLink.next = this);
|
94 | nextLink && (nextLink.prev = this);
|
95 | };
|
96 |
|
97 | __proto.disconnect = function () {
|
98 | // In double linked list, diconnect the interconnected relationship.
|
99 | var prevLink = this.prev;
|
100 | var nextLink = this.next;
|
101 | prevLink && (prevLink.next = nextLink);
|
102 | nextLink && (nextLink.prev = prevLink);
|
103 | };
|
104 |
|
105 | __proto.getIndex = function () {
|
106 | var link = this;
|
107 | var index = -1;
|
108 |
|
109 | while (link) {
|
110 | link = link.prev;
|
111 | ++index;
|
112 | }
|
113 |
|
114 | return index;
|
115 | };
|
116 |
|
117 | return Link;
|
118 | }();
|
119 |
|
120 | /*
|
121 | egjs-list-differ
|
122 | Copyright (c) 2019-present NAVER Corp.
|
123 | MIT license
|
124 | */
|
125 |
|
126 | function orderChanged(changed, fixed) {
|
127 | // It is roughly in the order of these examples.
|
128 | // 4, 6, 0, 2, 1, 3, 5, 7
|
129 | var fromLinks = []; // 0, 1, 2, 3, 4, 5, 6, 7
|
130 |
|
131 | var toLinks = [];
|
132 | changed.forEach(function (_a) {
|
133 | var from = _a[0],
|
134 | to = _a[1];
|
135 | var link = new Link();
|
136 | fromLinks[from] = link;
|
137 | toLinks[to] = link;
|
138 | }); // `fromLinks` are connected to each other by double linked list.
|
139 |
|
140 | fromLinks.forEach(function (link, i) {
|
141 | link.connect(fromLinks[i - 1]);
|
142 | });
|
143 | return changed.filter(function (_, i) {
|
144 | return !fixed[i];
|
145 | }).map(function (_a, i) {
|
146 | var from = _a[0],
|
147 | to = _a[1];
|
148 |
|
149 | if (from === to) {
|
150 | return [0, 0];
|
151 | }
|
152 |
|
153 | var fromLink = fromLinks[from];
|
154 | var toLink = toLinks[to - 1];
|
155 | var fromIndex = fromLink.getIndex(); // Disconnect the link connected to `fromLink`.
|
156 |
|
157 | fromLink.disconnect(); // Connect `fromLink` to the right of `toLink`.
|
158 |
|
159 | if (!toLink) {
|
160 | fromLink.connect(undefined, fromLinks[0]);
|
161 | } else {
|
162 | fromLink.connect(toLink, toLink.next);
|
163 | }
|
164 |
|
165 | var toIndex = fromLink.getIndex();
|
166 | return [fromIndex, toIndex];
|
167 | });
|
168 | }
|
169 |
|
170 | var Result =
|
171 | /*#__PURE__*/
|
172 | function () {
|
173 | function Result(prevList, list, added, removed, changed, maintained, changedBeforeAdded, fixed) {
|
174 | this.prevList = prevList;
|
175 | this.list = list;
|
176 | this.added = added;
|
177 | this.removed = removed;
|
178 | this.changed = changed;
|
179 | this.maintained = maintained;
|
180 | this.changedBeforeAdded = changedBeforeAdded;
|
181 | this.fixed = fixed;
|
182 | }
|
183 |
|
184 | var __proto = Result.prototype;
|
185 | Object.defineProperty(__proto, "ordered", {
|
186 | get: function () {
|
187 | if (!this.cacheOrdered) {
|
188 | this.caculateOrdered();
|
189 | }
|
190 |
|
191 | return this.cacheOrdered;
|
192 | },
|
193 | enumerable: true,
|
194 | configurable: true
|
195 | });
|
196 | Object.defineProperty(__proto, "pureChanged", {
|
197 | get: function () {
|
198 | if (!this.cachePureChanged) {
|
199 | this.caculateOrdered();
|
200 | }
|
201 |
|
202 | return this.cachePureChanged;
|
203 | },
|
204 | enumerable: true,
|
205 | configurable: true
|
206 | });
|
207 |
|
208 | __proto.caculateOrdered = function () {
|
209 | var ordered = orderChanged(this.changedBeforeAdded, this.fixed);
|
210 | var changed = this.changed;
|
211 | var pureChanged = [];
|
212 | this.cacheOrdered = ordered.filter(function (_a, i) {
|
213 | var from = _a[0],
|
214 | to = _a[1];
|
215 | var _b = changed[i],
|
216 | fromBefore = _b[0],
|
217 | toBefore = _b[1];
|
218 |
|
219 | if (from !== to) {
|
220 | pureChanged.push([fromBefore, toBefore]);
|
221 | return true;
|
222 | }
|
223 | });
|
224 | this.cachePureChanged = pureChanged;
|
225 | };
|
226 |
|
227 | return Result;
|
228 | }();
|
229 |
|
230 | /**
|
231 | *
|
232 | * @memberof eg.ListDiffer
|
233 | * @static
|
234 | * @function
|
235 | * @param - Previous List <ko> 이전 목록 </ko>
|
236 | * @param - List to Update <ko> 업데이트 할 목록 </ko>
|
237 | * @param - This callback function returns the key of the item. <ko> 아이템의 키를 반환하는 콜백 함수입니다.</ko>
|
238 | * @return - Returns the diff between `prevList` and `list` <ko> `prevList`와 `list`의 다른 점을 반환한다.</ko>
|
239 | * @example
|
240 | * import { diff } from "@egjs/list-differ";
|
241 | * // script => eg.ListDiffer.diff
|
242 | * const result = diff([0, 1, 2, 3, 4, 5], [7, 8, 0, 4, 3, 6, 2, 1], e => e);
|
243 | * // List before update
|
244 | * // [1, 2, 3, 4, 5]
|
245 | * console.log(result.prevList);
|
246 | * // Updated list
|
247 | * // [4, 3, 6, 2, 1]
|
248 | * console.log(result.list);
|
249 | * // Index array of values added to `list`
|
250 | * // [0, 1, 5]
|
251 | * console.log(result.added);
|
252 | * // Index array of values removed in `prevList`
|
253 | * // [5]
|
254 | * console.log(result.removed);
|
255 | * // An array of index pairs of `prevList` and `list` with different indexes from `prevList` and `list`
|
256 | * // [[0, 2], [4, 3], [3, 4], [2, 6], [1, 7]]
|
257 | * console.log(result.changed);
|
258 | * // The subset of `changed` and an array of index pairs that moved data directly. Indicate an array of absolute index pairs of `ordered`.(Formatted by: Array<[index of prevList, index of list]>)
|
259 | * // [[4, 3], [3, 4], [2, 6]]
|
260 | * console.log(result.pureChanged);
|
261 | * // An array of index pairs to be `ordered` that can synchronize `list` before adding data. (Formatted by: Array<[prevIndex, nextIndex]>)
|
262 | * // [[4, 1], [4, 2], [4, 3]]
|
263 | * console.log(result.ordered);
|
264 | * // An array of index pairs of `prevList` and `list` that have not been added/removed so data is preserved
|
265 | * // [[0, 2], [4, 3], [3, 4], [2, 6], [1, 7]]
|
266 | * console.log(result.maintained);
|
267 | */
|
268 |
|
269 | function diff(prevList, list, findKeyCallback) {
|
270 | var mapClass = SUPPORT_MAP ? Map : findKeyCallback ? HashMap : PolyMap;
|
271 |
|
272 | var callback = findKeyCallback || function (e) {
|
273 | return e;
|
274 | };
|
275 |
|
276 | var added = [];
|
277 | var removed = [];
|
278 | var maintained = [];
|
279 | var prevKeys = prevList.map(callback);
|
280 | var keys = list.map(callback);
|
281 | var prevKeyMap = new mapClass();
|
282 | var keyMap = new mapClass();
|
283 | var changedBeforeAdded = [];
|
284 | var fixed = [];
|
285 | var removedMap = {};
|
286 | var changed = [];
|
287 | var addedCount = 0;
|
288 | var removedCount = 0; // Add prevKeys and keys to the hashmap.
|
289 |
|
290 | prevKeys.forEach(function (key, prevListIndex) {
|
291 | prevKeyMap.set(key, prevListIndex);
|
292 | });
|
293 | keys.forEach(function (key, listIndex) {
|
294 | keyMap.set(key, listIndex);
|
295 | }); // Compare `prevKeys` and `keys` and add them to `removed` if they are not in `keys`.
|
296 |
|
297 | prevKeys.forEach(function (key, prevListIndex) {
|
298 | var listIndex = keyMap.get(key); // In prevList, but not in list, it is removed.
|
299 |
|
300 | if (typeof listIndex === "undefined") {
|
301 | ++removedCount;
|
302 | removed.push(prevListIndex);
|
303 | } else {
|
304 | removedMap[listIndex] = removedCount;
|
305 | }
|
306 | }); // Compare `prevKeys` and `keys` and add them to `added` if they are not in `prevKeys`.
|
307 |
|
308 | keys.forEach(function (key, listIndex) {
|
309 | var prevListIndex = prevKeyMap.get(key); // In list, but not in prevList, it is added.
|
310 |
|
311 | if (typeof prevListIndex === "undefined") {
|
312 | added.push(listIndex);
|
313 | ++addedCount;
|
314 | } else {
|
315 | maintained.push([prevListIndex, listIndex]);
|
316 | removedCount = removedMap[listIndex] || 0;
|
317 | changedBeforeAdded.push([prevListIndex - removedCount, listIndex - addedCount]);
|
318 | fixed.push(listIndex === prevListIndex);
|
319 |
|
320 | if (prevListIndex !== listIndex) {
|
321 | changed.push([prevListIndex, listIndex]);
|
322 | }
|
323 | }
|
324 | }); // Sort by ascending order of 'to(list's index).
|
325 |
|
326 | removed.reverse();
|
327 | return new Result(prevList, list, added, removed, changed, maintained, changedBeforeAdded, fixed);
|
328 | }
|
329 |
|
330 | /**
|
331 | * A module that checks diff when values are added, removed, or changed in an array.
|
332 | * @ko 배열 또는 오브젝트에서 값이 추가되거나 삭제되거나 순서가 변경사항을 체크하는 모듈입니다.
|
333 | * @memberof eg
|
334 | */
|
335 |
|
336 | var ListDiffer =
|
337 | /*#__PURE__*/
|
338 | function () {
|
339 | /**
|
340 | * @param - Initializing Data Array. <ko> 초기 설정할 데이터 배열.</ko>
|
341 | * @param - This callback function returns the key of the item. <ko> 아이템의 키를 반환하는 콜백 함수입니다.</ko>
|
342 | * @example
|
343 | * import ListDiffer from "@egjs/list-differ";
|
344 | * // script => eg.ListDiffer
|
345 | * const differ = new ListDiffer([0, 1, 2, 3, 4, 5], e => e);
|
346 | * const result = differ.update([7, 8, 0, 4, 3, 6, 2, 1]);
|
347 | * // List before update
|
348 | * // [1, 2, 3, 4, 5]
|
349 | * console.log(result.prevList);
|
350 | * // Updated list
|
351 | * // [4, 3, 6, 2, 1]
|
352 | * console.log(result.list);
|
353 | * // Index array of values added to `list`.
|
354 | * // [0, 1, 5]
|
355 | * console.log(result.added);
|
356 | * // Index array of values removed in `prevList`.
|
357 | * // [5]
|
358 | * console.log(result.removed);
|
359 | * // An array of index pairs of `prevList` and `list` with different indexes from `prevList` and `list`.
|
360 | * // [[0, 2], [4, 3], [3, 4], [2, 6], [1, 7]]
|
361 | * console.log(result.changed);
|
362 | * // The subset of `changed` and an array of index pairs that moved data directly. Indicate an array of absolute index pairs of `ordered`.(Formatted by: Array<[index of prevList, index of list]>)
|
363 | * // [[4, 3], [3, 4], [2, 6]]
|
364 | * console.log(result.pureChanged);
|
365 | * // An array of index pairs to be `ordered` that can synchronize `list` before adding data. (Formatted by: Array<[prevIndex, nextIndex]>)
|
366 | * // [[4, 1], [4, 2], [4, 3]]
|
367 | * console.log(result.ordered);
|
368 | * // An array of index pairs of `prevList` and `list` that have not been added/removed so data is preserved.
|
369 | * // [[0, 2], [4, 3], [3, 4], [2, 6], [1, 7]]
|
370 | * console.log(result.maintained);
|
371 | */
|
372 | function ListDiffer(list, findKeyCallback) {
|
373 | if (list === void 0) {
|
374 | list = [];
|
375 | }
|
376 |
|
377 | this.findKeyCallback = findKeyCallback;
|
378 | this.list = [].slice.call(list);
|
379 | }
|
380 | /**
|
381 | * Update list.
|
382 | * @ko 리스트를 업데이트를 합니다.
|
383 | * @param - List to update <ko> 업데이트할 리스트 </ko>
|
384 | * @return - Returns the results of an update from `prevList` to `list`.<ko> `prevList`에서 `list`로 업데이트한 결과를 반환한다. </ko>
|
385 | */
|
386 |
|
387 |
|
388 | var __proto = ListDiffer.prototype;
|
389 |
|
390 | __proto.update = function (list) {
|
391 | var newData = [].slice.call(list);
|
392 | var result = diff(this.list, newData, this.findKeyCallback);
|
393 | this.list = newData;
|
394 | return result;
|
395 | };
|
396 |
|
397 | return ListDiffer;
|
398 | }();
|
399 |
|
400 | /*
|
401 | egjs-list-differ
|
402 | Copyright (c) 2019-present NAVER Corp.
|
403 | MIT license
|
404 | */
|
405 |
|
406 | /*
|
407 | egjs-list-differ
|
408 | Copyright (c) 2019-present NAVER Corp.
|
409 | MIT license
|
410 | */
|
411 | ListDiffer.diff = diff;
|
412 |
|
413 | return ListDiffer;
|
414 |
|
415 | }));
|
416 | //# sourceMappingURL=list-differ.js.map
|