concat operator for observable lists

This commit is contained in:
Bruno Windels 2019-07-29 19:18:11 +02:00
parent 6f650d19b1
commit 7a6e91de84
3 changed files with 136 additions and 5 deletions

View file

@ -6,6 +6,7 @@ import BaseObservableMap from "./map/BaseObservableMap.js";
export { default as ObservableArray } from "./list/ObservableArray.js"; export { default as ObservableArray } from "./list/ObservableArray.js";
export { default as SortedArray } from "./list/SortedArray.js"; export { default as SortedArray } from "./list/SortedArray.js";
export { default as MappedList } from "./list/MappedList.js"; export { default as MappedList } from "./list/MappedList.js";
export { default as ConcatList } from "./list/ConcatList.js";
export { default as ObservableMap } from "./map/ObservableMap.js"; export { default as ObservableMap } from "./map/ObservableMap.js";
// avoid circular dependency between these classes // avoid circular dependency between these classes

View file

@ -3,26 +3,26 @@ import BaseObservableCollection from "../BaseObservableCollection.js";
export default class BaseObservableList extends BaseObservableCollection { export default class BaseObservableList extends BaseObservableCollection {
emitReset() { emitReset() {
for(let h of this._handlers) { for(let h of this._handlers) {
h.onReset(); h.onReset(this);
} }
} }
// we need batch events, mostly on index based collection though? // we need batch events, mostly on index based collection though?
// maybe we should get started without? // maybe we should get started without?
emitAdd(index, value) { emitAdd(index, value) {
for(let h of this._handlers) { for(let h of this._handlers) {
h.onAdd(index, value); h.onAdd(index, value, this);
} }
} }
emitUpdate(index, value, params) { emitUpdate(index, value, params) {
for(let h of this._handlers) { for(let h of this._handlers) {
h.onUpdate(index, value, params); h.onUpdate(index, value, params, this);
} }
} }
emitRemove(index, value) { emitRemove(index, value) {
for(let h of this._handlers) { for(let h of this._handlers) {
h.onRemove(index, value); h.onRemove(index, value, this);
} }
} }
@ -30,7 +30,7 @@ export default class BaseObservableList extends BaseObservableCollection {
// been removed from its fromIdx // been removed from its fromIdx
emitMove(fromIdx, toIdx, value) { emitMove(fromIdx, toIdx, value) {
for(let h of this._handlers) { for(let h of this._handlers) {
h.onMove(fromIdx, toIdx, value); h.onMove(fromIdx, toIdx, value, this);
} }
} }

View file

@ -0,0 +1,130 @@
import BaseObservableList from "./BaseObservableList.js";
export default class ConcatList extends BaseObservableList {
constructor(...sourceLists) {
super();
this._sourceLists = sourceLists;
this._sourceUnsubscribes = null;
}
_offsetForSource(sourceList) {
const listIdx = this._sourceLists.indexOf(sourceList);
let offset = 0;
for (let i = 0; i < listIdx; ++i) {
offset += this._sourceLists[i].length;
}
return offset;
}
onSubscribeFirst() {
this._sourceUnsubscribes = [];
for (const sourceList of this._sourceLists) {
this._sourceUnsubscribes.push(sourceList.subscribe(this));
}
}
onUnsubscribeLast() {
for (const sourceUnsubscribe of this._sourceUnsubscribes) {
sourceUnsubscribe();
}
}
onReset() {
// TODO: not ideal if other source lists are large
// but working impl for now
// reset, and
this.emitReset();
let idx = 0;
for(const item of this) {
this.emitAdd(idx, item);
idx += 1;
}
}
onAdd(index, value, sourceList) {
this.emitAdd(this._offsetForSource(sourceList) + index, value);
}
onUpdate(index, value, params, sourceList) {
this.emitAdd(this._offsetForSource(sourceList) + index, value, params);
}
onRemove(index, value, sourceList) {
this.emitRemove(this._offsetForSource(sourceList) + index, value);
}
onMove(fromIdx, toIdx, value, sourceList) {
const offset = this._offsetForSource(sourceList);
this.emitMove(offset + fromIdx, offset + toIdx, value);
}
get length() {
let len = 0;
for (let i = 0; i < this._sourceLists.length; ++i) {
len += this._sourceLists[i].length;
}
return len;
}
[Symbol.iterator]() {
let sourceListIdx = 0;
let it = this._sourceLists[0][Symbol.iterator]();
return {
next: () => {
let result = it.next();
while (result.done) {
sourceListIdx += 1;
if (sourceListIdx >= this._sourceLists.length) {
return result; //done
}
it = this._sourceLists[sourceListIdx][Symbol.iterator]();
result = it.next();
}
return result;
}
}
}
}
import ObservableArray from "./ObservableArray.js";
export async function tests() {
return {
test_length(assert) {
const all = new ConcatList(
new ObservableArray([1, 2, 3]),
new ObservableArray([11, 12, 13])
);
assert.equal(all.length, 6);
},
test_iterator(assert) {
const all = new ConcatList(
new ObservableArray([1, 2, 3]),
new ObservableArray([11, 12, 13])
);
const it = all[Symbol.iterator]();
assert.equal(it.next().value, 1);
assert.equal(it.next().value, 2);
assert.equal(it.next().value, 3);
assert.equal(it.next().value, 11);
assert.equal(it.next().value, 12);
assert.equal(it.next().value, 13);
assert(it.next().done);
},
test_add(assert) {
const list1 = new ObservableArray([1, 2, 3]);
const list2 = new ObservableArray([11, 12, 13]);
const all = new ConcatList(list1, list2);
let fired = false;
all.subscribe({
onAdd(index, value) {
fired = true;
assert.equal(index, 4);
assert.equal(value, 11.5);
}
});
list2.insert(1, 11.5);
assert(fired);
},
};
}