@@ -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+
2336interface 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+
127165class 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