Telegram Web K with changes to work inside I2P https://web.telegram.i2p/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

174 lines
4.6 KiB

/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import insertInDescendSortedArray from "./array/insertInDescendSortedArray";
import { getMiddleware } from "./middleware";
import safeAssign from "./object/safeAssign";
export type SortedElementId = PeerId;
export type SortedElementBase = {
id: SortedElementId,
index: number
};
export default class SortedList<SortedElement extends SortedElementBase> {
protected elements: Map<SortedElementId, SortedElement>;
protected sorted: Array<SortedElement>;
protected getIndex: (element: SortedElement) => PromiseLike<number> | number;
protected onDelete: (element: SortedElement) => void;
protected onUpdate: (element: SortedElement) => void;
protected onSort: (element: SortedElement, idx: number) => void;
protected onElementCreate: (base: SortedElementBase, batch: boolean) => SortedElement;
protected updateElementWith = (callback: () => void) => callback();
protected updateListWith = (callback: (canUpdate: boolean | undefined) => void) => callback(true);
protected middleware = getMiddleware();
constructor(options: {
getIndex: SortedList<SortedElement>['getIndex'],
onDelete?: SortedList<SortedElement>['onDelete'],
onUpdate?: SortedList<SortedElement>['onUpdate'],
onSort?: SortedList<SortedElement>['onSort'],
onElementCreate: SortedList<SortedElement>['onElementCreate'],
updateElementWith?: SortedList<SortedElement>['updateElementWith'],
updateListWith?: SortedList<SortedElement>['updateListWith']
}) {
safeAssign(this, options);
this.elements = new Map();
this.sorted = [];
}
public clear() {
this.middleware.clean();
this.elements.clear();
this.sorted.length = 0;
}
protected _updateList() {
this.elements.forEach((element) => {
this.update(element.id, true);
});
if(this.onSort) {
this.sorted.forEach((element, idx) => {
this.onSort(element, idx);
});
}
}
public updateList(callback: (updated: boolean) => void) {
const middleware = this.middleware.get();
this.updateListWith((canUpdate) => {
if(!middleware() || (canUpdate !== undefined && !canUpdate)) {
return callback(false);
}
this._updateList();
callback(true);
});
}
public has(id: SortedElementId) {
return this.elements.has(id);
}
public get(id: SortedElementId) {
return this.elements.get(id);
}
public getAll() {
return this.elements;
}
public add(
id: SortedElementId,
batch = false,
updateElementWith?: SortedList<SortedElement>['updateElementWith'],
updateBatch = batch
) {
let element = this.get(id);
if(element) {
return element;
}
const base: SortedElementBase = {
id,
index: 0
};
element = this.onElementCreate(base, batch);
this.elements.set(id, element);
this.update(id, updateBatch, element, updateElementWith);
return element;
}
public delete(id: SortedElementId, noScheduler?: boolean) {
const element = this.elements.get(id);
if(!element) {
return false;
}
this.elements.delete(id);
const idx = this.sorted.indexOf(element);
if(idx !== -1) {
this.sorted.splice(idx, 1);
}
if(this.onDelete) {
if(noScheduler) {
this.onDelete(element);
} else {
const middleware = this.middleware.get();
this.updateElementWith(() => {
if(!middleware()) {
return;
}
this.onDelete(element);
});
}
}
return true;
}
public async update(
id: SortedElementId,
batch = false,
element = this.get(id),
updateElementWith?: SortedList<SortedElement>['updateElementWith']
) {
if(!element) {
return;
}
element.index = await this.getIndex(element);
this.onUpdate && this.onUpdate(element);
const idx = insertInDescendSortedArray(this.sorted, element, 'index');
if(!batch && this.onSort) {
const middleware = this.middleware.get();
(updateElementWith || this.updateElementWith)(() => {
if(!middleware()) {
return;
}
// * в случае пересортировки этого же элемента во время ожидания вызовется вторая такая же. нужно соблюдать последовательность событий
this.onSort(element, idx);
/* if(this.get(id) === element) {
this.onSort(element, this.sorted.indexOf(element));
} */
});
}
}
}