Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 1 | // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 5 | import * as Common from '../../core/common/common.js'; |
| 6 | import * as Platform from '../../core/platform/platform.js'; |
| 7 | |
| 8 | export class ListModel<T> extends Common.ObjectWrapper.ObjectWrapper implements Iterable<T> { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 9 | private items: T[]; |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 10 | constructor(items?: T[]) { |
| 11 | super(); |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 12 | this.items = items || []; |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 13 | } |
| 14 | |
| 15 | // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration |
| 16 | // eslint-disable-next-line @typescript-eslint/no-explicit-any |
| 17 | [Symbol.iterator](): Iterator<T, any, undefined> { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 18 | return this.items[Symbol.iterator](); |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 19 | } |
| 20 | |
| 21 | get length(): number { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 22 | return this.items.length; |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 23 | } |
| 24 | |
| 25 | at(index: number): T { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 26 | return this.items[index]; |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 27 | } |
| 28 | |
| 29 | every(callback: (arg0: T) => boolean): boolean { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 30 | return this.items.every(callback); |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 31 | } |
| 32 | |
| 33 | filter(callback: (arg0: T) => boolean): T[] { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 34 | return this.items.filter(callback); |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 35 | } |
| 36 | |
| 37 | find(callback: (arg0: T) => boolean): T|undefined { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 38 | return this.items.find(callback); |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 39 | } |
| 40 | |
| 41 | findIndex(callback: (arg0: T) => boolean): number { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 42 | return this.items.findIndex(callback); |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 43 | } |
| 44 | |
| 45 | indexOf(value: T, fromIndex?: number): number { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 46 | return this.items.indexOf(value, fromIndex); |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 47 | } |
| 48 | |
| 49 | insert(index: number, value: T): void { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 50 | this.items.splice(index, 0, value); |
| 51 | this.replaced(index, [], 1); |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 52 | } |
| 53 | |
| 54 | insertWithComparator(value: T, comparator: (arg0: T, arg1: T) => number): void { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 55 | this.insert(Platform.ArrayUtilities.lowerBound(this.items, value, comparator), value); |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 56 | } |
| 57 | |
| 58 | join(separator?: string): string { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 59 | return this.items.join(separator); |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 60 | } |
| 61 | |
| 62 | remove(index: number): T { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 63 | const result = this.items[index]; |
| 64 | this.items.splice(index, 1); |
| 65 | this.replaced(index, [result], 0); |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 66 | return result; |
| 67 | } |
| 68 | |
| 69 | replace(index: number, value: T, keepSelectedIndex?: boolean): T { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 70 | const oldValue = this.items[index]; |
| 71 | this.items[index] = value; |
| 72 | this.replaced(index, [oldValue], 1, keepSelectedIndex); |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 73 | return oldValue; |
| 74 | } |
| 75 | |
| 76 | replaceRange(from: number, to: number, items: T[]): T[] { |
| 77 | let removed; |
| 78 | if (items.length < 10000) { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 79 | removed = this.items.splice(from, to - from, ...items); |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 80 | } else { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 81 | removed = this.items.slice(from, to); |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 82 | // Splice may fail with too many arguments. |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 83 | const before = this.items.slice(0, from); |
| 84 | const after = this.items.slice(to); |
| 85 | this.items = [...before, ...items, ...after]; |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 86 | } |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 87 | this.replaced(from, removed, items.length); |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 88 | return removed; |
| 89 | } |
| 90 | |
| 91 | replaceAll(items: T[]): T[] { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 92 | const oldItems = this.items.slice(); |
| 93 | this.items = items; |
| 94 | this.replaced(0, oldItems, items.length); |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 95 | return oldItems; |
| 96 | } |
| 97 | |
| 98 | slice(from?: number, to?: number): T[] { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 99 | return this.items.slice(from, to); |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 100 | } |
| 101 | |
| 102 | some(callback: (arg0: T) => boolean): boolean { |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 103 | return this.items.some(callback); |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 104 | } |
| 105 | |
Jan Scheffler | 01eab3c | 2021-08-16 17:18:07 | [diff] [blame^] | 106 | private replaced(index: number, removed: T[], inserted: number, keepSelectedIndex?: boolean): void { |
Jan Scheffler | 16b7c0c | 2021-04-14 15:58:14 | [diff] [blame] | 107 | this.dispatchEventToListeners(Events.ItemsReplaced, {index, removed, inserted, keepSelectedIndex}); |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | // TODO(crbug.com/1167717): Make this a const enum again |
| 112 | // eslint-disable-next-line rulesdir/const_enum |
| 113 | export enum Events { |
| 114 | ItemsReplaced = 'ItemsReplaced', |
| 115 | } |