diff --git a/src/observable/list/MappedList.js b/src/observable/list/MappedList.js index 139a6e73..0bc4065a 100644 --- a/src/observable/list/MappedList.js +++ b/src/observable/list/MappedList.js @@ -1,5 +1,6 @@ /* Copyright 2020 Bruno Windels +Copyright 2021 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,11 +18,12 @@ limitations under the License. import {BaseObservableList} from "./BaseObservableList.js"; export class MappedList extends BaseObservableList { - constructor(sourceList, mapper, updater) { + constructor(sourceList, mapper, updater, removeCallback) { super(); this._sourceList = sourceList; this._mapper = mapper; this._updater = updater; + this._removeCallback = removeCallback; this._sourceUnsubscribe = null; this._mappedValues = null; } @@ -56,6 +58,9 @@ export class MappedList extends BaseObservableList { onRemove(index) { const mappedValue = this._mappedValues[index]; this._mappedValues.splice(index, 1); + if (this._removeCallback) { + this._removeCallback(mappedValue); + } this.emitRemove(index, mappedValue); } @@ -70,6 +75,21 @@ export class MappedList extends BaseObservableList { this._sourceUnsubscribe(); } + findAndUpdate(predicate, updater) { + const index = this._mappedValues.findIndex(predicate); + if (index !== -1) { + const mappedValue = this._mappedValues[index]; + // allow bailing out of sending an emit if updater determined its not needed + const params = updater(mappedValue); + if (params !== false) { + this.emitUpdate(index, mappedValue, params); + } + // found + return true; + } + return false; + } + get length() { return this._mappedValues.length; } @@ -79,6 +99,8 @@ export class MappedList extends BaseObservableList { } } +import {ObservableArray} from "./ObservableArray.js"; + export async function tests() { class MockList extends BaseObservableList { get length() { @@ -126,6 +148,59 @@ export async function tests() { source.emitUpdate(0, 7); assert(fired); unsubscribe(); - } + }, + "test findAndUpdate not found": assert => { + const source = new ObservableArray([1, 3, 4]); + const mapped = new MappedList( + source, + n => {return n*n;} + ); + mapped.subscribe({ + onUpdate() { assert.fail(); } + }); + assert.equal(mapped.findAndUpdate( + n => n === 100, + () => assert.fail() + ), false); + }, + "test findAndUpdate found but updater bails out of update": assert => { + const source = new ObservableArray([1, 3, 4]); + const mapped = new MappedList( + source, + n => {return n*n;} + ); + mapped.subscribe({ + onUpdate() { assert.fail(); } + }); + let fired = false; + assert.equal(mapped.findAndUpdate( + n => n === 9, + n => { + assert.equal(n, 9); + fired = true; + return false; + } + ), true); + assert.equal(fired, true); + }, + "test findAndUpdate emits update": assert => { + const source = new ObservableArray([1, 3, 4]); + const mapped = new MappedList( + source, + n => {return n*n;} + ); + let fired = false; + mapped.subscribe({ + 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); + }, + }; }