未验证 提交 be2e900e 编写于 作者: R rebornix

batch dom read and write

上级 1a22d1ac
...@@ -11,6 +11,7 @@ export interface IListVirtualDelegate<T> { ...@@ -11,6 +11,7 @@ export interface IListVirtualDelegate<T> {
getHeight(element: T): number; getHeight(element: T): number;
getTemplateId(element: T): string; getTemplateId(element: T): string;
hasDynamicHeight?(element: T): boolean; hasDynamicHeight?(element: T): boolean;
getDynamicHeight?(element: T): number | null;
setDynamicHeight?(element: T, height: number): void; setDynamicHeight?(element: T, height: number): void;
} }
......
...@@ -1318,6 +1318,14 @@ export class ListView<T> implements ISpliceable<T>, IDisposable { ...@@ -1318,6 +1318,14 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
private probeDynamicHeight(index: number): number { private probeDynamicHeight(index: number): number {
const item = this.items[index]; const item = this.items[index];
if (!!this.virtualDelegate.getDynamicHeight && this.virtualDelegate.getDynamicHeight(item.element) !== null) {
const size = item.size;
let newSize = this.virtualDelegate.getDynamicHeight(item.element)!;
item.size = newSize;
item.lastDynamicHeightWidth = this.renderWidth;
return newSize - size;
}
if (!item.hasDynamicHeight || item.lastDynamicHeightWidth === this.renderWidth) { if (!item.hasDynamicHeight || item.lastDynamicHeightWidth === this.renderWidth) {
return 0; return 0;
} }
......
...@@ -749,6 +749,7 @@ ...@@ -749,6 +749,7 @@
.monaco-workbench .notebookOverlay .cell-list-top-cell-toolbar-container, .monaco-workbench .notebookOverlay .cell-list-top-cell-toolbar-container,
.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container { .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container {
position: absolute; position: absolute;
top: 0px;
display: flex; display: flex;
height: 33px; height: 33px;
justify-content: center; justify-content: center;
......
...@@ -1320,7 +1320,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD ...@@ -1320,7 +1320,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
this._localStore.add(this._list.onWillScroll(e => { this._localStore.add(this._list.onWillScroll(e => {
if (this._webview?.isResolved()) { if (this._webview?.isResolved()) {
this._webviewTransparentCover!.style.top = `${e.scrollTop}px`; this._webviewTransparentCover!.style.transform = `translateY(${e.scrollTop})`;
} }
})); }));
......
...@@ -68,9 +68,14 @@ export class CellOutputElement extends Disposable { ...@@ -68,9 +68,14 @@ export class CellOutputElement extends Disposable {
public useDedicatedDOM: boolean = true; public useDedicatedDOM: boolean = true;
private _height: number = -1;
get domOffsetHeight() { get domOffsetHeight() {
if (this.useDedicatedDOM) { if (this.useDedicatedDOM) {
return this.innerContainer.offsetHeight; if (this._height === -1) {
return this.innerContainer.offsetHeight;
} else {
return this._height;
}
} else { } else {
return 0; return 0;
} }
...@@ -200,6 +205,16 @@ export class CellOutputElement extends Disposable { ...@@ -200,6 +205,16 @@ export class CellOutputElement extends Disposable {
this.innerContainer.setAttribute('output-mime-type', pickedMimeTypeRenderer.mimeType); this.innerContainer.setAttribute('output-mime-type', pickedMimeTypeRenderer.mimeType);
} }
private _initHeightChecked = false;
probeHeight(index: number) {
if (!this._initHeightChecked) {
// postponed DOM read
const offsetHeight = this.domOffsetHeight;
this.viewCell.updateOutputHeight(index, offsetHeight, 'CellOutputElement#renderResultInitHeight');
}
}
render(previousSibling?: HTMLElement): IRenderResult | undefined { render(previousSibling?: HTMLElement): IRenderResult | undefined {
const index = this.viewCell.outputsViewModels.indexOf(this.output); const index = this.viewCell.outputsViewModels.indexOf(this.output);
...@@ -264,12 +279,20 @@ export class CellOutputElement extends Disposable { ...@@ -264,12 +279,20 @@ export class CellOutputElement extends Disposable {
return { initRenderIsSynchronous: true }; return { initRenderIsSynchronous: true };
} }
// let's use resize listener for them let offsetHeight = 0;
const offsetHeight = this.renderResult?.initHeight !== undefined ? this.renderResult?.initHeight : Math.ceil(this.innerContainer.offsetHeight); if (this.renderResult?.initHeight) {
offsetHeight = this.renderResult.initHeight;
this._initHeightChecked = true;
} else {
this._initHeightChecked = false;
}
const dimension = { const dimension = {
width: this.viewCell.layoutInfo.editorWidth, width: this.viewCell.layoutInfo.editorWidth,
height: offsetHeight height: offsetHeight
}; };
// let's use resize listener for them
this._bindResizeListener(dimension); this._bindResizeListener(dimension);
this.viewCell.updateOutputHeight(index, offsetHeight, 'CellOutputElement#renderResultInitHeight'); this.viewCell.updateOutputHeight(index, offsetHeight, 'CellOutputElement#renderResultInitHeight');
const top = this.viewCell.getOutputOffsetInContainer(index); const top = this.viewCell.getOutputOffsetInContainer(index);
...@@ -296,6 +319,8 @@ export class CellOutputElement extends Disposable { ...@@ -296,6 +319,8 @@ export class CellOutputElement extends Disposable {
height: height height: height
}; };
this._initHeightChecked = true;
this._height = height;
this._validateFinalOutputHeight(true); this._validateFinalOutputHeight(true);
this.viewCell.updateOutputHeight(currIndex, height, 'CellOutputElement#outputResize'); this.viewCell.updateOutputHeight(currIndex, height, 'CellOutputElement#outputResize');
this._relayoutCell(); this._relayoutCell();
...@@ -537,6 +562,15 @@ export class CellOutputContainer extends Disposable { ...@@ -537,6 +562,15 @@ export class CellOutputContainer extends Disposable {
})); }));
} }
probeHeight() {
this._outputEntries.forEach(entry => {
const index = this.viewCell.outputsViewModels.indexOf(entry.model);
if (index >= 0) {
entry.element.probeHeight(index);
}
});
}
render(editorHeight: number) { render(editorHeight: number) {
if (this.viewCell.outputsViewModels.length > 0) { if (this.viewCell.outputsViewModels.length > 0) {
if (this.viewCell.layoutInfo.totalHeight !== 0 && this.viewCell.layoutInfo.editorHeight > editorHeight) { if (this.viewCell.layoutInfo.totalHeight !== 0 && this.viewCell.layoutInfo.editorHeight > editorHeight) {
......
...@@ -74,6 +74,10 @@ export class NotebookCellListDelegate extends Disposable implements IListVirtual ...@@ -74,6 +74,10 @@ export class NotebookCellListDelegate extends Disposable implements IListVirtual
return element.hasDynamicHeight(); return element.hasDynamicHeight();
} }
getDynamicHeight(element: CellViewModel): number | null {
return element.getDynamicHeight();
}
getTemplateId(element: CellViewModel): string { getTemplateId(element: CellViewModel): string {
if (element.cellKind === CellKind.Markup) { if (element.cellKind === CellKind.Markup) {
return MarkupCellRenderer.TEMPLATE_ID; return MarkupCellRenderer.TEMPLATE_ID;
...@@ -144,11 +148,11 @@ abstract class AbstractCellRenderer { ...@@ -144,11 +148,11 @@ abstract class AbstractCellRenderer {
const container = templateData.bottomCellContainer; const container = templateData.bottomCellContainer;
const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset; const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset;
container.style.top = `${bottomToolbarOffset}px`; container.style.transform = `translateY(${bottomToolbarOffset}px)`;
templateData.elementDisposables.add(element.onDidChangeLayout(() => { templateData.elementDisposables.add(element.onDidChangeLayout(() => {
const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset; const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset;
container.style.top = `${bottomToolbarOffset}px`; container.style.transform = `translateY(${bottomToolbarOffset}px)`;
})); }));
} }
...@@ -192,14 +196,14 @@ abstract class AbstractCellRenderer { ...@@ -192,14 +196,14 @@ abstract class AbstractCellRenderer {
if (actions.primary.length || actions.secondary.length) { if (actions.primary.length || actions.secondary.length) {
templateData.container.classList.add('cell-has-toolbar-actions'); templateData.container.classList.add('cell-has-toolbar-actions');
if (isCodeCellRenderTemplate(templateData)) { if (isCodeCellRenderTemplate(templateData)) {
templateData.focusIndicatorLeft.style.top = `${layoutInfo.editorToolbarHeight + layoutInfo.cellTopMargin}px`; templateData.focusIndicatorLeft.style.transform = `translateY(${layoutInfo.editorToolbarHeight + layoutInfo.cellTopMargin}px)`;
templateData.focusIndicatorRight.style.top = `${layoutInfo.editorToolbarHeight + layoutInfo.cellTopMargin}px`; templateData.focusIndicatorRight.style.transform = `translateY(${layoutInfo.editorToolbarHeight + layoutInfo.cellTopMargin}px)`;
} }
} else { } else {
templateData.container.classList.remove('cell-has-toolbar-actions'); templateData.container.classList.remove('cell-has-toolbar-actions');
if (isCodeCellRenderTemplate(templateData)) { if (isCodeCellRenderTemplate(templateData)) {
templateData.focusIndicatorLeft.style.top = `${layoutInfo.cellTopMargin}px`; templateData.focusIndicatorLeft.style.transform = `translateY(${layoutInfo.cellTopMargin}px)`;
templateData.focusIndicatorRight.style.top = `${layoutInfo.cellTopMargin}px`; templateData.focusIndicatorRight.style.transform = `translateY(${layoutInfo.cellTopMargin}px)`;
} }
} }
}; };
...@@ -436,7 +440,8 @@ export class MarkupCellRenderer extends AbstractCellRenderer implements IListRen ...@@ -436,7 +440,8 @@ export class MarkupCellRenderer extends AbstractCellRenderer implements IListRen
private updateForLayout(element: MarkupCellViewModel, templateData: MarkdownCellRenderTemplate): void { private updateForLayout(element: MarkupCellViewModel, templateData: MarkdownCellRenderTemplate): void {
const indicatorPostion = this.notebookEditor.notebookOptions.computeIndicatorPosition(element.layoutInfo.totalHeight, this.notebookEditor.textModel?.viewType); const indicatorPostion = this.notebookEditor.notebookOptions.computeIndicatorPosition(element.layoutInfo.totalHeight, this.notebookEditor.textModel?.viewType);
templateData.focusIndicatorBottom.style.top = `${indicatorPostion.bottomIndicatorTop}px`; templateData.focusIndicatorBottom.style.transform = `translateY(${indicatorPostion.bottomIndicatorTop}px)`;
templateData.focusIndicatorLeft.style.height = `${indicatorPostion.verticalIndicatorHeight}px`; templateData.focusIndicatorLeft.style.height = `${indicatorPostion.verticalIndicatorHeight}px`;
templateData.focusIndicatorRight.style.height = `${indicatorPostion.verticalIndicatorHeight}px`; templateData.focusIndicatorRight.style.height = `${indicatorPostion.verticalIndicatorHeight}px`;
...@@ -930,17 +935,19 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende ...@@ -930,17 +935,19 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
} }
private updateForLayout(element: CodeCellViewModel, templateData: CodeCellRenderTemplate): void { private updateForLayout(element: CodeCellViewModel, templateData: CodeCellRenderTemplate): void {
const layoutInfo = this.notebookEditor.notebookOptions.getLayoutConfiguration(); templateData.disposables.add(DOM.scheduleAtNextAnimationFrame(() => {
const bottomToolbarDimensions = this.notebookEditor.notebookOptions.computeBottomToolbarDimensions(this.notebookEditor.textModel?.viewType); const layoutInfo = this.notebookEditor.notebookOptions.getLayoutConfiguration();
const bottomToolbarDimensions = this.notebookEditor.notebookOptions.computeBottomToolbarDimensions(this.notebookEditor.textModel?.viewType);
templateData.focusIndicatorLeft.style.height = `${element.layoutInfo.indicatorHeight}px`; templateData.focusIndicatorLeft.style.height = `${element.layoutInfo.indicatorHeight}px`;
templateData.focusIndicatorRight.style.height = `${element.layoutInfo.indicatorHeight}px`; templateData.focusIndicatorRight.style.height = `${element.layoutInfo.indicatorHeight}px`;
templateData.focusIndicatorBottom.style.top = `${element.layoutInfo.totalHeight - bottomToolbarDimensions.bottomToolbarGap - layoutInfo.cellBottomMargin}px`; templateData.focusIndicatorBottom.style.top = `${element.layoutInfo.totalHeight - bottomToolbarDimensions.bottomToolbarGap - layoutInfo.cellBottomMargin}px`;
templateData.outputContainer.style.top = `${element.layoutInfo.outputContainerOffset}px`; templateData.outputContainer.style.top = `${element.layoutInfo.outputContainerOffset}px`;
templateData.outputShowMoreContainer.style.top = `${element.layoutInfo.outputShowMoreContainerOffset}px`; templateData.outputShowMoreContainer.style.top = `${element.layoutInfo.outputShowMoreContainerOffset}px`;
templateData.dragHandle.style.height = `${element.layoutInfo.totalHeight - bottomToolbarDimensions.bottomToolbarGap}px`; templateData.dragHandle.style.height = `${element.layoutInfo.totalHeight - bottomToolbarDimensions.bottomToolbarGap}px`;
templateData.container.classList.toggle('cell-statusbar-hidden', this.notebookEditor.notebookOptions.computeEditorStatusbarHeight(element.internalMetadata) === 0); templateData.container.classList.toggle('cell-statusbar-hidden', this.notebookEditor.notebookOptions.computeEditorStatusbarHeight(element.internalMetadata) === 0);
}));
} }
renderElement(element: CodeCellViewModel, index: number, templateData: CodeCellRenderTemplate, height: number | undefined): void { renderElement(element: CodeCellViewModel, index: number, templateData: CodeCellRenderTemplate, height: number | undefined): void {
......
...@@ -250,6 +250,10 @@ export class CodeCell extends Disposable { ...@@ -250,6 +250,10 @@ export class CodeCell extends Disposable {
this.viewCell.layoutChange({}); this.viewCell.layoutChange({});
} }
this._register(this.viewCell.onLayoutInfoRead(() => {
this._outputContainerRenderer.probeHeight();
}));
this.updateForCollapseState(); this.updateForCollapseState();
} }
......
...@@ -23,6 +23,8 @@ import { BaseCellViewModel } from './baseCellViewModel'; ...@@ -23,6 +23,8 @@ import { BaseCellViewModel } from './baseCellViewModel';
export class CodeCellViewModel extends BaseCellViewModel implements ICellViewModel { export class CodeCellViewModel extends BaseCellViewModel implements ICellViewModel {
readonly cellKind = CellKind.Code; readonly cellKind = CellKind.Code;
protected readonly _onLayoutInfoRead = this._register(new Emitter<void>());
readonly onLayoutInfoRead = this._onLayoutInfoRead.event;
protected readonly _onDidChangeOutputs = this._register(new Emitter<NotebookCellOutputsSplice>()); protected readonly _onDidChangeOutputs = this._register(new Emitter<NotebookCellOutputsSplice>());
readonly onDidChangeOutputs = this._onDidChangeOutputs.event; readonly onDidChangeOutputs = this._onDidChangeOutputs.event;
...@@ -285,6 +287,11 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod ...@@ -285,6 +287,11 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
return false; return false;
} }
getDynamicHeight() {
this._onLayoutInfoRead.fire();
return this._layoutInfo.totalHeight;
}
firstLine(): string { firstLine(): string {
return this.getText().split('\n')[0]; return this.getText().split('\n')[0];
} }
......
...@@ -250,6 +250,10 @@ export class MarkupCellViewModel extends BaseCellViewModel implements ICellViewM ...@@ -250,6 +250,10 @@ export class MarkupCellViewModel extends BaseCellViewModel implements ICellViewM
return false; return false;
} }
getDynamicHeight() {
return null;
}
getHeight(lineHeight: number) { getHeight(lineHeight: number) {
if (this._layoutInfo.layoutState === CellLayoutState.Uninitialized) { if (this._layoutInfo.layoutState === CellLayoutState.Uninitialized) {
return 100; return 100;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册