diff --git a/src/domain/session/room/timeline/ReactionsViewModel.js b/src/domain/session/room/timeline/ReactionsViewModel.js index 3a47aaa0..ad29c01a 100644 --- a/src/domain/session/room/timeline/ReactionsViewModel.js +++ b/src/domain/session/room/timeline/ReactionsViewModel.js @@ -188,7 +188,7 @@ import {NullLogItem, NullLogger} from "../../../../logging/NullLogger"; import {HomeServer as MockHomeServer} from "../../../../mocks/HomeServer.js"; // other imports import {BaseMessageTile} from "./tiles/BaseMessageTile.js"; -import {MappedList} from "../../../../observable/list/MappedList.js"; +import {MappedList} from "../../../../observable/list/MappedList"; import {ObservableValue} from "../../../../observable/ObservableValue"; import {PowerLevels} from "../../../../matrix/room/PowerLevels.js"; diff --git a/src/domain/session/room/timeline/TilesCollection.js b/src/domain/session/room/timeline/TilesCollection.js index 8dce4125..54ab5ddd 100644 --- a/src/domain/session/room/timeline/TilesCollection.js +++ b/src/domain/session/room/timeline/TilesCollection.js @@ -253,7 +253,7 @@ export class TilesCollection extends BaseObservableList { } } -import {ObservableArray} from "../../../../observable/list/ObservableArray.js"; +import {ObservableArray} from "../../../../observable/list/ObservableArray"; import {UpdateAction} from "./UpdateAction.js"; export function tests() { diff --git a/src/matrix/room/sending/SendQueue.js b/src/matrix/room/sending/SendQueue.js index 896100c7..791ed854 100644 --- a/src/matrix/room/sending/SendQueue.js +++ b/src/matrix/room/sending/SendQueue.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {SortedArray} from "../../../observable/list/SortedArray.js"; +import {SortedArray} from "../../../observable/list/SortedArray"; import {ConnectionError} from "../../error.js"; import {PendingEvent, SendStatus} from "./PendingEvent.js"; import {makeTxnId, isTxnId} from "../../common.js"; diff --git a/src/observable/index.js b/src/observable/index.js index 47b68e91..4d7f18a3 100644 --- a/src/observable/index.js +++ b/src/observable/index.js @@ -20,11 +20,11 @@ import {MappedMap} from "./map/MappedMap.js"; import {JoinedMap} from "./map/JoinedMap.js"; import {BaseObservableMap} from "./map/BaseObservableMap.js"; // re-export "root" (of chain) collections -export { ObservableArray } from "./list/ObservableArray.js"; -export { SortedArray } from "./list/SortedArray.js"; -export { MappedList } from "./list/MappedList.js"; -export { AsyncMappedList } from "./list/AsyncMappedList.js"; -export { ConcatList } from "./list/ConcatList.js"; +export { ObservableArray } from "./list/ObservableArray"; +export { SortedArray } from "./list/SortedArray"; +export { MappedList } from "./list/MappedList"; +export { AsyncMappedList } from "./list/AsyncMappedList"; +export { ConcatList } from "./list/ConcatList"; export { ObservableMap } from "./map/ObservableMap.js"; // avoid circular dependency between these classes diff --git a/src/observable/list/AsyncMappedList.js b/src/observable/list/AsyncMappedList.ts similarity index 70% rename from src/observable/list/AsyncMappedList.js rename to src/observable/list/AsyncMappedList.ts index 9af1f95a..0a919cdc 100644 --- a/src/observable/list/AsyncMappedList.js +++ b/src/observable/list/AsyncMappedList.ts @@ -15,15 +15,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {BaseMappedList, runAdd, runUpdate, runRemove, runMove, runReset} from "./BaseMappedList"; +import {IListObserver} from "./BaseObservableList"; +import {BaseMappedList, Mapper, Updater, runAdd, runUpdate, runRemove, runMove, runReset} from "./BaseMappedList"; -export class AsyncMappedList extends BaseMappedList { - constructor(sourceList, mapper, updater, removeCallback) { - super(sourceList, mapper, updater, removeCallback); - this._eventQueue = null; - } +export class AsyncMappedList extends BaseMappedList> implements IListObserver { + private _eventQueue: AsyncEvent[] | null = null; + private _flushing: boolean = false; - onSubscribeFirst() { + onSubscribeFirst(): void { this._sourceUnsubscribe = this._sourceList.subscribe(this); this._eventQueue = []; this._mappedValues = []; @@ -35,122 +34,112 @@ export class AsyncMappedList extends BaseMappedList { this._flush(); } - async _flush() { + async _flush(): Promise { if (this._flushing) { return; } this._flushing = true; try { - while (this._eventQueue.length) { - const event = this._eventQueue.shift(); - await event.run(this); + while (this._eventQueue!.length) { + const event = this._eventQueue!.shift(); + await event!.run(this); } } finally { this._flushing = false; } } - onReset() { + onReset(): void { if (this._eventQueue) { this._eventQueue.push(new ResetEvent()); this._flush(); } } - onAdd(index, value) { + onAdd(index: number, value: F): void { if (this._eventQueue) { this._eventQueue.push(new AddEvent(index, value)); this._flush(); } } - onUpdate(index, value, params) { + onUpdate(index: number, value: F, params: any): void { if (this._eventQueue) { this._eventQueue.push(new UpdateEvent(index, value, params)); this._flush(); } } - onRemove(index) { + onRemove(index: number): void { if (this._eventQueue) { this._eventQueue.push(new RemoveEvent(index)); this._flush(); } } - onMove(fromIdx, toIdx) { + onMove(fromIdx: number, toIdx: number): void { if (this._eventQueue) { this._eventQueue.push(new MoveEvent(fromIdx, toIdx)); this._flush(); } } - onUnsubscribeLast() { - this._sourceUnsubscribe(); + onUnsubscribeLast(): void { + this._sourceUnsubscribe!(); this._eventQueue = null; this._mappedValues = null; } } -class AddEvent { - constructor(index, value) { - this.index = index; - this.value = value; - } +type AsyncEvent = AddEvent | UpdateEvent | RemoveEvent | MoveEvent | ResetEvent - async run(list) { +class AddEvent { + constructor(public index: number, public value: F) {} + + async run(list: AsyncMappedList): Promise { const mappedValue = await list._mapper(this.value); runAdd(list, this.index, mappedValue); } } -class UpdateEvent { - constructor(index, value, params) { - this.index = index; - this.value = value; - this.params = params; - } +class UpdateEvent { + constructor(public index: number, public value: F, public params: any) {} - async run(list) { + async run(list: AsyncMappedList): Promise { runUpdate(list, this.index, this.value, this.params); } } -class RemoveEvent { - constructor(index) { - this.index = index; - } +class RemoveEvent { + constructor(public index: number) {} - async run(list) { + async run(list: AsyncMappedList): Promise { runRemove(list, this.index); } } -class MoveEvent { - constructor(fromIdx, toIdx) { - this.fromIdx = fromIdx; - this.toIdx = toIdx; - } +class MoveEvent { + constructor(public fromIdx: number, public toIdx: number) {} - async run(list) { + async run(list: AsyncMappedList): Promise { runMove(list, this.fromIdx, this.toIdx); } } -class ResetEvent { - async run(list) { +class ResetEvent { + async run(list: AsyncMappedList): Promise { runReset(list); } } -import {ObservableArray} from "./ObservableArray.js"; +import {ObservableArray} from "./ObservableArray"; import {ListObserver} from "../../mocks/ListObserver.js"; export function tests() { return { "events are emitted in order": async assert => { const double = n => n * n; - const source = new ObservableArray(); + const source = new ObservableArray(); const mapper = new AsyncMappedList(source, async n => { await new Promise(r => setTimeout(r, n)); return {n: double(n)}; diff --git a/src/observable/list/BaseMappedList.ts b/src/observable/list/BaseMappedList.ts index f2203d34..4e3d05e0 100644 --- a/src/observable/list/BaseMappedList.ts +++ b/src/observable/list/BaseMappedList.ts @@ -21,15 +21,15 @@ import {findAndUpdateInArray} from "./common"; export type Mapper = (value: F) => T export type Updater = (mappedValue: T, params: any, value: F) => void; -export class BaseMappedList extends BaseObservableList { +export class BaseMappedList extends BaseObservableList { protected _sourceList: BaseObservableList; protected _sourceUnsubscribe: (() => void) | null = null; - _mapper: Mapper; - _updater: Updater; + _mapper: Mapper; + _updater?: Updater; _removeCallback?: (value: T) => void; _mappedValues: T[] | null = null; - constructor(sourceList: BaseObservableList, mapper: Mapper, updater: Updater, removeCallback?: (value: T) => void) { + constructor(sourceList: BaseObservableList, mapper: Mapper, updater?: Updater, removeCallback?: (value: T) => void) { super(); this._sourceList = sourceList; this._mapper = mapper; @@ -50,12 +50,12 @@ export class BaseMappedList extends BaseObservableList { } } -export function runAdd(list: BaseMappedList, index: number, mappedValue: T): void { +export function runAdd(list: BaseMappedList, index: number, mappedValue: T): void { list._mappedValues!.splice(index, 0, mappedValue); list.emitAdd(index, mappedValue); } -export function runUpdate(list: BaseMappedList, index: number, value: F, params: any): void { +export function runUpdate(list: BaseMappedList, index: number, value: F, params: any): void { const mappedValue = list._mappedValues![index]; if (list._updater) { list._updater(mappedValue, params, value); @@ -63,7 +63,7 @@ export function runUpdate(list: BaseMappedList, index: number, value: list.emitUpdate(index, mappedValue, params); } -export function runRemove(list: BaseMappedList, index: number): void { +export function runRemove(list: BaseMappedList, index: number): void { const mappedValue = list._mappedValues![index]; list._mappedValues!.splice(index, 1); if (list._removeCallback) { @@ -72,14 +72,14 @@ export function runRemove(list: BaseMappedList, index: number): void { list.emitRemove(index, mappedValue); } -export function runMove(list: BaseMappedList, fromIdx: number, toIdx: number): void { +export function runMove(list: BaseMappedList, fromIdx: number, toIdx: number): void { const mappedValue = list._mappedValues![fromIdx]; list._mappedValues!.splice(fromIdx, 1); list._mappedValues!.splice(toIdx, 0, mappedValue); list.emitMove(fromIdx, toIdx, mappedValue); } -export function runReset(list: BaseMappedList): void { +export function runReset(list: BaseMappedList): void { list._mappedValues = []; list.emitReset(); } diff --git a/src/observable/list/BaseObservableList.ts b/src/observable/list/BaseObservableList.ts index 9ba6559a..d103eb64 100644 --- a/src/observable/list/BaseObservableList.ts +++ b/src/observable/list/BaseObservableList.ts @@ -24,7 +24,18 @@ export interface IListObserver { onMove(from: number, to: number, value: T, list: BaseObservableList): void } -export abstract class BaseObservableList extends BaseObservable> { +export function defaultObserverWith(overrides: { [key in keyof IListObserver]?: IListObserver[key] }): IListObserver { + const defaults = { + onReset(){}, + onAdd(){}, + onUpdate(){}, + onRemove(){}, + onMove(){}, + } + return Object.assign(defaults, overrides); +} + +export abstract class BaseObservableList extends BaseObservable> implements Iterable { emitReset() { for(let h of this._handlers) { h.onReset(this); @@ -38,7 +49,7 @@ export abstract class BaseObservableList extends BaseObservable extends BaseObservable; + abstract [Symbol.iterator](): Iterator; abstract get length(): number; } diff --git a/src/observable/list/ConcatList.js b/src/observable/list/ConcatList.ts similarity index 80% rename from src/observable/list/ConcatList.js rename to src/observable/list/ConcatList.ts index e87ccb60..5822468a 100644 --- a/src/observable/list/ConcatList.js +++ b/src/observable/list/ConcatList.ts @@ -14,16 +14,18 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {BaseObservableList} from "./BaseObservableList"; +import {BaseObservableList, IListObserver} from "./BaseObservableList"; -export class ConcatList extends BaseObservableList { - constructor(...sourceLists) { +export class ConcatList extends BaseObservableList implements IListObserver { + protected _sourceLists: BaseObservableList[]; + protected _sourceUnsubscribes: (() => void)[] | null = null; + + constructor(...sourceLists: BaseObservableList[]) { super(); this._sourceLists = sourceLists; - this._sourceUnsubscribes = null; } - _offsetForSource(sourceList) { + _offsetForSource(sourceList: BaseObservableList): number { const listIdx = this._sourceLists.indexOf(sourceList); let offset = 0; for (let i = 0; i < listIdx; ++i) { @@ -32,17 +34,17 @@ export class ConcatList extends BaseObservableList { return offset; } - onSubscribeFirst() { + onSubscribeFirst(): void { this._sourceUnsubscribes = this._sourceLists.map(sourceList => sourceList.subscribe(this)); } - onUnsubscribeLast() { - for (const sourceUnsubscribe of this._sourceUnsubscribes) { + onUnsubscribeLast(): void { + for (const sourceUnsubscribe of this._sourceUnsubscribes!) { sourceUnsubscribe(); } } - onReset() { + onReset(): void { // TODO: not ideal if other source lists are large // but working impl for now // reset, and @@ -54,11 +56,11 @@ export class ConcatList extends BaseObservableList { } } - onAdd(index, value, sourceList) { + onAdd(index: number, value: T, sourceList: BaseObservableList): void { this.emitAdd(this._offsetForSource(sourceList) + index, value); } - onUpdate(index, value, params, sourceList) { + onUpdate(index: number, value: T, params: any, sourceList: BaseObservableList): void { // if an update is emitted while calling source.subscribe() from onSubscribeFirst, ignore it // as we are not supposed to call `length` on any uninitialized list if (!this._sourceUnsubscribes) { @@ -67,16 +69,16 @@ export class ConcatList extends BaseObservableList { this.emitUpdate(this._offsetForSource(sourceList) + index, value, params); } - onRemove(index, value, sourceList) { + onRemove(index: number, value: T, sourceList: BaseObservableList): void { this.emitRemove(this._offsetForSource(sourceList) + index, value); } - onMove(fromIdx, toIdx, value, sourceList) { + onMove(fromIdx: number, toIdx: number, value: T, sourceList: BaseObservableList): void { const offset = this._offsetForSource(sourceList); this.emitMove(offset + fromIdx, offset + toIdx, value); } - get length() { + get length(): number { let len = 0; for (let i = 0; i < this._sourceLists.length; ++i) { len += this._sourceLists[i].length; @@ -104,7 +106,8 @@ export class ConcatList extends BaseObservableList { } } -import {ObservableArray} from "./ObservableArray.js"; +import {ObservableArray} from "./ObservableArray"; +import {defaultObserverWith} from "./BaseObservableList"; export async function tests() { return { test_length(assert) { @@ -133,13 +136,13 @@ export async function tests() { const list2 = new ObservableArray([11, 12, 13]); const all = new ConcatList(list1, list2); let fired = false; - all.subscribe({ + all.subscribe(defaultObserverWith({ onAdd(index, value) { fired = true; assert.equal(index, 4); assert.equal(value, 11.5); } - }); + })); list2.insert(1, 11.5); assert(fired); }, @@ -148,13 +151,13 @@ export async function tests() { const list2 = new ObservableArray([11, 12, 13]); const all = new ConcatList(list1, list2); let fired = false; - all.subscribe({ + all.subscribe(defaultObserverWith({ onUpdate(index, value) { fired = true; assert.equal(index, 4); assert.equal(value, 10); } - }); + })); list2.emitUpdate(1, 10); assert(fired); }, diff --git a/src/observable/list/MappedList.js b/src/observable/list/MappedList.ts similarity index 80% rename from src/observable/list/MappedList.js rename to src/observable/list/MappedList.ts index c799fcff..ebb418d3 100644 --- a/src/observable/list/MappedList.js +++ b/src/observable/list/MappedList.ts @@ -15,9 +15,10 @@ See the License for the specific language governing permissions and limitations under the License. */ +import {IListObserver} from "./BaseObservableList"; import {BaseMappedList, runAdd, runUpdate, runRemove, runMove, runReset} from "./BaseMappedList"; -export class MappedList extends BaseMappedList { +export class MappedList extends BaseMappedList implements IListObserver { onSubscribeFirst() { this._sourceUnsubscribe = this._sourceList.subscribe(this); this._mappedValues = []; @@ -26,16 +27,16 @@ export class MappedList extends BaseMappedList { } } - onReset() { + onReset(): void { runReset(this); } - onAdd(index, value) { + onAdd(index: number, value: F): void { const mappedValue = this._mapper(value); runAdd(this, index, mappedValue); } - onUpdate(index, value, params) { + onUpdate(index: number, value: F, params: any): void { // if an update is emitted while calling source.subscribe() from onSubscribeFirst, ignore it if (!this._mappedValues) { return; @@ -43,24 +44,25 @@ export class MappedList extends BaseMappedList { runUpdate(this, index, value, params); } - onRemove(index) { + onRemove(index: number): void { runRemove(this, index); } - onMove(fromIdx, toIdx) { + onMove(fromIdx: number, toIdx: number): void { runMove(this, fromIdx, toIdx); } - onUnsubscribeLast() { - this._sourceUnsubscribe(); + onUnsubscribeLast(): void { + this._sourceUnsubscribe!(); } } -import {ObservableArray} from "./ObservableArray.js"; +import {ObservableArray} from "./ObservableArray"; import {BaseObservableList} from "./BaseObservableList"; +import {defaultObserverWith} from "./BaseObservableList"; export async function tests() { - class MockList extends BaseObservableList { + class MockList extends BaseObservableList { get length() { return 0; } @@ -74,26 +76,26 @@ export async function tests() { const source = new MockList(); const mapped = new MappedList(source, n => {return {n: n*n};}); let fired = false; - const unsubscribe = mapped.subscribe({ + const unsubscribe = mapped.subscribe(defaultObserverWith({ onAdd(idx, value) { fired = true; assert.equal(idx, 0); assert.equal(value.n, 36); } - }); + })); source.emitAdd(0, 6); assert(fired); unsubscribe(); }, test_update(assert) { const source = new MockList(); - const mapped = new MappedList( + const mapped = new MappedList( source, n => {return {n: n*n};}, (o, p, n) => o.m = n*n ); let fired = false; - const unsubscribe = mapped.subscribe({ + const unsubscribe = mapped.subscribe(defaultObserverWith({ onAdd() {}, onUpdate(idx, value) { fired = true; @@ -101,7 +103,7 @@ export async function tests() { assert.equal(value.n, 36); assert.equal(value.m, 49); } - }); + })); source.emitAdd(0, 6); source.emitUpdate(0, 7); assert(fired); @@ -113,9 +115,9 @@ export async function tests() { source, n => {return n*n;} ); - mapped.subscribe({ + mapped.subscribe(defaultObserverWith({ onUpdate() { assert.fail(); } - }); + })); assert.equal(mapped.findAndUpdate( n => n === 100, () => assert.fail() @@ -127,9 +129,9 @@ export async function tests() { source, n => {return n*n;} ); - mapped.subscribe({ + mapped.subscribe(defaultObserverWith({ onUpdate() { assert.fail(); } - }); + })); let fired = false; assert.equal(mapped.findAndUpdate( n => n === 9, @@ -148,14 +150,14 @@ export async function tests() { n => {return n*n;} ); let fired = false; - mapped.subscribe({ + mapped.subscribe(defaultObserverWith({ onUpdate(idx, n, params) { assert.equal(idx, 1); assert.equal(n, 9); assert.equal(params, "param"); fired = true; } - }); + })); assert.equal(mapped.findAndUpdate(n => n === 9, () => "param"), true); assert.equal(fired, true); }, diff --git a/src/observable/list/ObservableArray.js b/src/observable/list/ObservableArray.ts similarity index 78% rename from src/observable/list/ObservableArray.js rename to src/observable/list/ObservableArray.ts index afdaba37..0771d0f6 100644 --- a/src/observable/list/ObservableArray.js +++ b/src/observable/list/ObservableArray.ts @@ -16,35 +16,37 @@ limitations under the License. import {BaseObservableList} from "./BaseObservableList"; -export class ObservableArray extends BaseObservableList { - constructor(initialValues = []) { +export class ObservableArray extends BaseObservableList { + private _items: T[]; + + constructor(initialValues: T[] = []) { super(); this._items = initialValues; } - append(item) { + append(item: T): void { this._items.push(item); this.emitAdd(this._items.length - 1, item); } - remove(idx) { + remove(idx: number): void { const [item] = this._items.splice(idx, 1); this.emitRemove(idx, item); } - insertMany(idx, items) { + insertMany(idx: number, items: T[]): void { for(let item of items) { this.insert(idx, item); idx += 1; } } - insert(idx, item) { + insert(idx: number, item: T): void { this._items.splice(idx, 0, item); this.emitAdd(idx, item); } - move(fromIdx, toIdx) { + move(fromIdx: number, toIdx: number): void { if (fromIdx < this._items.length && toIdx < this._items.length) { const [item] = this._items.splice(fromIdx, 1); this._items.splice(toIdx, 0, item); @@ -52,24 +54,24 @@ export class ObservableArray extends BaseObservableList { } } - update(idx, item, params = null) { + update(idx: number, item: T, params: any = null): void { if (idx < this._items.length) { this._items[idx] = item; this.emitUpdate(idx, item, params); } } - get array() { + get array(): Readonly { return this._items; } - at(idx) { + at(idx: number): T | undefined { if (this._items && idx >= 0 && idx < this._items.length) { return this._items[idx]; } } - get length() { + get length(): number { return this._items.length; } diff --git a/src/observable/list/SortedArray.js b/src/observable/list/SortedArray.ts similarity index 81% rename from src/observable/list/SortedArray.js rename to src/observable/list/SortedArray.ts index 1201845c..c85cca27 100644 --- a/src/observable/list/SortedArray.js +++ b/src/observable/list/SortedArray.ts @@ -18,18 +18,20 @@ import {BaseObservableList} from "./BaseObservableList"; import {sortedIndex} from "../../utils/sortedIndex"; import {findAndUpdateInArray} from "./common"; -export class SortedArray extends BaseObservableList { - constructor(comparator) { +export class SortedArray extends BaseObservableList { + private _comparator: (left: T, right: T) => number; + private _items: T[] = []; + + constructor(comparator: (left: T, right: T) => number) { super(); this._comparator = comparator; - this._items = []; } - setManyUnsorted(items) { + setManyUnsorted(items: T[]): void { this.setManySorted(items); } - setManySorted(items) { + setManySorted(items: T[]): void { // TODO: we can make this way faster by only looking up the first and last key, // and merging whatever is inbetween with items // if items is not sorted, 💩🌀 will follow! @@ -42,11 +44,11 @@ export class SortedArray extends BaseObservableList { } } - findAndUpdate(predicate, updater) { + findAndUpdate(predicate: (value: T) => boolean, updater: (value: T) => any | false): boolean { return findAndUpdateInArray(predicate, this._items, this, updater); } - getAndUpdate(item, updater, updateParams = null) { + getAndUpdate(item: T, updater: (existing: T, item: T) => any, updateParams: any = null): void { const idx = this.indexOf(item); if (idx !== -1) { const existingItem = this._items[idx]; @@ -56,7 +58,7 @@ export class SortedArray extends BaseObservableList { } } - update(item, updateParams = null) { + update(item: T, updateParams: any = null): void { const idx = this.indexOf(item); if (idx !== -1) { this._items[idx] = item; @@ -64,7 +66,7 @@ export class SortedArray extends BaseObservableList { } } - indexOf(item) { + indexOf(item: T): number { const idx = sortedIndex(this._items, item, this._comparator); if (idx < this._items.length && this._comparator(this._items[idx], item) === 0) { return idx; @@ -73,7 +75,7 @@ export class SortedArray extends BaseObservableList { } } - _getNext(item) { + _getNext(item: T): T | undefined { let idx = sortedIndex(this._items, item, this._comparator); while(idx < this._items.length && this._comparator(this._items[idx], item) <= 0) { idx += 1; @@ -81,7 +83,7 @@ export class SortedArray extends BaseObservableList { return this.get(idx); } - set(item, updateParams = null) { + set(item: T, updateParams: any = null): void { const idx = sortedIndex(this._items, item, this._comparator); if (idx >= this._items.length || this._comparator(this._items[idx], item) !== 0) { this._items.splice(idx, 0, item); @@ -92,21 +94,21 @@ export class SortedArray extends BaseObservableList { } } - get(idx) { + get(idx: number): T | undefined { return this._items[idx]; } - remove(idx) { + remove(idx: number): void { const item = this._items[idx]; this._items.splice(idx, 1); this.emitRemove(idx, item); } - get array() { + get array(): T[] { return this._items; } - get length() { + get length(): number { return this._items.length; } @@ -116,8 +118,11 @@ export class SortedArray extends BaseObservableList { } // iterator that works even if the current value is removed while iterating -class Iterator { - constructor(sortedArray) { +class Iterator { + private _sortedArray: SortedArray | null + private _current: T | null | undefined + + constructor(sortedArray: SortedArray) { this._sortedArray = sortedArray; this._current = null; } @@ -145,7 +150,7 @@ class Iterator { export function tests() { return { "setManyUnsorted": assert => { - const sa = new SortedArray((a, b) => a.localeCompare(b)); + const sa = new SortedArray((a, b) => a.localeCompare(b)); sa.setManyUnsorted(["b", "a", "c"]); assert.equal(sa.length, 3); assert.equal(sa.get(0), "a"); @@ -153,7 +158,7 @@ export function tests() { assert.equal(sa.get(2), "c"); }, "_getNext": assert => { - const sa = new SortedArray((a, b) => a.localeCompare(b)); + const sa = new SortedArray((a, b) => a.localeCompare(b)); sa.setManyUnsorted(["b", "a", "f"]); assert.equal(sa._getNext("a"), "b"); assert.equal(sa._getNext("b"), "f"); @@ -162,7 +167,7 @@ export function tests() { assert.equal(sa._getNext("f"), undefined); }, "iterator with removals": assert => { - const queue = new SortedArray((a, b) => a.idx - b.idx); + const queue = new SortedArray<{idx: number}>((a, b) => a.idx - b.idx); queue.setManyUnsorted([{idx: 5}, {idx: 3}, {idx: 1}, {idx: 4}, {idx: 2}]); const it = queue[Symbol.iterator](); assert.equal(it.next().value.idx, 1); diff --git a/src/platform/web/ui/general/ListRange.ts b/src/platform/web/ui/general/ListRange.ts index 4f62ba21..66ee8dfb 100644 --- a/src/platform/web/ui/general/ListRange.ts +++ b/src/platform/web/ui/general/ListRange.ts @@ -15,6 +15,7 @@ limitations under the License. */ import {Range, RangeZone} from "./Range"; +import {defaultObserverWith} from "../../../../observable/list/BaseObservableList"; function skipOnIterator(it: Iterator, pos: number): boolean { let i = 0; @@ -268,7 +269,7 @@ export function tests() { const list = new ObservableArray(["b", "c", "d", "e"]); const range = new ListRange(1, 3, list.length); let added = false; - list.subscribe({ + list.subscribe(defaultObserverWith({ onAdd(idx, value) { added = true; const result = range.queryAdd(idx, value, list); @@ -280,7 +281,7 @@ export function tests() { newRange: new ListRange(1, 3, 5) }); } - }); + })); list.insert(0, "a"); assert(added); }, @@ -288,7 +289,7 @@ export function tests() { const list = new ObservableArray(["a", "b", "d", "e"]); const range = new ListRange(1, 3, list.length); let added = false; - list.subscribe({ + list.subscribe(defaultObserverWith({ onAdd(idx, value) { added = true; const result = range.queryAdd(idx, value, list); @@ -300,7 +301,7 @@ export function tests() { newRange: new ListRange(1, 3, 5) }); } - }); + })); list.insert(2, "c"); assert(added); }, @@ -308,7 +309,7 @@ export function tests() { const list = new ObservableArray(["a", "b", "c", "d"]); const range = new ListRange(1, 3, list.length); let added = false; - list.subscribe({ + list.subscribe(defaultObserverWith({ onAdd(idx, value) { added = true; const result = range.queryAdd(idx, value, list); @@ -317,7 +318,7 @@ export function tests() { newRange: new ListRange(1, 3, 5) }); } - }); + })); list.insert(4, "e"); assert(added); }, @@ -326,7 +327,7 @@ export function tests() { const viewportItemCount = 4; const range = new ListRange(0, 3, list.length, viewportItemCount); let added = false; - list.subscribe({ + list.subscribe(defaultObserverWith({ onAdd(idx, value) { added = true; const result = range.queryAdd(idx, value, list); @@ -337,7 +338,7 @@ export function tests() { value: "c" }); } - }); + })); list.insert(2, "c"); assert(added); }, @@ -345,7 +346,7 @@ export function tests() { const list = new ObservableArray(["a", "b", "c", "d", "e"]); const range = new ListRange(1, 3, list.length); let removed = false; - list.subscribe({ + list.subscribe(defaultObserverWith({ onRemove(idx) { removed = true; const result = range.queryRemove(idx, list); @@ -357,7 +358,7 @@ export function tests() { newRange: new ListRange(1, 3, 4) }); } - }); + })); list.remove(0); assert(removed); }, @@ -365,7 +366,7 @@ export function tests() { const list = new ObservableArray(["a", "b", "c", "d", "e"]); const range = new ListRange(1, 3, list.length); let removed = false; - list.subscribe({ + list.subscribe(defaultObserverWith({ onRemove(idx) { removed = true; const result = range.queryRemove(idx, list); @@ -378,7 +379,7 @@ export function tests() { }); assert.equal(list.length, 4); } - }); + })); list.remove(2); assert(removed); }, @@ -386,7 +387,7 @@ export function tests() { const list = new ObservableArray(["a", "b", "c", "d", "e"]); const range = new ListRange(1, 3, list.length); let removed = false; - list.subscribe({ + list.subscribe(defaultObserverWith({ onRemove(idx) { removed = true; const result = range.queryRemove(idx, list); @@ -395,7 +396,7 @@ export function tests() { newRange: new ListRange(1, 3, 4) }); } - }); + })); list.remove(3); assert(removed); }, @@ -403,7 +404,7 @@ export function tests() { const list = new ObservableArray(["a", "b", "c"]); const range = new ListRange(1, 3, list.length); let removed = false; - list.subscribe({ + list.subscribe(defaultObserverWith({ onRemove(idx) { removed = true; const result = range.queryRemove(idx, list); @@ -415,7 +416,7 @@ export function tests() { value: "a" }); } - }); + })); list.remove(2); assert(removed); }, @@ -423,7 +424,7 @@ export function tests() { const list = new ObservableArray(["a", "b", "c"]); const range = new ListRange(0, 3, list.length); let removed = false; - list.subscribe({ + list.subscribe(defaultObserverWith({ onRemove(idx) { removed = true; const result = range.queryRemove(idx, list); @@ -433,7 +434,7 @@ export function tests() { removeIdx: 2, }); } - }); + })); list.remove(2); assert(removed); }, @@ -441,7 +442,7 @@ export function tests() { const list = new ObservableArray(["a", "b", "c", "d", "e"]); const range = new ListRange(1, 4, list.length); let moved = false; - list.subscribe({ + list.subscribe(defaultObserverWith({ onMove(fromIdx, toIdx, value) { moved = true; const result = range.queryMove(fromIdx, toIdx, value, list); @@ -451,7 +452,7 @@ export function tests() { toIdx: 3 }); } - }); + })); list.move(2, 3); assert(moved); }, @@ -459,7 +460,7 @@ export function tests() { const list = new ObservableArray(["a", "b", "c", "d", "e"]); const range = new ListRange(2, 5, list.length); let moved = false; - list.subscribe({ + list.subscribe(defaultObserverWith({ onMove(fromIdx, toIdx, value) { moved = true; const result = range.queryMove(fromIdx, toIdx, value, list); @@ -470,7 +471,7 @@ export function tests() { value: "a" }); } - }); + })); list.move(0, 3); // move "a" to after "d" assert(moved); }, @@ -478,7 +479,7 @@ export function tests() { const list = new ObservableArray(["a", "b", "c", "d", "e"]); const range = new ListRange(0, 3, list.length); let moved = false; - list.subscribe({ + list.subscribe(defaultObserverWith({ onMove(fromIdx, toIdx, value) { moved = true; const result = range.queryMove(fromIdx, toIdx, value, list); @@ -489,7 +490,7 @@ export function tests() { value: "e" }); } - }); + })); list.move(4, 1); // move "e" to before "b" assert(moved); }, @@ -497,7 +498,7 @@ export function tests() { const list = new ObservableArray(["a", "b", "c", "d", "e"]); const range = new ListRange(0, 3, list.length); let moved = false; - list.subscribe({ + list.subscribe(defaultObserverWith({ onMove(fromIdx, toIdx, value) { moved = true; const result = range.queryMove(fromIdx, toIdx, value, list); @@ -508,7 +509,7 @@ export function tests() { value: "d" }); } - }); + })); list.move(1, 3); // move "b" to after "d" assert(moved); }, @@ -516,7 +517,7 @@ export function tests() { const list = new ObservableArray(["a", "b", "c", "d", "e"]); const range = new ListRange(2, 5, list.length); let moved = false; - list.subscribe({ + list.subscribe(defaultObserverWith({ onMove(fromIdx, toIdx, value) { moved = true; const result = range.queryMove(fromIdx, toIdx, value, list); @@ -527,7 +528,7 @@ export function tests() { value: "b" }); } - }); + })); list.move(3, 0); // move "d" to before "a" assert(moved); }, @@ -535,7 +536,7 @@ export function tests() { const list = new ObservableArray(["a", "b", "c", "d", "e"]); const range = new ListRange(1, 4, list.length); let moved = false; - list.subscribe({ + list.subscribe(defaultObserverWith({ onMove(fromIdx, toIdx, value) { moved = true; const result = range.queryMove(fromIdx, toIdx, value, list); @@ -546,7 +547,7 @@ export function tests() { value: "e" }); } - }); + })); list.move(0, 4); // move "a" to after "e" assert(moved); }, diff --git a/src/platform/web/ui/general/Range.ts b/src/platform/web/ui/general/Range.ts index 16dc0a33..a3ca54c0 100644 --- a/src/platform/web/ui/general/Range.ts +++ b/src/platform/web/ui/general/Range.ts @@ -43,7 +43,7 @@ export class Range { return range.start < this.end && this.start < range.end; } - forEachInIterator(it: IterableIterator, callback: ((T, i: number) => void)) { + forEachInIterator(it: Iterator, callback: ((T, i: number) => void)) { let i = 0; for (i = 0; i < this.start; i += 1) { it.next();