From 62383be39eefb80cf70786d616339dd68632afee Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 14 Feb 2017 16:47:44 +0100 Subject: [PATCH] list: cleanup trait preserving splice --- src/vs/base/browser/ui/list/listWidget.ts | 63 +++++++++++++++++------ 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 80726c6ff8f..e329c16252c 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -20,6 +20,19 @@ export interface IIdentityProvider { (element: T): string; } +export interface ISpliceable { + splice(start: number, deleteCount: number, elements: T[]): void; +} + +class CombinedSpliceable implements ISpliceable { + + constructor(private spliceables: ISpliceable[]) { } + + splice(start: number, deleteCount: number, elements: T[]): void { + this.spliceables.forEach(s => s.splice(start, deleteCount, elements)); + } +} + interface ITraitTemplateData { container: HTMLElement; data: D; @@ -56,7 +69,7 @@ class TraitRenderer implements IRenderer> } } -class Trait implements IDisposable { +class Trait implements ISpliceable, IDisposable { private indexes: number[]; @@ -124,6 +137,31 @@ class FocusTrait extends Trait { } } +/** + * The TraitSpliceable is used as a util class to be able + * to preserve traits across splice calls, given an identity + * provider. + */ +class TraitSpliceable implements ISpliceable { + + constructor( + private trait: Trait, + private view: ListView, + private getId?: IIdentityProvider + ) { } + + splice(start: number, deleteCount: number, elements: T[]): void { + if (!this.getId) { + return this.trait.splice(start, deleteCount, elements.map(e => false)); + } + + const pastElementsWithTrait = this.trait.get().map(i => this.getId(this.view.element(i))); + const elementsWithTrait = elements.map(e => pastElementsWithTrait.indexOf(this.getId(e)) > -1); + + this.trait.splice(start, deleteCount, elementsWithTrait); + } +} + class KeyboardController implements IDisposable { private disposables: IDisposable[]; @@ -229,7 +267,7 @@ const DefaultOptions: IListOptions = { mouseSupport: true }; -export class List implements IDisposable { +export class List implements ISpliceable, IDisposable { private static InstanceCount = 0; private idPrefix = `list_id_${++List.InstanceCount}`; @@ -238,7 +276,7 @@ export class List implements IDisposable { private selection: Trait; private eventBufferer: EventBufferer; private view: ListView; - private getId?: IIdentityProvider; + private spliceable: ISpliceable; private disposables: IDisposable[]; @memoize @@ -274,7 +312,6 @@ export class List implements IDisposable { this.focus = new FocusTrait(i => this.getElementDomId(i)); this.selection = new Trait('selected'); this.eventBufferer = new EventBufferer(); - this.getId = options.identityProvider; renderers = renderers.map(r => { r = this.focus.wrapRenderer(r); @@ -286,6 +323,12 @@ export class List implements IDisposable { this.view.domNode.setAttribute('role', 'tree'); this.view.domNode.tabIndex = 0; + this.spliceable = new CombinedSpliceable([ + new TraitSpliceable(this.focus, this.view, options.identityProvider), + new TraitSpliceable(this.selection, this.view, options.identityProvider), + this.view + ]); + this.disposables = [this.focus, this.selection, this.view, this._onDispose]; const tracker = DOM.trackFocus(this.view.domNode); @@ -308,17 +351,7 @@ export class List implements IDisposable { } splice(start: number, deleteCount: number, elements: T[] = []): void { - this.eventBufferer.bufferEvents(() => { - const focus = this.focus.get().map(i => this.getId(this.view.element(i))); - const focusElements = elements.map(e => focus.indexOf(this.getId(e)) > -1); - - const selection = this.selection.get().map(i => this.getId(this.view.element(i))); - const selectionElements = elements.map(e => selection.indexOf(this.getId(e)) > -1); - - this.focus.splice(start, deleteCount, focusElements); - this.selection.splice(start, deleteCount, selectionElements); - this.view.splice(start, deleteCount, elements); - }); + this.eventBufferer.bufferEvents(() => this.spliceable.splice(start, deleteCount, elements)); } get length(): number { -- GitLab