| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import * as Common from '../../core/common/common.js'; |
| import * as Platform from '../../core/platform/platform.js'; |
| |
| export class ListModel<T> extends Common.ObjectWrapper.ObjectWrapper implements Iterable<T> { |
| private items: T[]; |
| constructor(items?: T[]) { |
| super(); |
| this.items = items || []; |
| } |
| |
| // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any |
| [Symbol.iterator](): Iterator<T, any, undefined> { |
| return this.items[Symbol.iterator](); |
| } |
| |
| get length(): number { |
| return this.items.length; |
| } |
| |
| at(index: number): T { |
| return this.items[index]; |
| } |
| |
| every(callback: (arg0: T) => boolean): boolean { |
| return this.items.every(callback); |
| } |
| |
| filter(callback: (arg0: T) => boolean): T[] { |
| return this.items.filter(callback); |
| } |
| |
| find(callback: (arg0: T) => boolean): T|undefined { |
| return this.items.find(callback); |
| } |
| |
| findIndex(callback: (arg0: T) => boolean): number { |
| return this.items.findIndex(callback); |
| } |
| |
| indexOf(value: T, fromIndex?: number): number { |
| return this.items.indexOf(value, fromIndex); |
| } |
| |
| insert(index: number, value: T): void { |
| this.items.splice(index, 0, value); |
| this.replaced(index, [], 1); |
| } |
| |
| insertWithComparator(value: T, comparator: (arg0: T, arg1: T) => number): void { |
| this.insert(Platform.ArrayUtilities.lowerBound(this.items, value, comparator), value); |
| } |
| |
| join(separator?: string): string { |
| return this.items.join(separator); |
| } |
| |
| remove(index: number): T { |
| const result = this.items[index]; |
| this.items.splice(index, 1); |
| this.replaced(index, [result], 0); |
| return result; |
| } |
| |
| replace(index: number, value: T, keepSelectedIndex?: boolean): T { |
| const oldValue = this.items[index]; |
| this.items[index] = value; |
| this.replaced(index, [oldValue], 1, keepSelectedIndex); |
| return oldValue; |
| } |
| |
| replaceRange(from: number, to: number, items: T[]): T[] { |
| let removed; |
| if (items.length < 10000) { |
| removed = this.items.splice(from, to - from, ...items); |
| } else { |
| removed = this.items.slice(from, to); |
| // Splice may fail with too many arguments. |
| const before = this.items.slice(0, from); |
| const after = this.items.slice(to); |
| this.items = [...before, ...items, ...after]; |
| } |
| this.replaced(from, removed, items.length); |
| return removed; |
| } |
| |
| replaceAll(items: T[]): T[] { |
| const oldItems = this.items.slice(); |
| this.items = items; |
| this.replaced(0, oldItems, items.length); |
| return oldItems; |
| } |
| |
| slice(from?: number, to?: number): T[] { |
| return this.items.slice(from, to); |
| } |
| |
| some(callback: (arg0: T) => boolean): boolean { |
| return this.items.some(callback); |
| } |
| |
| private replaced(index: number, removed: T[], inserted: number, keepSelectedIndex?: boolean): void { |
| this.dispatchEventToListeners(Events.ItemsReplaced, {index, removed, inserted, keepSelectedIndex}); |
| } |
| } |
| |
| // TODO(crbug.com/1167717): Make this a const enum again |
| // eslint-disable-next-line rulesdir/const_enum |
| export enum Events { |
| ItemsReplaced = 'ItemsReplaced', |
| } |