Path: blob/main/src/vs/workbench/contrib/notebook/browser/view/cellPart.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import * as DOM from '../../../../../base/browser/dom.js';6import { onUnexpectedError } from '../../../../../base/common/errors.js';7import { Disposable, DisposableStore, MutableDisposable } from '../../../../../base/common/lifecycle.js';8import { ICellViewModel } from '../notebookBrowser.js';9import { CellViewModelStateChangeEvent } from '../notebookViewEvents.js';10import { ICellExecutionStateChangedEvent } from '../../common/notebookExecutionStateService.js';1112/**13* A content part is a non-floating element that is rendered inside a cell.14* The rendering of the content part is synchronous to avoid flickering.15*/16export abstract class CellContentPart extends Disposable {17protected currentCell: ICellViewModel | undefined;18protected readonly cellDisposables = this._register(new DisposableStore());1920constructor() {21super();22}2324/**25* Prepare model for cell part rendering26* No DOM operations recommended within this operation27*/28prepareRenderCell(element: ICellViewModel): void { }2930/**31* Update the DOM for the cell `element`32*/33renderCell(element: ICellViewModel): void {34this.currentCell = element;35safeInvokeNoArg(() => this.didRenderCell(element));36}3738didRenderCell(element: ICellViewModel): void { }3940/**41* Dispose any disposables generated from `didRenderCell`42*/43unrenderCell(element: ICellViewModel): void {44this.currentCell = undefined;45this.cellDisposables.clear();46}4748/**49* Perform DOM read operations to prepare for the list/cell layout update.50*/51prepareLayout(): void { }5253/**54* Update internal DOM (top positions) per cell layout info change55* Note that a cell part doesn't need to call `DOM.scheduleNextFrame`,56* the list view will ensure that layout call is invoked in the right frame57*/58updateInternalLayoutNow(element: ICellViewModel): void { }5960/**61* Update per cell state change62*/63updateState(element: ICellViewModel, e: CellViewModelStateChangeEvent): void { }6465/**66* Update per execution state change.67*/68updateForExecutionState(element: ICellViewModel, e: ICellExecutionStateChangedEvent): void { }69}7071/**72* An overlay part renders on top of other components.73* The rendering of the overlay part might be postponed to the next animation frame to avoid forced reflow.74*/75export abstract class CellOverlayPart extends Disposable {76protected currentCell: ICellViewModel | undefined;77protected readonly cellDisposables = this._register(new DisposableStore());7879constructor() {80super();81}8283/**84* Prepare model for cell part rendering85* No DOM operations recommended within this operation86*/87prepareRenderCell(element: ICellViewModel): void { }8889/**90* Update the DOM for the cell `element`91*/92renderCell(element: ICellViewModel): void {93this.currentCell = element;94this.didRenderCell(element);95}9697didRenderCell(element: ICellViewModel): void { }9899/**100* Dispose any disposables generated from `didRenderCell`101*/102unrenderCell(element: ICellViewModel): void {103this.currentCell = undefined;104this.cellDisposables.clear();105}106107/**108* Update internal DOM (top positions) per cell layout info change109* Note that a cell part doesn't need to call `DOM.scheduleNextFrame`,110* the list view will ensure that layout call is invoked in the right frame111*/112updateInternalLayoutNow(element: ICellViewModel): void { }113114/**115* Update per cell state change116*/117updateState(element: ICellViewModel, e: CellViewModelStateChangeEvent): void { }118119/**120* Update per execution state change.121*/122updateForExecutionState(element: ICellViewModel, e: ICellExecutionStateChangedEvent): void { }123}124125function safeInvokeNoArg<T>(func: () => T): T | null {126try {127return func();128} catch (e) {129onUnexpectedError(e);130return null;131}132}133134export class CellPartsCollection extends Disposable {135private readonly _scheduledOverlayRendering = this._register(new MutableDisposable());136private readonly _scheduledOverlayUpdateState = this._register(new MutableDisposable());137private readonly _scheduledOverlayUpdateExecutionState = this._register(new MutableDisposable());138139constructor(140private readonly targetWindow: Window,141private readonly contentParts: readonly CellContentPart[],142private readonly overlayParts: readonly CellOverlayPart[]143) {144super();145}146147concatContentPart(other: readonly CellContentPart[], targetWindow: Window): CellPartsCollection {148return new CellPartsCollection(targetWindow, this.contentParts.concat(other), this.overlayParts);149}150151concatOverlayPart(other: readonly CellOverlayPart[], targetWindow: Window): CellPartsCollection {152return new CellPartsCollection(targetWindow, this.contentParts, this.overlayParts.concat(other));153}154155scheduleRenderCell(element: ICellViewModel): void {156// prepare model157for (const part of this.contentParts) {158safeInvokeNoArg(() => part.prepareRenderCell(element));159}160161for (const part of this.overlayParts) {162safeInvokeNoArg(() => part.prepareRenderCell(element));163}164165// render content parts166for (const part of this.contentParts) {167safeInvokeNoArg(() => part.renderCell(element));168}169170this._scheduledOverlayRendering.value = DOM.modify(this.targetWindow, () => {171for (const part of this.overlayParts) {172safeInvokeNoArg(() => part.renderCell(element));173}174});175}176177unrenderCell(element: ICellViewModel): void {178for (const part of this.contentParts) {179safeInvokeNoArg(() => part.unrenderCell(element));180}181182this._scheduledOverlayRendering.value = undefined;183this._scheduledOverlayUpdateState.value = undefined;184this._scheduledOverlayUpdateExecutionState.value = undefined;185186for (const part of this.overlayParts) {187safeInvokeNoArg(() => part.unrenderCell(element));188}189}190191updateInternalLayoutNow(viewCell: ICellViewModel) {192for (const part of this.contentParts) {193safeInvokeNoArg(() => part.updateInternalLayoutNow(viewCell));194}195196for (const part of this.overlayParts) {197safeInvokeNoArg(() => part.updateInternalLayoutNow(viewCell));198}199}200201prepareLayout() {202for (const part of this.contentParts) {203safeInvokeNoArg(() => part.prepareLayout());204}205}206207updateState(viewCell: ICellViewModel, e: CellViewModelStateChangeEvent) {208for (const part of this.contentParts) {209safeInvokeNoArg(() => part.updateState(viewCell, e));210}211212this._scheduledOverlayUpdateState.value = DOM.modify(this.targetWindow, () => {213for (const part of this.overlayParts) {214safeInvokeNoArg(() => part.updateState(viewCell, e));215}216});217}218219updateForExecutionState(viewCell: ICellViewModel, e: ICellExecutionStateChangedEvent) {220for (const part of this.contentParts) {221safeInvokeNoArg(() => part.updateForExecutionState(viewCell, e));222}223224this._scheduledOverlayUpdateExecutionState.value = DOM.modify(this.targetWindow, () => {225for (const part of this.overlayParts) {226safeInvokeNoArg(() => part.updateForExecutionState(viewCell, e));227}228});229}230}231232233