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
|
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 updateViewFilter(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 updateViewFilter(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
}
export function updateViewSort(list, sortFn = defaultSortFn) {
let sorted = [...list]
if (sortFn) {
sorted.sort(makeCompareFn(sortFn))
}
sorted.indexOf = x => sortedIndexOf(sorted, x, sortFn)
return sorted
}
|