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
|
import {ADD, UPDATE, REMOVE, REQUEST_LIST, RECEIVE_LIST} from "./list"
const defaultFilterFn = x => true
const defaultSortFn = false
const makeCompareFn = sortFn => {
let compareFn = (a, b) => {
let akey = sortFn(a),
bkey = sortFn(b)
if (akey < bkey) {
return -1
} else if (akey > bkey) {
return 1
} else {
return 0
}
}
// need to adjust sortedIndexOf as well
// if (sortFn.reverse)
// return (a, b) => compareFn(b, a)
return compareFn
}
const sortedInsert = (list, sortFn, item) => {
let l = [...list, item]
l.indexOf = x => sortedIndexOf(l, x, sortFn)
let compareFn = makeCompareFn(sortFn)
// only sort if sorting order is not correct yet
if (sortFn && compareFn(list[list.length - 1], item) > 0) {
// TODO: This is untested
console.debug("sorting view...")
l.sort(compareFn)
}
return l
}
const sortedRemove = (list, sortFn, item) => {
let itemId = item.id
let l = list.filter(x => x.id !== itemId)
l.indexOf = x => sortedIndexOf(l, x, sortFn)
return l
}
export function sortedIndexOf(list, value, sortFn) {
if (!sortFn) {
sortFn = x => 0 // This triggers the linear search for flows that have the same sort value.
}
let low = 0,
high = list.length,
val = sortFn(value),
mid;
while (low < high) {
mid = (low + high) >>> 1;
if (sortFn(list[mid]) < val) {
low = mid + 1
} else {
high = mid
}
}
// Two flows may have the same sort value.
// we previously determined the leftmost flow with the same sort value,
// so no we need to scan linearly
while (list[low].id !== value.id && sortFn(list[low + 1]) === val) {
low++
}
return low;
}
// for when the list changes
export function updateViewList(currentView, currentList, nextList, action, filterFn = defaultFilterFn, sortFn = defaultSortFn) {
switch (action.cmd) {
case REQUEST_LIST:
return currentView
case RECEIVE_LIST:
return updateViewFilterSort(nextList, filterFn, sortFn)
case ADD:
if (filterFn(action.item)) {
return sortedInsert(currentView, sortFn, action.item)
}
return currentView
case UPDATE:
// let's determine if it's in the view currently and if it should be in the view.
let currentItemState = currentList.byId[action.item.id],
nextItemState = action.item,
isInView = filterFn(currentItemState),
shouldBeInView = filterFn(nextItemState)
if (!isInView && shouldBeInView)
return sortedInsert(currentView, sortFn, action.item)
if (isInView && !shouldBeInView)
return sortedRemove(currentView, sortFn, action.item)
if (isInView && shouldBeInView) {
let s = [...currentView]
s.indexOf = x => sortedIndexOf(s, x, sortFn)
s[s.indexOf(currentItemState)] = nextItemState
if (sortFn && sortFn(currentItemState) !== sortFn(nextItemState))
s.sort(makeCompareFn(sortFn))
return s
}
return currentView
case REMOVE:
let isInView_ = filterFn(currentList.byId[action.item.id])
if (isInView_) {
return sortedRemove(currentView, sortFn, action.item)
}
return currentView
default:
console.error("Unknown list action: ", action)
return currentView
}
}
export function updateViewFilterSort(list, filterFn = defaultFilterFn, sortFn = defaultSortFn) {
let filtered = list.list.filter(filterFn)
if (sortFn){
filtered.sort(makeCompareFn(sortFn))
}
filtered.indexOf = x => sortedIndexOf(filtered, x, sortFn)
return filtered
}
|