mirror of
https://github.com/vector-im/element-web.git
synced 2026-05-04 19:56:45 +02:00
Add onFirstWatch and onLastWatch to watchable
So that we can create custom watchable objects that can add/remove event listeners as necessary.
This commit is contained in:
parent
17f1a54a1f
commit
cd9a21ac93
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { expect, test, vitest } from "vitest";
|
||||
import { expect, test, vi, vitest } from "vitest";
|
||||
|
||||
import { Watchable } from "./watchable";
|
||||
|
||||
@ -56,3 +56,44 @@ test("when value is an object, shallow comparison works", () => {
|
||||
|
||||
watchable.unwatch(listener); // Clean up after the test
|
||||
});
|
||||
|
||||
test("onFirstWatch and onLastWatch are called when appropriate", () => {
|
||||
const onFirstWatch = vi.fn();
|
||||
const onLastWatch = vi.fn();
|
||||
class CustomWatchable extends Watchable<number> {
|
||||
protected onFirstWatch(): void {
|
||||
onFirstWatch();
|
||||
}
|
||||
protected onLastWatch(): void {
|
||||
onLastWatch();
|
||||
}
|
||||
}
|
||||
|
||||
const watchable = new CustomWatchable(10);
|
||||
// No listeners yet, so expect no calls
|
||||
expect(onFirstWatch).not.toHaveBeenCalled();
|
||||
expect(onLastWatch).not.toHaveBeenCalled();
|
||||
|
||||
// Let's say that we have three listeners
|
||||
const listeners = [vi.fn(), vi.fn(), vi.fn()];
|
||||
|
||||
// Let's add all of them via watch
|
||||
for (const listener of listeners) {
|
||||
watchable.watch(listener);
|
||||
}
|
||||
|
||||
// Only expect onFirstWatch() to have been called once
|
||||
expect(onFirstWatch).toHaveBeenCalledOnce();
|
||||
|
||||
// Let's remove all the listeners
|
||||
for (const listener of listeners) {
|
||||
watchable.unwatch(listener);
|
||||
}
|
||||
|
||||
// Only expect onLastWatch to have been called once
|
||||
expect(onLastWatch).toHaveBeenCalledOnce();
|
||||
|
||||
// Should call onFirstWatch again once we have more listeners
|
||||
watchable.watch(vi.fn());
|
||||
expect(onFirstWatch).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
@ -30,6 +30,10 @@ export class Watchable<T> {
|
||||
|
||||
public constructor(private currentValue: T) {}
|
||||
|
||||
/**
|
||||
* The value stored in this watchable.
|
||||
* Warning: Could potentially return stale data if you haven't called {@link Watchable#watch}.
|
||||
*/
|
||||
public get value(): T {
|
||||
return this.currentValue;
|
||||
}
|
||||
@ -50,12 +54,32 @@ export class Watchable<T> {
|
||||
}
|
||||
|
||||
public watch(listener: (value: T) => void): void {
|
||||
// Call onFirstWatch if there was no listener before.
|
||||
if (this.listeners.size === 0) {
|
||||
this.onFirstWatch();
|
||||
}
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
public unwatch(listener: (value: T) => void): void {
|
||||
this.listeners.delete(listener);
|
||||
const hasDeleted = this.listeners.delete(listener);
|
||||
// Call onLastWatch if every listener has been removed.
|
||||
if (hasDeleted && this.listeners.size === 0) {
|
||||
this.onLastWatch();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when the number of listeners go from zero to one.
|
||||
* Could be used to add external event listeners.
|
||||
*/
|
||||
protected onFirstWatch(): void {}
|
||||
|
||||
/**
|
||||
* This is called when the number of listeners go from one to zero.
|
||||
* Could be used to remove external event listeners.
|
||||
*/
|
||||
protected onLastWatch(): void {}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user