提交 7d2bf6ac 编写于 作者: J Joao Moreno

list: support trait persistence

上级 8dde28b8
...@@ -67,7 +67,7 @@ export class PagedList<T> { ...@@ -67,7 +67,7 @@ export class PagedList<T> {
container: HTMLElement, container: HTMLElement,
delegate: IDelegate<number>, delegate: IDelegate<number>,
renderers: IPagedRenderer<T, any>[], renderers: IPagedRenderer<T, any>[],
options: IListOptions = {} options: IListOptions<any> = {} // TODO@Joao: should be IListOptions<T>
) { ) {
const pagedRenderers = renderers.map(r => new PagedRenderer<T, ITemplateData<T>>(r, () => this.model)); const pagedRenderers = renderers.map(r => new PagedRenderer<T, ITemplateData<T>>(r, () => this.model));
this.list = new List(container, delegate, pagedRenderers, options); this.list = new List(container, delegate, pagedRenderers, options);
......
...@@ -16,6 +16,10 @@ import { domEvent } from 'vs/base/browser/event'; ...@@ -16,6 +16,10 @@ import { domEvent } from 'vs/base/browser/event';
import { IDelegate, IRenderer, IListMouseEvent, IFocusChangeEvent, ISelectionChangeEvent } from './list'; import { IDelegate, IRenderer, IListMouseEvent, IFocusChangeEvent, ISelectionChangeEvent } from './list';
import { ListView, IListViewOptions } from './listView'; import { ListView, IListViewOptions } from './listView';
export interface IIdentityProvider<T> {
(element: T): string;
}
interface ITraitTemplateData<D> { interface ITraitTemplateData<D> {
container: HTMLElement; container: HTMLElement;
data: D; data: D;
...@@ -63,18 +67,14 @@ class Trait<T> implements IDisposable { ...@@ -63,18 +67,14 @@ class Trait<T> implements IDisposable {
this.indexes = []; this.indexes = [];
} }
splice(start: number, deleteCount: number, insertCount: number): void { splice(start: number, deleteCount: number, elements: boolean[]): void {
const diff = insertCount - deleteCount; const diff = elements.length - deleteCount;
const end = start + deleteCount; const end = start + deleteCount;
const indexes: number[] = []; const indexes = [
...this.indexes.filter(i => i < start),
for (let index of indexes) { ...elements.reduce((r, hasTrait, i) => hasTrait ? [...r, i + start] : r, []),
if (index >= start && index < end) { ...this.indexes.filter(i => i >= end).map(i => i + diff)
continue; ];
}
indexes.push(index > start ? index + diff : index);
}
this.indexes = indexes; this.indexes = indexes;
this._onChange.fire({ indexes }); this._onChange.fire({ indexes });
...@@ -111,14 +111,16 @@ class Trait<T> implements IDisposable { ...@@ -111,14 +111,16 @@ class Trait<T> implements IDisposable {
class FocusTrait<T> extends Trait<T> { class FocusTrait<T> extends Trait<T> {
constructor(private getElementId: (number: number) => string) { constructor(
private getDomId: IIdentityProvider<number>
) {
super('focused'); super('focused');
} }
renderElement(element: T, index: number, container: HTMLElement): void { renderElement(element: T, index: number, container: HTMLElement): void {
super.renderElement(element, index, container); super.renderElement(element, index, container);
container.setAttribute('role', 'treeitem'); container.setAttribute('role', 'treeitem');
container.setAttribute('id', this.getElementId(index)); container.setAttribute('id', this.getDomId(index));
} }
} }
...@@ -215,13 +217,14 @@ class MouseController<T> implements IDisposable { ...@@ -215,13 +217,14 @@ class MouseController<T> implements IDisposable {
} }
} }
export interface IListOptions extends IListViewOptions { export interface IListOptions<T> extends IListViewOptions {
identityProvider?: IIdentityProvider<T>;
ariaLabel?: string; ariaLabel?: string;
mouseSupport?: boolean; mouseSupport?: boolean;
keyboardSupport?: boolean; keyboardSupport?: boolean;
} }
const DefaultOptions: IListOptions = { const DefaultOptions: IListOptions<any> = {
keyboardSupport: true, keyboardSupport: true,
mouseSupport: true mouseSupport: true
}; };
...@@ -235,16 +238,17 @@ export class List<T> implements IDisposable { ...@@ -235,16 +238,17 @@ export class List<T> implements IDisposable {
private selection: Trait<T>; private selection: Trait<T>;
private eventBufferer: EventBufferer; private eventBufferer: EventBufferer;
private view: ListView<T>; private view: ListView<T>;
private getId?: IIdentityProvider<T>;
private disposables: IDisposable[]; private disposables: IDisposable[];
@memoize @memoize
get onFocusChange(): Event<IFocusChangeEvent<T>> { get onFocusChange(): Event<IFocusChangeEvent<T>> {
return this.eventBufferer.wrapEvent(mapEvent(this.focus.onChange, e => this.toListEvent(e))); return mapEvent(this.eventBufferer.wrapEvent(this.focus.onChange), e => this.toListEvent(e));
} }
@memoize @memoize
get onSelectionChange(): Event<ISelectionChangeEvent<T>> { get onSelectionChange(): Event<ISelectionChangeEvent<T>> {
return this.eventBufferer.wrapEvent(mapEvent(this.selection.onChange, e => this.toListEvent(e))); return mapEvent(this.eventBufferer.wrapEvent(this.selection.onChange), e => this.toListEvent(e));
} }
@memoize @memoize
...@@ -265,11 +269,12 @@ export class List<T> implements IDisposable { ...@@ -265,11 +269,12 @@ export class List<T> implements IDisposable {
container: HTMLElement, container: HTMLElement,
delegate: IDelegate<T>, delegate: IDelegate<T>,
renderers: IRenderer<T, any>[], renderers: IRenderer<T, any>[],
options: IListOptions = DefaultOptions options: IListOptions<T> = DefaultOptions
) { ) {
this.focus = new FocusTrait(i => this.getElementId(i)); this.focus = new FocusTrait(i => this.getElementDomId(i));
this.selection = new Trait('selected'); this.selection = new Trait('selected');
this.eventBufferer = new EventBufferer(); this.eventBufferer = new EventBufferer();
this.getId = options.identityProvider;
renderers = renderers.map(r => { renderers = renderers.map(r => {
r = this.focus.wrapRenderer(r); r = this.focus.wrapRenderer(r);
...@@ -304,8 +309,14 @@ export class List<T> implements IDisposable { ...@@ -304,8 +309,14 @@ export class List<T> implements IDisposable {
splice(start: number, deleteCount: number, elements: T[] = []): void { splice(start: number, deleteCount: number, elements: T[] = []): void {
this.eventBufferer.bufferEvents(() => { this.eventBufferer.bufferEvents(() => {
this.focus.splice(start, deleteCount, elements.length); const focus = this.focus.get().map(i => this.getId(this.view.element(i)));
this.selection.splice(start, deleteCount, elements.length); 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.view.splice(start, deleteCount, elements);
}); });
} }
...@@ -457,7 +468,7 @@ export class List<T> implements IDisposable { ...@@ -457,7 +468,7 @@ export class List<T> implements IDisposable {
} }
} }
getElementId(index: number): string { getElementDomId(index: number): string {
return `${this.idPrefix}_${index}`; return `${this.idPrefix}_${index}`;
} }
...@@ -477,7 +488,7 @@ export class List<T> implements IDisposable { ...@@ -477,7 +488,7 @@ export class List<T> implements IDisposable {
const focus = this.focus.get(); const focus = this.focus.get();
if (focus.length > 0) { if (focus.length > 0) {
this.view.domNode.setAttribute('aria-activedescendant', this.getElementId(focus[0])); this.view.domNode.setAttribute('aria-activedescendant', this.getElementDomId(focus[0]));
} else { } else {
this.view.domNode.removeAttribute('aria-activedescendant'); this.view.domNode.removeAttribute('aria-activedescendant');
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册