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

fix #130790.

上级 d3aefe7f
...@@ -64,7 +64,7 @@ export class CellOutputElement extends Disposable { ...@@ -64,7 +64,7 @@ export class CellOutputElement extends Disposable {
private readonly _renderDisposableStore = this._register(new DisposableStore()); private readonly _renderDisposableStore = this._register(new DisposableStore());
private readonly _actionsDisposable = this._register(new MutableDisposable()); private readonly _actionsDisposable = this._register(new MutableDisposable());
innerContainer!: HTMLElement; innerContainer?: HTMLElement;
renderedOutputContainer!: HTMLElement; renderedOutputContainer!: HTMLElement;
renderResult?: IRenderOutput; renderResult?: IRenderOutput;
...@@ -74,7 +74,7 @@ export class CellOutputElement extends Disposable { ...@@ -74,7 +74,7 @@ export class CellOutputElement extends Disposable {
get domOffsetHeight() { get domOffsetHeight() {
if (this.useDedicatedDOM) { if (this.useDedicatedDOM) {
if (this._height === -1) { if (this._height === -1) {
return this.innerContainer.offsetHeight; return this.innerContainer?.offsetHeight ?? 0;
} else { } else {
return this._height; return this._height;
} }
...@@ -88,6 +88,7 @@ export class CellOutputElement extends Disposable { ...@@ -88,6 +88,7 @@ export class CellOutputElement extends Disposable {
constructor( constructor(
private notebookEditor: INotebookEditorDelegate, private notebookEditor: INotebookEditorDelegate,
private viewCell: CodeCellViewModel, private viewCell: CodeCellViewModel,
private cellOutputContainer: CellOutputContainer,
private outputContainer: FastDomNode<HTMLElement>, private outputContainer: FastDomNode<HTMLElement>,
readonly output: ICellOutputViewModel, readonly output: ICellOutputViewModel,
@INotebookService private readonly notebookService: INotebookService, @INotebookService private readonly notebookService: INotebookService,
...@@ -147,7 +148,18 @@ export class CellOutputElement extends Disposable { ...@@ -147,7 +148,18 @@ export class CellOutputElement extends Disposable {
updateOutputData() { updateOutputData() {
// update the content inside the domNode, do not need to worry about streaming // update the content inside the domNode, do not need to worry about streaming
if (!this.innerContainer) { if (!this.innerContainer) {
return; if (this.renderResult) {
return;
} else {
// init rendering didn't happen
const currOutputIndex = this.cellOutputContainer.renderedOutputEntries.findIndex(entry => entry.element === this);
const previousSibling = currOutputIndex > 0 && !!(this.cellOutputContainer.renderedOutputEntries[currOutputIndex - 1].element.innerContainer?.parentElement)
? this.cellOutputContainer.renderedOutputEntries[currOutputIndex - 1].element.innerContainer
: undefined;
this.render(previousSibling);
this._relayoutCell();
return;
}
} }
// user chooses another mimetype // user chooses another mimetype
...@@ -165,8 +177,8 @@ export class CellOutputElement extends Disposable { ...@@ -165,8 +177,8 @@ export class CellOutputElement extends Disposable {
} }
// insert after previousSibling // insert after previousSibling
private _generateInnerOutputContainer(previousSibling: HTMLElement | undefined, pickedMimeTypeRenderer: IOrderedMimeType) { private _generateInnerOutputContainer(previousSibling: HTMLElement | undefined, pickedMimeTypeRenderer: IOrderedMimeType, forceBreakStreaming: boolean) {
if (this.output.supportAppend()) { if (this.output.supportAppend() && !forceBreakStreaming) {
// current output support append // current output support append
if (previousSibling) { if (previousSibling) {
if (this._divSupportAppend(previousSibling as HTMLElement | null, pickedMimeTypeRenderer.mimeType)) { if (this._divSupportAppend(previousSibling as HTMLElement | null, pickedMimeTypeRenderer.mimeType)) {
...@@ -205,6 +217,7 @@ export class CellOutputElement extends Disposable { ...@@ -205,6 +217,7 @@ export class CellOutputElement extends Disposable {
} }
this.innerContainer.setAttribute('output-mime-type', pickedMimeTypeRenderer.mimeType); this.innerContainer.setAttribute('output-mime-type', pickedMimeTypeRenderer.mimeType);
return this.innerContainer;
} }
private _initHeightChecked = false; private _initHeightChecked = false;
...@@ -217,7 +230,7 @@ export class CellOutputElement extends Disposable { ...@@ -217,7 +230,7 @@ export class CellOutputElement extends Disposable {
} }
} }
render(previousSibling?: HTMLElement): IRenderResult | undefined { render(previousSibling: HTMLElement | undefined, forceBreakStreaming: boolean = false): IRenderResult | undefined {
const index = this.viewCell.outputsViewModels.indexOf(this.output); const index = this.viewCell.outputsViewModels.indexOf(this.output);
if (this.viewCell.metadata.outputCollapsed || !this.notebookEditor.hasModel()) { if (this.viewCell.metadata.outputCollapsed || !this.notebookEditor.hasModel()) {
...@@ -241,10 +254,10 @@ export class CellOutputElement extends Disposable { ...@@ -241,10 +254,10 @@ export class CellOutputElement extends Disposable {
const pickedMimeTypeRenderer = mimeTypes[pick]; const pickedMimeTypeRenderer = mimeTypes[pick];
// generate an innerOutputContainer only when needed, for text streaming, it will reuse the previous element's container // generate an innerOutputContainer only when needed, for text streaming, it will reuse the previous element's container
this._generateInnerOutputContainer(previousSibling, pickedMimeTypeRenderer); const innerContainer = this._generateInnerOutputContainer(previousSibling, pickedMimeTypeRenderer, forceBreakStreaming);
this._attachToolbar(this.innerContainer, notebookTextModel, this.notebookEditor.activeKernel, index, mimeTypes); this._attachToolbar(innerContainer, notebookTextModel, this.notebookEditor.activeKernel, index, mimeTypes);
this.renderedOutputContainer = DOM.append(this.innerContainer, DOM.$('.rendered-output')); this.renderedOutputContainer = DOM.append(innerContainer, DOM.$('.rendered-output'));
if (pickedMimeTypeRenderer.rendererId !== BUILTIN_RENDERER_ID) { if (pickedMimeTypeRenderer.rendererId !== BUILTIN_RENDERER_ID) {
const renderer = this.notebookService.getRendererInfo(pickedMimeTypeRenderer.rendererId); const renderer = this.notebookService.getRendererInfo(pickedMimeTypeRenderer.rendererId);
...@@ -264,10 +277,10 @@ export class CellOutputElement extends Disposable { ...@@ -264,10 +277,10 @@ export class CellOutputElement extends Disposable {
if (this.renderResult.type !== RenderOutputType.Mainframe) { if (this.renderResult.type !== RenderOutputType.Mainframe) {
this.notebookEditor.createOutput(this.viewCell, this.renderResult, this.viewCell.getOutputOffset(index)); this.notebookEditor.createOutput(this.viewCell, this.renderResult, this.viewCell.getOutputOffset(index));
this.innerContainer.classList.add('background'); innerContainer.classList.add('background');
} else { } else {
this.innerContainer.classList.add('foreground', 'output-element'); innerContainer.classList.add('foreground', 'output-element');
this.innerContainer.style.position = 'absolute'; innerContainer.style.position = 'absolute';
} }
if (this.renderResult.type === RenderOutputType.Html || this.renderResult.type === RenderOutputType.Extension) { if (this.renderResult.type === RenderOutputType.Html || this.renderResult.type === RenderOutputType.Extension) {
...@@ -302,15 +315,15 @@ export class CellOutputElement extends Disposable { ...@@ -302,15 +315,15 @@ export class CellOutputElement extends Disposable {
}; };
// let's use resize listener for them // let's use resize listener for them
this._bindResizeListener(dimension); this._bindResizeListener(innerContainer, 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);
this.innerContainer.style.top = `${top}px`; innerContainer.style.top = `${top}px`;
return { initRenderIsSynchronous: true }; return { initRenderIsSynchronous: true };
} }
private _bindResizeListener(dimension: DOM.IDimension) { private _bindResizeListener(innerContainer: HTMLElement, dimension: DOM.IDimension) {
const elementSizeObserver = getResizesObserver(this.innerContainer, dimension, () => { const elementSizeObserver = getResizesObserver(innerContainer, dimension, () => {
if (this.outputContainer && document.body.contains(this.outputContainer.domNode)) { if (this.outputContainer && document.body.contains(this.outputContainer.domNode)) {
const height = elementSizeObserver.getHeight() + OutputInnerContainerTopPadding * 2; const height = elementSizeObserver.getHeight() + OutputInnerContainerTopPadding * 2;
...@@ -378,7 +391,7 @@ export class CellOutputElement extends Disposable { ...@@ -378,7 +391,7 @@ export class CellOutputElement extends Disposable {
// TODO: This could probably be a real registered action, but it has to talk to this output element // TODO: This could probably be a real registered action, but it has to talk to this output element
const pickAction = new Action('notebook.output.pickMimetype', nls.localize('pickMimeType', "Choose Output Mimetype"), ThemeIcon.asClassName(mimetypeIcon), undefined, const pickAction = new Action('notebook.output.pickMimetype', nls.localize('pickMimeType', "Choose Output Mimetype"), ThemeIcon.asClassName(mimetypeIcon), undefined,
async _context => this._pickActiveMimeTypeRenderer(notebookTextModel, kernel, this.output)); async _context => this._pickActiveMimeTypeRenderer(outputItemDiv, notebookTextModel, kernel, this.output));
if (index === 0 && useConsolidatedButton) { if (index === 0 && useConsolidatedButton) {
const menu = this._renderDisposableStore.add(this.menuService.createMenu(MenuId.NotebookOutputToolbar, this.contextKeyService)); const menu = this._renderDisposableStore.add(this.menuService.createMenu(MenuId.NotebookOutputToolbar, this.contextKeyService));
const updateMenuToolbar = () => { const updateMenuToolbar = () => {
...@@ -396,7 +409,7 @@ export class CellOutputElement extends Disposable { ...@@ -396,7 +409,7 @@ export class CellOutputElement extends Disposable {
} }
} }
private async _pickActiveMimeTypeRenderer(notebookTextModel: NotebookTextModel, kernel: INotebookKernel | undefined, viewModel: ICellOutputViewModel) { private async _pickActiveMimeTypeRenderer(outputItemDiv: HTMLElement, notebookTextModel: NotebookTextModel, kernel: INotebookKernel | undefined, viewModel: ICellOutputViewModel) {
const [mimeTypes, currIndex] = viewModel.resolveMimeTypes(notebookTextModel, kernel?.preloadProvides); const [mimeTypes, currIndex] = viewModel.resolveMimeTypes(notebookTextModel, kernel?.preloadProvides);
const items: IMimeTypeRenderer[] = []; const items: IMimeTypeRenderer[] = [];
...@@ -454,7 +467,7 @@ export class CellOutputElement extends Disposable { ...@@ -454,7 +467,7 @@ export class CellOutputElement extends Disposable {
} }
// user chooses another mimetype // user chooses another mimetype
const nextElement = this.innerContainer.nextElementSibling; const nextElement = outputItemDiv.nextElementSibling;
this._renderDisposableStore.clear(); this._renderDisposableStore.clear();
const element = this.innerContainer; const element = this.innerContainer;
if (element) { if (element) {
...@@ -590,9 +603,9 @@ export class CellOutputContainer extends Disposable { ...@@ -590,9 +603,9 @@ export class CellOutputContainer extends Disposable {
DOM.show(this.templateData.outputContainer.domNode); DOM.show(this.templateData.outputContainer.domNode);
for (let index = 0; index < Math.min(this.options.limit, this.viewCell.outputsViewModels.length); index++) { for (let index = 0; index < Math.min(this.options.limit, this.viewCell.outputsViewModels.length); index++) {
const currOutput = this.viewCell.outputsViewModels[index]; const currOutput = this.viewCell.outputsViewModels[index];
const entry = this.instantiationService.createInstance(CellOutputElement, this.notebookEditor, this.viewCell, this.templateData.outputContainer, currOutput); const entry = this.instantiationService.createInstance(CellOutputElement, this.notebookEditor, this.viewCell, this, this.templateData.outputContainer, currOutput);
this._outputEntries.push(new OutputEntryViewHandler(currOutput, entry)); this._outputEntries.push(new OutputEntryViewHandler(currOutput, entry));
entry.render(); entry.render(undefined);
} }
this.viewCell.editorHeight = editorHeight; this.viewCell.editorHeight = editorHeight;
...@@ -630,7 +643,7 @@ export class CellOutputContainer extends Disposable { ...@@ -630,7 +643,7 @@ export class CellOutputContainer extends Disposable {
this.viewCell.updateOutputHeight(index, outputEntry.domOffsetHeight, 'CellOutputContainer#viewUpdateShowOutputs'); this.viewCell.updateOutputHeight(index, outputEntry.domOffsetHeight, 'CellOutputContainer#viewUpdateShowOutputs');
} }
} else { } else {
outputEntry.render(); outputEntry.render(undefined);
} }
} }
...@@ -702,14 +715,14 @@ export class CellOutputContainer extends Disposable { ...@@ -702,14 +715,14 @@ export class CellOutputContainer extends Disposable {
newlyInserted = newlyInserted.slice(0, this.options.limit - firstGroupEntries.length); newlyInserted = newlyInserted.slice(0, this.options.limit - firstGroupEntries.length);
const newlyInsertedEntries = newlyInserted.map(insert => { const newlyInsertedEntries = newlyInserted.map(insert => {
return new OutputEntryViewHandler(insert, this.instantiationService.createInstance(CellOutputElement, this.notebookEditor, this.viewCell, this.templateData.outputContainer, insert)); return new OutputEntryViewHandler(insert, this.instantiationService.createInstance(CellOutputElement, this.notebookEditor, this.viewCell, this, this.templateData.outputContainer, insert));
}); });
this._outputEntries = [...firstGroupEntries, ...newlyInsertedEntries]; this._outputEntries = [...firstGroupEntries, ...newlyInsertedEntries];
// render newly inserted outputs // render newly inserted outputs
for (let i = firstGroupEntries.length; i < this._outputEntries.length; i++) { for (let i = firstGroupEntries.length; i < this._outputEntries.length; i++) {
const renderResult = this._outputEntries[i].element.render(); const renderResult = this._outputEntries[i].element.render(undefined, i >= 1 && !this._outputEntries[i - 1].element.innerContainer);
if (renderResult) { if (renderResult) {
outputHasDynamicHeight = outputHasDynamicHeight || !renderResult.initRenderIsSynchronous; outputHasDynamicHeight = outputHasDynamicHeight || !renderResult.initRenderIsSynchronous;
} }
...@@ -731,7 +744,7 @@ export class CellOutputContainer extends Disposable { ...@@ -731,7 +744,7 @@ export class CellOutputContainer extends Disposable {
if (!entry.element.useDedicatedDOM) { if (!entry.element.useDedicatedDOM) {
entry.element.detach(); entry.element.detach();
entry.element.dispose(); entry.element.dispose();
secondGroupEntries[j] = new OutputEntryViewHandler(entry.model, this.instantiationService.createInstance(CellOutputElement, this.notebookEditor, this.viewCell, this.templateData.outputContainer, entry.model)); secondGroupEntries[j] = new OutputEntryViewHandler(entry.model, this.instantiationService.createInstance(CellOutputElement, this.notebookEditor, this.viewCell, this, this.templateData.outputContainer, entry.model));
reRenderRightBoundary++; reRenderRightBoundary++;
} else { } else {
break; break;
...@@ -739,14 +752,14 @@ export class CellOutputContainer extends Disposable { ...@@ -739,14 +752,14 @@ export class CellOutputContainer extends Disposable {
} }
const newlyInsertedEntries = newlyInserted.map(insert => { const newlyInsertedEntries = newlyInserted.map(insert => {
return new OutputEntryViewHandler(insert, this.instantiationService.createInstance(CellOutputElement, this.notebookEditor, this.viewCell, this.templateData.outputContainer, insert)); return new OutputEntryViewHandler(insert, this.instantiationService.createInstance(CellOutputElement, this.notebookEditor, this.viewCell, this, this.templateData.outputContainer, insert));
}); });
this._outputEntries = [...firstGroupEntries, ...newlyInsertedEntries, ...secondGroupEntries.slice(0, this.options.limit - firstGroupEntries.length - newlyInserted.length)]; this._outputEntries = [...firstGroupEntries, ...newlyInsertedEntries, ...secondGroupEntries.slice(0, this.options.limit - firstGroupEntries.length - newlyInserted.length)];
for (let i = firstGroupEntries.length; i < reRenderRightBoundary; i++) { for (let i = firstGroupEntries.length; i < reRenderRightBoundary; i++) {
const previousSibling = i - 1 >= 0 && this._outputEntries[i - 1] && this._outputEntries[i - 1].element.innerContainer.parentElement !== null ? this._outputEntries[i - 1].element.innerContainer : undefined; const previousSibling = i - 1 >= 0 && this._outputEntries[i - 1] && !!(this._outputEntries[i - 1].element.innerContainer?.parentElement) ? this._outputEntries[i - 1].element.innerContainer : undefined;
const renderResult = this._outputEntries[i].element.render(previousSibling); const renderResult = this._outputEntries[i].element.render(previousSibling, i >= 1 && !this._outputEntries[i - 1].element.innerContainer);
if (renderResult) { if (renderResult) {
outputHasDynamicHeight = outputHasDynamicHeight || !renderResult.initRenderIsSynchronous; outputHasDynamicHeight = outputHasDynamicHeight || !renderResult.initRenderIsSynchronous;
} }
...@@ -766,7 +779,7 @@ export class CellOutputContainer extends Disposable { ...@@ -766,7 +779,7 @@ export class CellOutputContainer extends Disposable {
if (!entry.element.useDedicatedDOM) { if (!entry.element.useDedicatedDOM) {
entry.element.detach(); entry.element.detach();
entry.element.dispose(); entry.element.dispose();
secondGroupEntries[j] = new OutputEntryViewHandler(entry.model, this.instantiationService.createInstance(CellOutputElement, this.notebookEditor, this.viewCell, this.templateData.outputContainer, entry.model)); secondGroupEntries[j] = new OutputEntryViewHandler(entry.model, this.instantiationService.createInstance(CellOutputElement, this.notebookEditor, this.viewCell, this, this.templateData.outputContainer, entry.model));
reRenderRightBoundary++; reRenderRightBoundary++;
} else { } else {
break; break;
...@@ -774,7 +787,7 @@ export class CellOutputContainer extends Disposable { ...@@ -774,7 +787,7 @@ export class CellOutputContainer extends Disposable {
} }
const newlyInsertedEntries = newlyInserted.map(insert => { const newlyInsertedEntries = newlyInserted.map(insert => {
return new OutputEntryViewHandler(insert, this.instantiationService.createInstance(CellOutputElement, this.notebookEditor, this.viewCell, this.templateData.outputContainer, insert)); return new OutputEntryViewHandler(insert, this.instantiationService.createInstance(CellOutputElement, this.notebookEditor, this.viewCell, this, this.templateData.outputContainer, insert));
}); });
let outputsNewlyAvailable: OutputEntryViewHandler[] = []; let outputsNewlyAvailable: OutputEntryViewHandler[] = [];
...@@ -782,7 +795,7 @@ export class CellOutputContainer extends Disposable { ...@@ -782,7 +795,7 @@ export class CellOutputContainer extends Disposable {
if (firstGroupEntries.length + newlyInsertedEntries.length + secondGroupEntries.length < this.viewCell.outputsViewModels.length) { if (firstGroupEntries.length + newlyInsertedEntries.length + secondGroupEntries.length < this.viewCell.outputsViewModels.length) {
const last = Math.min(this.options.limit, this.viewCell.outputsViewModels.length); const last = Math.min(this.options.limit, this.viewCell.outputsViewModels.length);
outputsNewlyAvailable = this.viewCell.outputsViewModels.slice(firstGroupEntries.length + newlyInsertedEntries.length + secondGroupEntries.length, last).map(output => { outputsNewlyAvailable = this.viewCell.outputsViewModels.slice(firstGroupEntries.length + newlyInsertedEntries.length + secondGroupEntries.length, last).map(output => {
return new OutputEntryViewHandler(output, this.instantiationService.createInstance(CellOutputElement, this.notebookEditor, this.viewCell, this.templateData.outputContainer, output)); return new OutputEntryViewHandler(output, this.instantiationService.createInstance(CellOutputElement, this.notebookEditor, this.viewCell, this, this.templateData.outputContainer, output));
}); });
} }
...@@ -798,15 +811,15 @@ export class CellOutputContainer extends Disposable { ...@@ -798,15 +811,15 @@ export class CellOutputContainer extends Disposable {
// } // }
// } else { // } else {
for (let i = firstGroupEntries.length; i < reRenderRightBoundary; i++) { for (let i = firstGroupEntries.length; i < reRenderRightBoundary; i++) {
const previousSibling = i - 1 >= 0 && this._outputEntries[i - 1] && this._outputEntries[i - 1].element.innerContainer.parentElement !== null ? this._outputEntries[i - 1].element.innerContainer : undefined; const previousSibling = i - 1 >= 0 && this._outputEntries[i - 1] && !!(this._outputEntries[i - 1].element.innerContainer?.parentElement) ? this._outputEntries[i - 1].element.innerContainer : undefined;
const renderResult = this._outputEntries[i].element.render(previousSibling); const renderResult = this._outputEntries[i].element.render(previousSibling, i >= 1 && !this._outputEntries[i - 1].element.innerContainer);
if (renderResult) { if (renderResult) {
outputHasDynamicHeight = outputHasDynamicHeight || !renderResult.initRenderIsSynchronous; outputHasDynamicHeight = outputHasDynamicHeight || !renderResult.initRenderIsSynchronous;
} }
} }
for (let i = 0; i < outputsNewlyAvailable.length; i++) { for (let i = 0; i < outputsNewlyAvailable.length; i++) {
const renderResult = this._outputEntries[firstGroupEntries.length + newlyInserted.length + secondGroupEntries.length + i].element.render(); const renderResult = this._outputEntries[firstGroupEntries.length + newlyInserted.length + secondGroupEntries.length + i].element.render(undefined);
if (renderResult) { if (renderResult) {
outputHasDynamicHeight = outputHasDynamicHeight || !renderResult.initRenderIsSynchronous; outputHasDynamicHeight = outputHasDynamicHeight || !renderResult.initRenderIsSynchronous;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册