Skip to content

Commit 62383be

Browse files
committed
list: cleanup trait preserving splice
1 parent efbd753 commit 62383be

1 file changed

Lines changed: 48 additions & 15 deletions

File tree

src/vs/base/browser/ui/list/listWidget.ts

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,19 @@ export interface IIdentityProvider<T> {
2020
(element: T): string;
2121
}
2222

23+
export interface ISpliceable<T> {
24+
splice(start: number, deleteCount: number, elements: T[]): void;
25+
}
26+
27+
class CombinedSpliceable<T> implements ISpliceable<T> {
28+
29+
constructor(private spliceables: ISpliceable<T>[]) { }
30+
31+
splice(start: number, deleteCount: number, elements: T[]): void {
32+
this.spliceables.forEach(s => s.splice(start, deleteCount, elements));
33+
}
34+
}
35+
2336
interface ITraitTemplateData<D> {
2437
container: HTMLElement;
2538
data: D;
@@ -56,7 +69,7 @@ class TraitRenderer<T, D> implements IRenderer<T, ITraitTemplateData<D>>
5669
}
5770
}
5871

59-
class Trait<T> implements IDisposable {
72+
class Trait<T> implements ISpliceable<boolean>, IDisposable {
6073

6174
private indexes: number[];
6275

@@ -124,6 +137,31 @@ class FocusTrait<T> extends Trait<T> {
124137
}
125138
}
126139

140+
/**
141+
* The TraitSpliceable is used as a util class to be able
142+
* to preserve traits across splice calls, given an identity
143+
* provider.
144+
*/
145+
class TraitSpliceable<T> implements ISpliceable<T> {
146+
147+
constructor(
148+
private trait: Trait<T>,
149+
private view: ListView<T>,
150+
private getId?: IIdentityProvider<T>
151+
) { }
152+
153+
splice(start: number, deleteCount: number, elements: T[]): void {
154+
if (!this.getId) {
155+
return this.trait.splice(start, deleteCount, elements.map(e => false));
156+
}
157+
158+
const pastElementsWithTrait = this.trait.get().map(i => this.getId(this.view.element(i)));
159+
const elementsWithTrait = elements.map(e => pastElementsWithTrait.indexOf(this.getId(e)) > -1);
160+
161+
this.trait.splice(start, deleteCount, elementsWithTrait);
162+
}
163+
}
164+
127165
class KeyboardController<T> implements IDisposable {
128166
private disposables: IDisposable[];
129167

@@ -229,7 +267,7 @@ const DefaultOptions: IListOptions<any> = {
229267
mouseSupport: true
230268
};
231269

232-
export class List<T> implements IDisposable {
270+
export class List<T> implements ISpliceable<T>, IDisposable {
233271

234272
private static InstanceCount = 0;
235273
private idPrefix = `list_id_${++List.InstanceCount}`;
@@ -238,7 +276,7 @@ export class List<T> implements IDisposable {
238276
private selection: Trait<T>;
239277
private eventBufferer: EventBufferer;
240278
private view: ListView<T>;
241-
private getId?: IIdentityProvider<T>;
279+
private spliceable: ISpliceable<T>;
242280
private disposables: IDisposable[];
243281

244282
@memoize
@@ -274,7 +312,6 @@ export class List<T> implements IDisposable {
274312
this.focus = new FocusTrait(i => this.getElementDomId(i));
275313
this.selection = new Trait('selected');
276314
this.eventBufferer = new EventBufferer();
277-
this.getId = options.identityProvider;
278315

279316
renderers = renderers.map(r => {
280317
r = this.focus.wrapRenderer(r);
@@ -286,6 +323,12 @@ export class List<T> implements IDisposable {
286323
this.view.domNode.setAttribute('role', 'tree');
287324
this.view.domNode.tabIndex = 0;
288325

326+
this.spliceable = new CombinedSpliceable([
327+
new TraitSpliceable(this.focus, this.view, options.identityProvider),
328+
new TraitSpliceable(this.selection, this.view, options.identityProvider),
329+
this.view
330+
]);
331+
289332
this.disposables = [this.focus, this.selection, this.view, this._onDispose];
290333

291334
const tracker = DOM.trackFocus(this.view.domNode);
@@ -308,17 +351,7 @@ export class List<T> implements IDisposable {
308351
}
309352

310353
splice(start: number, deleteCount: number, elements: T[] = []): void {
311-
this.eventBufferer.bufferEvents(() => {
312-
const focus = this.focus.get().map(i => this.getId(this.view.element(i)));
313-
const focusElements = elements.map(e => focus.indexOf(this.getId(e)) > -1);
314-
315-
const selection = this.selection.get().map(i => this.getId(this.view.element(i)));
316-
const selectionElements = elements.map(e => selection.indexOf(this.getId(e)) > -1);
317-
318-
this.focus.splice(start, deleteCount, focusElements);
319-
this.selection.splice(start, deleteCount, selectionElements);
320-
this.view.splice(start, deleteCount, elements);
321-
});
354+
this.eventBufferer.bufferEvents(() => this.spliceable.splice(start, deleteCount, elements));
322355
}
323356

324357
get length(): number {

0 commit comments

Comments
 (0)