forked from mystiq/hydrogen-web
concat operator for observable lists
This commit is contained in:
parent
6f650d19b1
commit
7a6e91de84
3 changed files with 136 additions and 5 deletions
|
@ -6,6 +6,7 @@ import BaseObservableMap from "./map/BaseObservableMap.js";
|
|||
export { default as ObservableArray } from "./list/ObservableArray.js";
|
||||
export { default as SortedArray } from "./list/SortedArray.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";
|
||||
|
||||
// avoid circular dependency between these classes
|
||||
|
|
|
@ -3,26 +3,26 @@ import BaseObservableCollection from "../BaseObservableCollection.js";
|
|||
export default class BaseObservableList extends BaseObservableCollection {
|
||||
emitReset() {
|
||||
for(let h of this._handlers) {
|
||||
h.onReset();
|
||||
h.onReset(this);
|
||||
}
|
||||
}
|
||||
// we need batch events, mostly on index based collection though?
|
||||
// maybe we should get started without?
|
||||
emitAdd(index, value) {
|
||||
for(let h of this._handlers) {
|
||||
h.onAdd(index, value);
|
||||
h.onAdd(index, value, this);
|
||||
}
|
||||
}
|
||||
|
||||
emitUpdate(index, value, params) {
|
||||
for(let h of this._handlers) {
|
||||
h.onUpdate(index, value, params);
|
||||
h.onUpdate(index, value, params, this);
|
||||
}
|
||||
}
|
||||
|
||||
emitRemove(index, value) {
|
||||
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
|
||||
emitMove(fromIdx, toIdx, value) {
|
||||
for(let h of this._handlers) {
|
||||
h.onMove(fromIdx, toIdx, value);
|
||||
h.onMove(fromIdx, toIdx, value, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
130
src/observable/list/ConcatList.js
Normal file
130
src/observable/list/ConcatList.js
Normal 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);
|
||||
},
|
||||
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue