提交 ab2fc06b 编写于 作者: J Joao Moreno

list: fix indexIn when position is > length

上级 55544750
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import 'vs/css!./list';
import { IScrollable } from 'vs/base/common/scrollable'; import { IScrollable } from 'vs/base/common/scrollable';
import Event, { Emitter } from 'vs/base/common/event'; import Event, { Emitter } from 'vs/base/common/event';
import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IDisposable, dispose } from 'vs/base/common/lifecycle';
...@@ -14,15 +15,16 @@ import { RangeMap } from './rangeMap'; ...@@ -14,15 +15,16 @@ import { RangeMap } from './rangeMap';
import { IScrollEvent, IDelegate, IRendererMap } from './list'; import { IScrollEvent, IDelegate, IRendererMap } from './list';
import { RowCache, IRow } from './rowCache'; import { RowCache, IRow } from './rowCache';
interface IItem { interface IItem<T> {
height: number; element: T;
size: number;
templateId: string; templateId: string;
row: IRow; row: IRow;
} }
export class List<T> implements IScrollable { export class List<T> implements IScrollable {
private items: IItem[]; private items: IItem<T>[];
private rangeMap: RangeMap; private rangeMap: RangeMap;
private cache: RowCache<T>; private cache: RowCache<T>;
...@@ -40,7 +42,11 @@ export class List<T> implements IScrollable { ...@@ -40,7 +42,11 @@ export class List<T> implements IScrollable {
private _onScroll = new Emitter<IScrollEvent>(); private _onScroll = new Emitter<IScrollEvent>();
onScroll: Event<IScrollEvent> = this._onScroll.event; onScroll: Event<IScrollEvent> = this._onScroll.event;
constructor(container: HTMLElement, delegate: IDelegate<T>, renderers: IRendererMap<T>) { constructor(
container: HTMLElement,
private delegate: IDelegate<T>,
private renderers: IRendererMap<T>
) {
this.items = []; this.items = [];
this.rangeMap = new RangeMap(); this.rangeMap = new RangeMap();
this.cache = new RowCache(renderers); this.cache = new RowCache(renderers);
...@@ -64,6 +70,35 @@ export class List<T> implements IScrollable { ...@@ -64,6 +70,35 @@ export class List<T> implements IScrollable {
this.rowsContainer = document.createElement('div'); this.rowsContainer = document.createElement('div');
this.rowsContainer.className = 'monaco-list-rows'; this.rowsContainer.className = 'monaco-list-rows';
this.wrapper.appendChild(this.rowsContainer);
this.domNode.appendChild(this.scrollableElement.getDomNode());
container.appendChild(this.domNode);
this._scrollTop = 0;
this._viewHeight = 0;
this.renderTop = 0;
this.renderHeight = 0;
this.layout();
}
splice(start: number, deleteCount: number, ...elements: T[]): void {
const inserted = elements.map<IItem<T>>(element => ({
element,
size: this.delegate.getHeight(element),
templateId: this.delegate.getTemplateId(element),
row: null
}));
this.rangeMap.splice(start, deleteCount, ...inserted);
const deleted = this.items.splice(start, deleteCount, ...inserted);
deleted.forEach(item => this.removeItemFromDOM(item));
inserted.forEach((_, index) => this.insertItemInDOM(start + index));
this.setScrollTop(this.scrollTop);
this.scrollableElement.onElementInternalDimensions();
} }
layout(height?: number): void { layout(height?: number): void {
...@@ -120,7 +155,7 @@ export class List<T> implements IScrollable { ...@@ -120,7 +155,7 @@ export class List<T> implements IScrollable {
return this._viewHeight; return this._viewHeight;
} }
private set viewHeight(viewHeight: number) { private set viewHeight(viewHeight: number) {
this.render(this.scrollTop, viewHeight); this.render(this.scrollTop, viewHeight);
this._viewHeight = viewHeight; this._viewHeight = viewHeight;
} }
...@@ -135,6 +170,10 @@ export class List<T> implements IScrollable { ...@@ -135,6 +170,10 @@ export class List<T> implements IScrollable {
// Render // Render
private indexAfter(position: number): number {
return Math.min(this.rangeMap.indexAt(position) + 1, this.rangeMap.count);
}
private render(scrollTop: number, viewHeight: number): void { private render(scrollTop: number, viewHeight: number): void {
const renderTop = Math.max(scrollTop, 0); const renderTop = Math.max(scrollTop, 0);
const renderBottom = scrollTop + viewHeight; const renderBottom = scrollTop + viewHeight;
...@@ -153,12 +192,12 @@ export class List<T> implements IScrollable { ...@@ -153,12 +192,12 @@ export class List<T> implements IScrollable {
// when view scrolls down, start unrendering from renderTop // when view scrolls down, start unrendering from renderTop
for (i = this.rangeMap.indexAt(this.renderTop), stop = Math.min(this.rangeMap.indexAt(renderTop), this.indexAfter(thisRenderBottom)); i < stop; i++) { for (i = this.rangeMap.indexAt(this.renderTop), stop = Math.min(this.rangeMap.indexAt(renderTop), this.indexAfter(thisRenderBottom)); i < stop; i++) {
this.removeItemFromDOM(i); this.removeItemFromDOM(this.items[i]);
} }
// when view scrolls up, start unrendering from either renderBottom this.renderTop // when view scrolls up, start unrendering from either renderBottom this.renderTop
for (i = Math.max(this.indexAfter(renderBottom), this.rangeMap.indexAt(this.renderTop)), stop = this.indexAfter(thisRenderBottom); i < stop; i++) { for (i = Math.max(this.indexAfter(renderBottom), this.rangeMap.indexAt(this.renderTop)), stop = this.indexAfter(thisRenderBottom); i < stop; i++) {
this.removeItemFromDOM(i); this.removeItemFromDOM(this.items[i]);
} }
const topPosition = this.rangeMap.positionAt(this.rangeMap.indexAt(renderTop)); const topPosition = this.rangeMap.positionAt(this.rangeMap.indexAt(renderTop));
...@@ -171,11 +210,29 @@ export class List<T> implements IScrollable { ...@@ -171,11 +210,29 @@ export class List<T> implements IScrollable {
this.renderHeight = renderBottom - renderTop; this.renderHeight = renderBottom - renderTop;
} }
private indexAfter(position: number): number { private isInView(index: number): boolean {
return Math.min(this.rangeMap.indexAt(position) + 1, this.rangeMap.size); const item = this.items[index];
const top = this.rangeMap.positionAt(index);
return top < this.renderTop + this.renderHeight && top + item.size > this.renderTop;
}
private refreshItem(index: number): void {
if (index < 0) {
return;
}
if (this.isInView(index)) {
this.insertItemInDOM(index);
} else {
this.removeItemFromDOM(this.items[index]);
}
} }
private insertItemInDOM(index: number): void { private insertItemInDOM(index: number): void {
if (index < 0) {
return;
}
const item = this.items[index]; const item = this.items[index];
if (!item.row) { if (!item.row) {
...@@ -200,10 +257,8 @@ export class List<T> implements IScrollable { ...@@ -200,10 +257,8 @@ export class List<T> implements IScrollable {
this.renderItem(index); this.renderItem(index);
} }
private removeItemFromDOM(index: number): void { private removeItemFromDOM(item: IItem<T>): void {
const item = this.items[index]; if (!item || !item.row) {
if (!item.row) {
return; return;
} }
...@@ -213,7 +268,11 @@ export class List<T> implements IScrollable { ...@@ -213,7 +268,11 @@ export class List<T> implements IScrollable {
} }
private renderItem(index: number): void { private renderItem(index: number): void {
// TODO const item = this.items[index];
const renderer = this.renderers[item.templateId];
item.row.domNode.style.height = `${ item.size }px`;
renderer.renderElement(item.element, item.row.templateData);
} }
dispose() { dispose() {
......
...@@ -161,17 +161,18 @@ export class RangeMap { ...@@ -161,17 +161,18 @@ export class RangeMap {
let size = 0; let size = 0;
for (const group of this.groups) { for (const group of this.groups) {
const newSize = size + ((group.range.end - group.range.start) * group.size); const count = group.range.end - group.range.start;
const newSize = size + (count * group.size);
if (position < newSize) { if (position < newSize) {
return index + Math.floor((position - size) / group.size); return index + Math.floor((position - size) / group.size);
} }
index += group.size; index += count;
size = newSize; size = newSize;
} }
return -1; return index;
} }
/** /**
......
...@@ -44,7 +44,7 @@ export class RowCache<T> implements IDisposable { ...@@ -44,7 +44,7 @@ export class RowCache<T> implements IDisposable {
let result = this.getTemplateCache(templateId).pop(); let result = this.getTemplateCache(templateId).pop();
if (!result) { if (!result) {
const domNode = $('div'); const domNode = $('.monaco-list-row');
const content = append(domNode, $('.content')); const content = append(domNode, $('.content'));
const renderer = this.renderers[templateId]; const renderer = this.renderers[templateId];
const templateData = renderer.renderTemplate(content); const templateData = renderer.renderTemplate(content);
......
...@@ -268,8 +268,8 @@ suite('RangeMap', () => { ...@@ -268,8 +268,8 @@ suite('RangeMap', () => {
suite('indexAt, positionAt', () => { suite('indexAt, positionAt', () => {
test('empty', () => { test('empty', () => {
assert.equal(rangeMap.indexAt(0), -1); assert.equal(rangeMap.indexAt(0), 0);
assert.equal(rangeMap.indexAt(10), -1); assert.equal(rangeMap.indexAt(10), 0);
assert.equal(rangeMap.indexAt(-1), -1); assert.equal(rangeMap.indexAt(-1), -1);
assert.equal(rangeMap.positionAt(0), -1); assert.equal(rangeMap.positionAt(0), -1);
assert.equal(rangeMap.positionAt(10), -1); assert.equal(rangeMap.positionAt(10), -1);
...@@ -279,7 +279,7 @@ suite('RangeMap', () => { ...@@ -279,7 +279,7 @@ suite('RangeMap', () => {
test('simple', () => { test('simple', () => {
rangeMap.splice(0, 0, one); rangeMap.splice(0, 0, one);
assert.equal(rangeMap.indexAt(0), 0); assert.equal(rangeMap.indexAt(0), 0);
assert.equal(rangeMap.indexAt(1), -1); assert.equal(rangeMap.indexAt(1), 1);
assert.equal(rangeMap.positionAt(0), 0); assert.equal(rangeMap.positionAt(0), 0);
assert.equal(rangeMap.positionAt(1), -1); assert.equal(rangeMap.positionAt(1), -1);
}); });
...@@ -289,7 +289,7 @@ suite('RangeMap', () => { ...@@ -289,7 +289,7 @@ suite('RangeMap', () => {
assert.equal(rangeMap.indexAt(0), 0); assert.equal(rangeMap.indexAt(0), 0);
assert.equal(rangeMap.indexAt(5), 0); assert.equal(rangeMap.indexAt(5), 0);
assert.equal(rangeMap.indexAt(9), 0); assert.equal(rangeMap.indexAt(9), 0);
assert.equal(rangeMap.indexAt(10), -1); assert.equal(rangeMap.indexAt(10), 1);
assert.equal(rangeMap.positionAt(0), 0); assert.equal(rangeMap.positionAt(0), 0);
assert.equal(rangeMap.positionAt(1), -1); assert.equal(rangeMap.positionAt(1), -1);
}); });
...@@ -300,12 +300,14 @@ suite('RangeMap', () => { ...@@ -300,12 +300,14 @@ suite('RangeMap', () => {
assert.equal(rangeMap.indexAt(1), 1); assert.equal(rangeMap.indexAt(1), 1);
assert.equal(rangeMap.indexAt(5), 5); assert.equal(rangeMap.indexAt(5), 5);
assert.equal(rangeMap.indexAt(9), 9); assert.equal(rangeMap.indexAt(9), 9);
assert.equal(rangeMap.indexAt(10), -1); assert.equal(rangeMap.indexAt(10), 10);
assert.equal(rangeMap.indexAt(11), 10);
rangeMap.splice(10, 0, one, one, one, one, one, one, one, one, one, one); rangeMap.splice(10, 0, one, one, one, one, one, one, one, one, one, one);
assert.equal(rangeMap.indexAt(10), 10); assert.equal(rangeMap.indexAt(10), 10);
assert.equal(rangeMap.indexAt(19), 19); assert.equal(rangeMap.indexAt(19), 19);
assert.equal(rangeMap.indexAt(20), -1); assert.equal(rangeMap.indexAt(20), 20);
assert.equal(rangeMap.indexAt(21), 20);
assert.equal(rangeMap.positionAt(0), 0); assert.equal(rangeMap.positionAt(0), 0);
assert.equal(rangeMap.positionAt(1), 1); assert.equal(rangeMap.positionAt(1), 1);
assert.equal(rangeMap.positionAt(19), 19); assert.equal(rangeMap.positionAt(19), 19);
...@@ -319,7 +321,8 @@ suite('RangeMap', () => { ...@@ -319,7 +321,8 @@ suite('RangeMap', () => {
assert.equal(rangeMap.indexAt(0), 0); assert.equal(rangeMap.indexAt(0), 0);
assert.equal(rangeMap.indexAt(1), 1); assert.equal(rangeMap.indexAt(1), 1);
assert.equal(rangeMap.indexAt(3), 3); assert.equal(rangeMap.indexAt(3), 3);
assert.equal(rangeMap.indexAt(4), -1); assert.equal(rangeMap.indexAt(4), 4);
assert.equal(rangeMap.indexAt(5), 4);
assert.equal(rangeMap.positionAt(0), 0); assert.equal(rangeMap.positionAt(0), 0);
assert.equal(rangeMap.positionAt(1), 1); assert.equal(rangeMap.positionAt(1), 1);
assert.equal(rangeMap.positionAt(3), 3); assert.equal(rangeMap.positionAt(3), 3);
...@@ -333,7 +336,8 @@ suite('RangeMap', () => { ...@@ -333,7 +336,8 @@ suite('RangeMap', () => {
assert.equal(rangeMap.indexAt(0), 0); assert.equal(rangeMap.indexAt(0), 0);
assert.equal(rangeMap.indexAt(1), 0); assert.equal(rangeMap.indexAt(1), 0);
assert.equal(rangeMap.indexAt(30), 3); assert.equal(rangeMap.indexAt(30), 3);
assert.equal(rangeMap.indexAt(40), -1); assert.equal(rangeMap.indexAt(40), 4);
assert.equal(rangeMap.indexAt(50), 4);
assert.equal(rangeMap.positionAt(0), 0); assert.equal(rangeMap.positionAt(0), 0);
assert.equal(rangeMap.positionAt(1), 10); assert.equal(rangeMap.positionAt(1), 10);
assert.equal(rangeMap.positionAt(2), 20); assert.equal(rangeMap.positionAt(2), 20);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册