diff --git a/core/block.ts b/core/block.ts index 1ac77cd5492..9e345e1d8e1 100644 --- a/core/block.ts +++ b/core/block.ts @@ -221,9 +221,7 @@ export class Block implements IASTNodeLocation, IDeletable { type!: string; // Record initial inline state. inputsInlineDefault?: boolean; - // Setting this to null indicates that the block has been disposed. Must be - // nullable. - workspace: Workspace|null; + workspace: Workspace; /** * @param workspace The block's workspace. @@ -317,7 +315,7 @@ export class Block implements IASTNodeLocation, IDeletable { * @suppress {checkTypes} */ dispose(healStack: boolean) { - if (!this.workspace) { + if (this.disposed) { // Already deleted. return; } @@ -335,13 +333,10 @@ export class Block implements IASTNodeLocation, IDeletable { try { // This block is now at the top of the workspace. // Remove this block from the workspace's list of top-most blocks. - if (this.workspace) { - this.workspace.removeTopBlock(this); - this.workspace.removeTypedBlock(this); - // Remove from block database. - this.workspace.removeBlockById(this.id); - this.workspace = null; - } + this.workspace.removeTopBlock(this); + this.workspace.removeTypedBlock(this); + // Remove from block database. + this.workspace.removeBlockById(this.id); // First, dispose of all my children. for (let i = this.childBlocks_.length - 1; i >= 0; i--) { @@ -428,7 +423,7 @@ export class Block implements IASTNodeLocation, IDeletable { // Disconnect the child block. childConnection?.disconnect(); // Connect child to the parent if possible, otherwise bump away. - if (this.workspace!.connectionChecker.canConnect( + if (this.workspace.connectionChecker.canConnect( childConnection, parentConnection, false)) { parentConnection.connect(childConnection!); } else { @@ -481,7 +476,7 @@ export class Block implements IASTNodeLocation, IDeletable { const nextTarget = this.nextConnection.targetConnection; nextTarget?.disconnect(); if (previousTarget && - this.workspace!.connectionChecker.canConnect( + this.workspace.connectionChecker.canConnect( previousTarget, nextTarget, false)) { // Attach the next statement to the previous statement. previousTarget.connect(nextTarget!); @@ -721,7 +716,7 @@ export class Block implements IASTNodeLocation, IDeletable { } else { // New parent must be non-null so remove this block from the workspace's // list of top-most blocks. - this.workspace!.removeTopBlock(this); + this.workspace.removeTopBlock(this); } this.parentBlock_ = newParent; @@ -729,7 +724,7 @@ export class Block implements IASTNodeLocation, IDeletable { // Add this block to the new parent's child list. newParent.childBlocks_.push(this); } else { - this.workspace!.addTopBlock(this); + this.workspace.addTopBlock(this); } } @@ -759,8 +754,8 @@ export class Block implements IASTNodeLocation, IDeletable { * @return True if deletable. */ isDeletable(): boolean { - return this.deletable_ && !this.isShadow_ && - !(this.workspace && this.workspace.options.readOnly); + return this.deletable_ && !this.isShadow_ && !this.disposed && + !this.workspace.options.readOnly; } /** @@ -776,8 +771,8 @@ export class Block implements IASTNodeLocation, IDeletable { * @return True if movable. */ isMovable(): boolean { - return this.movable_ && !this.isShadow_ && - !(this.workspace && this.workspace.options.readOnly); + return this.movable_ && !this.isShadow_ && !this.disposed && + !this.workspace.options.readOnly; } /** @@ -796,10 +791,10 @@ export class Block implements IASTNodeLocation, IDeletable { * @return True if duplicatable. */ isDuplicatable(): boolean { - if (!this.workspace!.hasBlockLimits()) { + if (!this.workspace.hasBlockLimits()) { return true; } - return this.workspace!.isCapacityAvailable( + return this.workspace.isCapacityAvailable( common.getBlockTypeCounts(this, true)); } @@ -843,8 +838,7 @@ export class Block implements IASTNodeLocation, IDeletable { * @return True if editable. */ isEditable(): boolean { - return this.editable_ && - !(this.workspace && this.workspace.options.readOnly); + return this.editable_ && !this.disposed && !this.workspace.options.readOnly; } /** @@ -974,11 +968,11 @@ export class Block implements IASTNodeLocation, IDeletable { throw Error('onchange must be a function.'); } if (this.onchangeWrapper_) { - this.workspace!.removeChangeListener(this.onchangeWrapper_); + this.workspace.removeChangeListener(this.onchangeWrapper_); } this.onchange = onchangeFn; this.onchangeWrapper_ = onchangeFn.bind(this); - this.workspace!.addChangeListener(this.onchangeWrapper_); + this.workspace.addChangeListener(this.onchangeWrapper_); } /** @@ -1031,7 +1025,7 @@ export class Block implements IASTNodeLocation, IDeletable { for (let j = 0, field; field = input.fieldRow[j]; j++) { if (field.referencesVariables()) { const model = - this.workspace!.getVariableById(field.getValue() as string); + this.workspace.getVariableById(field.getValue() as string); // Check if the variable actually exists (and isn't just a potential // variable). if (model) { diff --git a/core/block_animations.ts b/core/block_animations.ts index a999ee745bf..104ef0b38ee 100644 --- a/core/block_animations.ts +++ b/core/block_animations.ts @@ -42,7 +42,7 @@ let disconnectGroup: Element = null as AnyDuringMigration; * @internal */ export function disposeUiEffect(block: BlockSvg) { - const workspace = block.workspace!; + const workspace = block.workspace; const svgGroup = block.getSvgRoot(); workspace.getAudioManager().play('delete'); @@ -100,7 +100,7 @@ function disposeUiStep( * @internal */ export function connectionUiEffect(block: BlockSvg) { - const workspace = block.workspace!; + const workspace = block.workspace; const scale = workspace.scale; workspace.getAudioManager().play('click'); if (scale < 1) { @@ -157,8 +157,8 @@ function connectionUiStep(ripple: SVGElement, start: Date, scale: number) { * @internal */ export function disconnectUiEffect(block: BlockSvg) { - block.workspace!.getAudioManager().play('disconnect'); - if (block.workspace!.scale < 1) { + block.workspace.getAudioManager().play('disconnect'); + if (block.workspace.scale < 1) { return; // Too small to care about visual effects. } // Horizontal distance for bottom of block to wiggle. diff --git a/core/block_dragger.ts b/core/block_dragger.ts index 9ce8b6b9eb8..c540fd2a8a3 100644 --- a/core/block_dragger.ts +++ b/core/block_dragger.ts @@ -242,7 +242,7 @@ export class BlockDragger implements IBlockDragger { // Blocks dragged directly from a flyout may need to be bumped into // bounds. bumpObjects.bumpIntoBounds( - this.draggingBlock_.workspace!, + this.draggingBlock_.workspace, this.workspace_.getMetricsManager().getScrollMetrics(true), this.draggingBlock_); } diff --git a/core/block_svg.ts b/core/block_svg.ts index aac747b717e..e937c42a3d9 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -144,7 +144,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, /** Whether mousedown events have been bound yet. */ private eventsInit_ = false; - override workspace: WorkspaceSvg|null; + override workspace: WorkspaceSvg; // TODO(b/109816955): remove '!', see go/strict-prop-init-fix. override outputConnection!: RenderedConnection; // TODO(b/109816955): remove '!', see go/strict-prop-init-fix. @@ -223,7 +223,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, * May be called more than once. */ initSvg() { - if (!this.workspace!.rendered) { + if (!this.workspace.rendered) { throw TypeError('Workspace is headless.'); } for (let i = 0, input; input = this.inputList[i]; i++) { @@ -236,13 +236,13 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, this.applyColour(); this.pathObject.updateMovable(this.isMovable()); const svg = this.getSvgRoot(); - if (!this.workspace!.options.readOnly && !this.eventsInit_ && svg) { + if (!this.workspace.options.readOnly && !this.eventsInit_ && svg) { browserEvents.conditionalBind(svg, 'mousedown', this, this.onMouseDown_); } this.eventsInit_ = true; if (!svg.parentNode) { - this.workspace!.getCanvas().appendChild(svg); + this.workspace.getCanvas().appendChild(svg); } } @@ -287,7 +287,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, } } const event = new (eventUtils.get(eventUtils.SELECTED))! - (oldId, this.id, this.workspace!.id); + (oldId, this.id, this.workspace.id); eventUtils.fire(event); common.setSelected(this); this.addSelect(); @@ -302,8 +302,8 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, return; } const event = new (eventUtils.get(eventUtils.SELECTED))! - (this.id, null, this.workspace!.id); - event.workspaceId = this.workspace!.id; + (this.id, null, this.workspace.id); + event.workspaceId = this.workspace.id; eventUtils.fire(event); common.setSelected(null); this.removeSelect(); @@ -348,7 +348,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, // Bail early if workspace is clearing, or we aren't rendered. // We won't need to reattach ourselves anywhere. - if (this.workspace!.isClearing || !svgRoot) { + if (this.workspace.isClearing || !svgRoot) { return; } @@ -361,7 +361,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, } else if (oldParent) { // If we are losing a parent, we want to move our DOM element to the // root of the workspace. - this.workspace!.getCanvas().appendChild(svgRoot); + this.workspace.getCanvas().appendChild(svgRoot); this.translate(oldXY.x, oldXY.y); } @@ -381,7 +381,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, let y = 0; const dragSurfaceGroup = this.useDragSurface_ ? - this.workspace!.getBlockDragSurface()!.getGroup() : + this.workspace.getBlockDragSurface()!.getGroup() : null; let element: SVGElement = this.getSvgRoot(); @@ -394,15 +394,15 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, // If this element is the current element on the drag surface, include // the translation of the drag surface itself. if (this.useDragSurface_ && - this.workspace!.getBlockDragSurface()!.getCurrentBlock() === + this.workspace.getBlockDragSurface()!.getCurrentBlock() === element) { const surfaceTranslation = - this.workspace!.getBlockDragSurface()!.getSurfaceTranslation(); + this.workspace.getBlockDragSurface()!.getSurfaceTranslation(); x += surfaceTranslation.x; y += surfaceTranslation.y; } element = element.parentNode as SVGElement; - } while (element && element !== this.workspace!.getCanvas() && + } while (element && element !== this.workspace.getCanvas() && element !== dragSurfaceGroup); } return new Coordinate(x, y); @@ -429,7 +429,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, event!.recordNew(); eventUtils.fire(event); } - this.workspace!.resizeContents(); + this.workspace.resizeContents(); } /** @@ -459,11 +459,11 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, // This is in workspace coordinates. const xy = this.getRelativeToSurfaceXY(); this.clearTransformAttributes_(); - this.workspace!.getBlockDragSurface()!.translateSurface(xy.x, xy.y); + this.workspace.getBlockDragSurface()!.translateSurface(xy.x, xy.y); // Execute the move on the top-level SVG component const svg = this.getSvgRoot(); if (svg) { - this.workspace!.getBlockDragSurface()!.setBlocksAndShow(svg); + this.workspace.getBlockDragSurface()!.setBlocksAndShow(svg); } } @@ -490,8 +490,8 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, } // Translate to current position, turning off 3d. this.translate(newXY.x, newXY.y); - this.workspace!.getBlockDragSurface()!.clearAndHide( - this.workspace!.getCanvas()); + this.workspace.getBlockDragSurface()!.clearAndHide( + this.workspace.getCanvas()); } /** @@ -503,7 +503,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, */ moveDuringDrag(newLoc: Coordinate) { if (this.useDragSurface_) { - this.workspace!.getBlockDragSurface()!.translateSurface( + this.workspace.getBlockDragSurface()!.translateSurface( newLoc.x, newLoc.y); } else { (this.svgGroup_ as AnyDuringMigration).translate_ = @@ -526,10 +526,10 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, /** Snap this block to the nearest grid point. */ snapToGrid() { - if (!this.workspace) { + if (this.disposed) { return; // Deleted block. } - if (this.workspace!.isDragging()) { + if (this.workspace.isDragging()) { return // Don't bump blocks during a drag.; } @@ -539,7 +539,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, if (this.isInFlyout) { return; // Don't move blocks around in a flyout. } - const grid = this.workspace!.getGrid(); + const grid = this.workspace.getGrid(); if (!grid || !grid.shouldSnap()) { return; // Config says no snapping. } @@ -581,7 +581,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, * A dirty field is a field that needs to be re-rendered. */ markDirty() { - this.pathObject.constants = this.workspace!.getRenderer().getConstants(); + this.pathObject.constants = this.workspace.getRenderer().getConstants(); for (let i = 0, input; input = this.inputList[i]; i++) { input.markDirty(); } @@ -667,8 +667,8 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, nextField.showEditor(); // Also move the cursor if we're in keyboard nav mode. - if (this.workspace!.keyboardAccessibilityMode) { - this.workspace!.getCursor()!.setCurNode(nextNode); + if (this.workspace.keyboardAccessibilityMode) { + this.workspace.getCursor()!.setCurNode(nextNode); } } } @@ -678,7 +678,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, * @param e Mouse down event or touch start event. */ private onMouseDown_(e: Event) { - const gesture = this.workspace && this.workspace!.getGesture(e); + const gesture = this.workspace.getGesture(e); if (gesture) { gesture.handleBlockStart(e, this); } @@ -702,7 +702,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, */ protected generateContextMenu(): Array|null { - if (this.workspace!.options.readOnly || !this.contextMenu) { + if (this.workspace.options.readOnly || !this.contextMenu) { return null; } // AnyDuringMigration because: Argument of type '{ block: this; }' is not @@ -830,7 +830,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, this.isInsertionMarker_ = insertionMarker; if (this.isInsertionMarker_) { this.setColour( - this.workspace!.getRenderer().getConstants().INSERTION_MARKER_COLOUR); + this.workspace.getRenderer().getConstants().INSERTION_MARKER_COLOUR); this.pathObject.updateInsertionMarker(true); } } @@ -852,7 +852,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, * @suppress {checkTypes} */ override dispose(healStack?: boolean, animate?: boolean) { - if (!this.workspace) { + if (this.disposed) { // The block has already been deleted. return; } @@ -865,7 +865,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, // If this block is being dragged, unlink the mouse events. if (common.getSelected() === this) { this.unselect(); - this.workspace!.cancelCurrentGesture(); + this.workspace.cancelCurrentGesture(); } // If this block has a context menu open, close it. if (ContextMenu.getCurrentBlock() === this) { @@ -920,11 +920,11 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, * grouping, or hide chaff, then use `block.dispose()` directly. */ checkAndDelete() { - if (this.workspace!.isFlyout) { + if (this.workspace.isFlyout) { return; } eventUtils.setGroup(true); - this.workspace!.hideChaff(); + this.workspace.hideChaff(); if (this.outputConnection) { // Do not attempt to heal rows // (https://github.com/google/blockly/issues/4832) @@ -953,7 +953,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, this as AnyDuringMigration, {addCoordinates: true, addNextBlocks: false}) as blocks.State, - source: this.workspace!, + source: this.workspace, typeCounts: common.getBlockTypeCounts(this as AnyDuringMigration, true), }; } @@ -1062,12 +1062,12 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, clearTimeout(this.warningTextDb_[id]); delete this.warningTextDb_[id]; } - if (this.workspace!.isDragging()) { + if (this.workspace.isDragging()) { // Don't change the warning text during a drag. // Wait until the drag finishes. const thisBlock = this; this.warningTextDb_[id] = setTimeout(function() { - if (thisBlock.workspace) { // Check block wasn't deleted. + if (!thisBlock.disposed) { // Check block wasn't deleted. delete thisBlock.warningTextDb_[id]; thisBlock.setWarningText(text, id); } @@ -1212,7 +1212,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, override setColour(colour: number|string) { super.setColour(colour); const styleObj = - this.workspace!.getRenderer().getConstants().getBlockStyleForColour( + this.workspace.getRenderer().getConstants().getBlockStyleForColour( this.colour_); this.pathObject.setStyle(styleObj.style); @@ -1229,7 +1229,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, */ override setStyle(blockStyleName: string) { const blockStyle = - this.workspace!.getRenderer().getConstants().getBlockStyle( + this.workspace.getRenderer().getConstants().getBlockStyle( blockStyleName); this.styleName_ = blockStyleName; @@ -1516,10 +1516,10 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, * connected should not coincidentally line up on screen. */ override bumpNeighbours() { - if (!this.workspace) { + if (this.disposed) { return; // Deleted block. } - if (this.workspace!.isDragging()) { + if (this.workspace.isDragging()) { return; // Don't bump blocks during a drag. } const rootBlock = this.getRootBlock(); @@ -1639,7 +1639,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, if (this.isCollapsed()) { this.updateCollapsed_(); } - this.workspace!.getRenderer().render(this); + this.workspace.getRenderer().render(this); this.updateConnectionLocations_(); if (opt_bubble !== false) { @@ -1648,7 +1648,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, parentBlock.render(true); } else { // Top-most block. Fire an event to allow scrollbars to resize. - this.workspace!.resizeContents(); + this.workspace.resizeContents(); } } @@ -1661,14 +1661,12 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, /** Redraw any attached marker or cursor svgs if needed. */ protected updateMarkers_() { - if (this.workspace!.keyboardAccessibilityMode && - this.pathObject.cursorSvg) { - this.workspace!.getCursor()!.draw(); + if (this.workspace.keyboardAccessibilityMode && this.pathObject.cursorSvg) { + this.workspace.getCursor()!.draw(); } - if (this.workspace!.keyboardAccessibilityMode && - this.pathObject.markerSvg) { + if (this.workspace.keyboardAccessibilityMode && this.pathObject.markerSvg) { // TODO(#4592): Update all markers on the block. - this.workspace!.getMarker(MarkerManager.LOCAL_MARKER)!.draw(); + this.workspace.getMarker(MarkerManager.LOCAL_MARKER)!.draw(); } } @@ -1740,7 +1738,7 @@ export class BlockSvg extends Block implements IASTNodeLocationSvg, if (nextBlock) { const nextHeightWidth = nextBlock.getHeightWidth(); const tabHeight = - this.workspace!.getRenderer().getConstants().NOTCH_HEIGHT; + this.workspace.getRenderer().getConstants().NOTCH_HEIGHT; height += nextHeightWidth.height - tabHeight; width = Math.max(width, nextHeightWidth.width); } diff --git a/core/comment.ts b/core/comment.ts index 36b6a8d6ddf..e6759d2d054 100644 --- a/core/comment.ts +++ b/core/comment.ts @@ -271,7 +271,7 @@ export class Comment extends Icon { /** Show an editable bubble. */ private createEditableBubble_() { this.bubble_ = new Bubble( - this.block_.workspace!, this.createEditor_(), + this.block_.workspace, this.createEditor_(), this.block_.pathObject.svgPath, (this.iconXY_ as Coordinate), this.model_.size.width, this.model_.size.height); // Expose this comment's block's ID on its top-level SVG group. diff --git a/core/connection.ts b/core/connection.ts index 8dd84f13510..47792ed5435 100644 --- a/core/connection.ts +++ b/core/connection.ts @@ -197,7 +197,7 @@ export class Connection implements IASTNodeLocationWithBlock { * @internal */ getConnectionChecker(): IConnectionChecker { - return this.sourceBlock_.workspace!.connectionChecker; + return this.sourceBlock_.workspace.connectionChecker; } /** @@ -563,7 +563,7 @@ export class Connection implements IASTNodeLocationWithBlock { const parentBlock = this.getSourceBlock(); const shadowState = this.getShadowState(); const shadowDom = this.getShadowDom(); - if (!parentBlock.workspace || !shadowState && !shadowDom) { + if (parentBlock.disposed || !shadowState && !shadowDom) { return null; } diff --git a/core/contextmenu_items.ts b/core/contextmenu_items.ts index 30441cfb819..df8c246924f 100644 --- a/core/contextmenu_items.ts +++ b/core/contextmenu_items.ts @@ -250,7 +250,7 @@ function deleteNext_(deleteList: BlockSvg[], eventGroup: string) { eventUtils.setGroup(eventGroup); const block = deleteList.shift(); if (block) { - if (block.workspace) { + if (!block.disposed) { block.dispose(false, true); setTimeout(deleteNext_, DELAY, deleteList, eventGroup); } else { @@ -372,7 +372,7 @@ export function registerComment() { const block = scope.block; // IE doesn't support necessary features for comment editing. if (!userAgent.IE && !block!.isInFlyout && - block!.workspace!.options.comments && !block!.isCollapsed() && + block!.workspace.options.comments && !block!.isCollapsed() && block!.isEditable()) { return 'enabled'; } @@ -440,7 +440,7 @@ export function registerCollapseExpandBlock() { preconditionFn(scope: Scope) { const block = scope.block; if (!block!.isInFlyout && block!.isMovable() && - block!.workspace!.options.collapse) { + block!.workspace.options.collapse) { return 'enabled'; } return 'hidden'; @@ -467,7 +467,7 @@ export function registerDisable() { }, preconditionFn(scope: Scope) { const block = scope.block; - if (!block!.isInFlyout && block!.workspace!.options.disable && + if (!block!.isInFlyout && block!.workspace.options.disable && block!.isEditable()) { if (block!.getInheritedDisabled()) { return 'disabled'; diff --git a/core/dropdowndiv.ts b/core/dropdowndiv.ts index bda20ee5a2b..b6a6def74a3 100644 --- a/core/dropdowndiv.ts +++ b/core/dropdowndiv.ts @@ -226,7 +226,7 @@ export function showPositionedByField( */ function getScaledBboxOfBlock(block: BlockSvg): Rect { const blockSvg = block.getSvgRoot(); - const scale = block.workspace!.scale; + const scale = block.workspace.scale; const scaledHeight = block.height * scale; const scaledWidth = block.width * scale; const xy = style.getPageOffset(blockSvg); @@ -268,7 +268,7 @@ function showPositionedByRect( } const sourceBlock = field.getSourceBlock() as BlockSvg; // Set bounds to main workspace; show the drop-down. - let workspace = sourceBlock.workspace!; + let workspace = sourceBlock.workspace; while (workspace.options.parentWorkspace) { workspace = workspace.options.parentWorkspace; } diff --git a/core/events/events_block_base.ts b/core/events/events_block_base.ts index 86f6e04c2db..b9359f4e01d 100644 --- a/core/events/events_block_base.ts +++ b/core/events/events_block_base.ts @@ -41,7 +41,7 @@ export class BlockBase extends AbstractEvent { this.blockId = this.isBlank ? '' : opt_block!.id; /** The workspace identifier for this event. */ - this.workspaceId = this.isBlank ? '' : opt_block!.workspace?.id ?? ''; + this.workspaceId = this.isBlank ? '' : opt_block!.workspace.id; } /** diff --git a/core/events/events_block_drag.ts b/core/events/events_block_drag.ts index 266a3d102f0..84860e73795 100644 --- a/core/events/events_block_drag.ts +++ b/core/events/events_block_drag.ts @@ -41,7 +41,7 @@ export class BlockDrag extends UiBase { * event. */ constructor(opt_block?: Block, opt_isStart?: boolean, opt_blocks?: Block[]) { - const workspaceId = opt_block ? opt_block.workspace?.id : undefined; + const workspaceId = opt_block ? opt_block.workspace.id : undefined; super(workspaceId); this.blockId = opt_block ? opt_block.id : null; diff --git a/core/events/events_bubble_open.ts b/core/events/events_bubble_open.ts index f599d139995..aad69b1331b 100644 --- a/core/events/events_bubble_open.ts +++ b/core/events/events_bubble_open.ts @@ -41,7 +41,7 @@ export class BubbleOpen extends UiBase { */ constructor( opt_block: BlockSvg, opt_isOpen?: boolean, opt_bubbleType?: string) { - const workspaceId = opt_block ? opt_block.workspace!.id : undefined; + const workspaceId = opt_block ? opt_block.workspace.id : undefined; super(workspaceId); this.blockId = opt_block ? opt_block.id : null; diff --git a/core/events/events_click.ts b/core/events/events_click.ts index 513f1f86461..a58a7b8acb4 100644 --- a/core/events/events_click.ts +++ b/core/events/events_click.ts @@ -43,7 +43,7 @@ export class Click extends UiBase { constructor( opt_block?: Block|null, opt_workspaceId?: string|null, opt_targetType?: string) { - let workspaceId = opt_block ? opt_block.workspace!.id : opt_workspaceId; + let workspaceId = opt_block ? opt_block.workspace.id : opt_workspaceId; if (workspaceId === null) { workspaceId = undefined; } diff --git a/core/events/events_marker_move.ts b/core/events/events_marker_move.ts index 12feb7c2f9b..f91246a95e7 100644 --- a/core/events/events_marker_move.ts +++ b/core/events/events_marker_move.ts @@ -48,7 +48,7 @@ export class MarkerMove extends UiBase { constructor( opt_block?: Block|null, isCursor?: boolean, opt_oldNode?: ASTNode|null, opt_newNode?: ASTNode) { - let workspaceId = opt_block ? opt_block.workspace!.id : undefined; + let workspaceId = opt_block ? opt_block.workspace.id : undefined; if (opt_newNode && opt_newNode.getType() === ASTNode.types.WORKSPACE) { workspaceId = (opt_newNode.getLocation() as Workspace).id; } diff --git a/core/events/events_ui.ts b/core/events/events_ui.ts index f77fe7ee34e..de647f2fb40 100644 --- a/core/events/events_ui.ts +++ b/core/events/events_ui.ts @@ -46,7 +46,7 @@ export class Ui extends UiBase { constructor( opt_block?: Block|null, opt_element?: string, opt_oldValue?: AnyDuringMigration, opt_newValue?: AnyDuringMigration) { - const workspaceId = opt_block ? opt_block.workspace!.id : undefined; + const workspaceId = opt_block ? opt_block.workspace.id : undefined; super(workspaceId); this.blockId = opt_block ? opt_block.id : null; diff --git a/core/field.ts b/core/field.ts index 0654411ed9f..8f4fa456d12 100644 --- a/core/field.ts +++ b/core/field.ts @@ -264,7 +264,7 @@ export abstract class Field implements IASTNodeLocationSvg, * @return The renderer constant provider. */ getConstants(): ConstantProvider|null { - if (!this.constants_ && this.sourceBlock_ && this.sourceBlock_.workspace && + if (!this.constants_ && this.sourceBlock_ && !this.sourceBlock_.disposed && this.sourceBlock_.workspace.rendered) { this.constants_ = (this.sourceBlock_.workspace as WorkspaceSvg) .getRenderer() @@ -1023,7 +1023,7 @@ export abstract class Field implements IASTNodeLocationSvg, * @param e Mouse down event. */ protected onMouseDown_(e: Event) { - if (!this.sourceBlock_ || !this.sourceBlock_.workspace) { + if (!this.sourceBlock_ || this.sourceBlock_.disposed) { return; } const gesture = (this.sourceBlock_.workspace as WorkspaceSvg).getGesture(e); diff --git a/core/field_variable.ts b/core/field_variable.ts index 4b510af7e16..39fe3f3ba04 100644 --- a/core/field_variable.ts +++ b/core/field_variable.ts @@ -139,7 +139,7 @@ export class FieldVariable extends FieldDropdown { return; // Initialization already happened. } const variable = Variables.getOrCreateVariablePackage( - this.sourceBlock_.workspace!, null, this.defaultVariableName, + this.sourceBlock_.workspace, null, this.defaultVariableName, this.defaultType_); // Don't call setValue because we don't want to cause a rerender. this.doValueUpdate_(variable.getId()); @@ -167,7 +167,7 @@ export class FieldVariable extends FieldDropdown { // AnyDuringMigration because: Argument of type 'string | null' is not // assignable to parameter of type 'string | undefined'. const variable = Variables.getOrCreateVariablePackage( - this.sourceBlock_.workspace!, id, variableName as AnyDuringMigration, + this.sourceBlock_.workspace, id, variableName as AnyDuringMigration, variableType); // This should never happen :) @@ -234,7 +234,7 @@ export class FieldVariable extends FieldDropdown { } // This is necessary so that blocks in the flyout can have custom var names. const variable = Variables.getOrCreateVariablePackage( - this.sourceBlock_.workspace!, state['id'] || null, state['name'], + this.sourceBlock_.workspace, state['id'] || null, state['name'], state['type'] || ''); this.setValue(variable.getId()); } @@ -306,7 +306,7 @@ export class FieldVariable extends FieldDropdown { return null; } const newId = opt_newValue as string; - const variable = Variables.getVariable(this.sourceBlock_.workspace!, newId); + const variable = Variables.getVariable(this.sourceBlock_.workspace, newId); if (!variable) { console.warn( 'Variable id doesn\'t point to a real variable! ' + @@ -332,7 +332,7 @@ export class FieldVariable extends FieldDropdown { */ protected override doValueUpdate_(newId: AnyDuringMigration) { this.variable_ = - Variables.getVariable(this.sourceBlock_.workspace!, newId as string); + Variables.getVariable(this.sourceBlock_.workspace, newId as string); super.doValueUpdate_(newId); } @@ -364,7 +364,7 @@ export class FieldVariable extends FieldDropdown { let variableTypes = this.variableTypes; if (variableTypes === null) { // If variableTypes is null, return all variable types. - if (this.sourceBlock_ && this.sourceBlock_.workspace) { + if (this.sourceBlock_ && !this.sourceBlock_.disposed) { return this.sourceBlock_.workspace.getVariableTypes(); } } @@ -440,7 +440,7 @@ export class FieldVariable extends FieldDropdown { protected override onItemSelected_(menu: Menu, menuItem: MenuItem) { const id = menuItem.getValue(); // Handle special cases. - if (this.sourceBlock_ && this.sourceBlock_.workspace) { + if (this.sourceBlock_ && !this.sourceBlock_.disposed) { if (id === internalConstants.RENAME_VARIABLE_ID) { // Rename variable. Variables.renameVariable( @@ -495,7 +495,7 @@ export class FieldVariable extends FieldDropdown { } const name = this.getText(); let variableModelList: AnyDuringMigration[] = []; - if (this.sourceBlock_ && this.sourceBlock_.workspace) { + if (this.sourceBlock_ && !this.sourceBlock_.disposed) { const variableTypes = this.getVariableTypes_(); // Get a copy of the list, so that adding rename and new variable options // doesn't modify the workspace's list. diff --git a/core/gesture.ts b/core/gesture.ts index 053ea396f4e..5d9ff2604a0 100644 --- a/core/gesture.ts +++ b/core/gesture.ts @@ -581,7 +581,7 @@ export class Gesture { handleRightClick(e: Event) { if (this.targetBlock_) { this.bringBlockToFront_(); - this.targetBlock_.workspace!.hideChaff(!!this.flyout_); + this.targetBlock_.workspace.hideChaff(!!this.flyout_); this.targetBlock_.showContextMenu(e); } else if (this.startBubble_) { this.startBubble_.showContextMenu(e); diff --git a/core/icon.ts b/core/icon.ts index c74028acb81..6cf57f2a9b6 100644 --- a/core/icon.ts +++ b/core/icon.ts @@ -111,7 +111,7 @@ export abstract class Icon { * @param e Mouse click event. */ protected iconClick_(e: Event) { - if (this.block_.workspace!.isDragging()) { + if (this.block_.workspace.isDragging()) { // Drag operation is concluding. Don't open the editor. return; } diff --git a/core/input.ts b/core/input.ts index 079366cb889..4d58cc2f064 100644 --- a/core/input.ts +++ b/core/input.ts @@ -271,7 +271,7 @@ export class Input { /** Initialize the fields on this input. */ init() { - if (!this.sourceBlock_.workspace!.rendered) { + if (!this.sourceBlock_.workspace.rendered) { return; // Headless blocks don't need fields initialized. } for (let i = 0; i < this.fieldRow.length; i++) { diff --git a/core/insertion_marker_manager.ts b/core/insertion_marker_manager.ts index 1f8941fa6ac..abdfca4dea3 100644 --- a/core/insertion_marker_manager.ts +++ b/core/insertion_marker_manager.ts @@ -133,7 +133,7 @@ export class InsertionMarkerManager { * The workspace on which these connections are being dragged. * Does not change during a drag. */ - this.workspace_ = block.workspace!; + this.workspace_ = block.workspace; /** * The insertion marker that shows up between blocks to show where a block diff --git a/core/keyboard_nav/ast_node.ts b/core/keyboard_nav/ast_node.ts index 4efe194dbb6..45cd785e35f 100644 --- a/core/keyboard_nav/ast_node.ts +++ b/core/keyboard_nav/ast_node.ts @@ -268,11 +268,11 @@ export class ASTNode { // TODO(#6097): Use instanceof checks to exit early for values of // curLocation that don't make sense. const curLocationAsBlock = curLocation as Block; - if (!curLocationAsBlock || !curLocationAsBlock.workspace) { + if (!curLocationAsBlock || curLocationAsBlock.disposed) { return null; } const curRoot = curLocationAsBlock.getRootBlock(); - const topBlocks = curRoot.workspace?.getTopBlocks(true) ?? []; + const topBlocks = curRoot.workspace.getTopBlocks(true); for (let i = 0; i < topBlocks.length; i++) { const topBlock = topBlocks[i]; if (curRoot.id === topBlock.id) { diff --git a/core/mutator.ts b/core/mutator.ts index aff6f8bf02b..1201e06300c 100644 --- a/core/mutator.ts +++ b/core/mutator.ts @@ -178,11 +178,11 @@ export class Mutator extends Icon { // event filter from workspaceChanged_ . 'disable': false, 'parentWorkspace': this.block_.workspace, - 'media': this.block_.workspace!.options.pathToMedia, + 'media': this.block_.workspace.options.pathToMedia, 'rtl': this.block_.RTL, 'horizontalLayout': false, - 'renderer': this.block_.workspace!.options.renderer, - 'rendererOverrides': this.block_.workspace!.options.rendererOverrides, + 'renderer': this.block_.workspace.options.renderer, + 'rendererOverrides': this.block_.workspace.options.rendererOverrides, } as BlocklyOptions)); workspaceOptions.toolboxPosition = this.block_.RTL ? toolbox.Position.RIGHT : toolbox.Position.LEFT; @@ -353,7 +353,7 @@ export class Mutator extends Icon { this.block_.saveConnections(thisRootBlock); } }; - this.block_.workspace!.addChangeListener(this.sourceListener_); + this.block_.workspace.addChangeListener(this.sourceListener_); } this.resizeBubble_(); // When the mutator's workspace changes, update the source block. @@ -372,7 +372,7 @@ export class Mutator extends Icon { this.workspaceWidth_ = 0; this.workspaceHeight_ = 0; if (this.sourceListener_) { - this.block_.workspace!.removeChangeListener(this.sourceListener_); + this.block_.workspace.removeChangeListener(this.sourceListener_); this.sourceListener_ = null; } } diff --git a/core/procedures.ts b/core/procedures.ts index 4e152c3c7b3..f5ac72f7317 100644 --- a/core/procedures.ts +++ b/core/procedures.ts @@ -111,7 +111,7 @@ export function findLegalName(name: string, block: Block): string { return name; } name = name || Msg['UNNAMED_KEY'] || 'unnamed'; - while (!isLegalName(name, block.workspace!, block)) { + while (!isLegalName(name, block.workspace, block)) { // Collision with another procedure. const r = name.match(/^(.*?)(\d+)$/); if (!r) { @@ -179,7 +179,7 @@ export function rename(this: Field, name: string): string { const oldName = this.getValue(); if (oldName !== name && oldName !== legalName) { // Rename any callers. - const blocks = this.getSourceBlock().workspace!.getAllBlocks(false); + const blocks = this.getSourceBlock().workspace.getAllBlocks(false); for (let i = 0; i < blocks.length; i++) { // Assume it is a procedure so we can check. const procedureBlock = blocks[i] as unknown as ProcedureBlock; @@ -396,7 +396,7 @@ export function mutateCallers(defBlock: Block) { const procedureBlock = defBlock as unknown as ProcedureBlock; const name = procedureBlock.getProcedureDef()[0]; const xmlElement = defBlock.mutationToDom!(true); - const callers = getCallers(name, defBlock.workspace!); + const callers = getCallers(name, defBlock.workspace); for (let i = 0, caller; caller = callers[i]; i++) { const oldMutationDom = caller.mutationToDom!(); const oldMutation = oldMutationDom && Xml.domToText(oldMutationDom); diff --git a/core/rendered_connection.ts b/core/rendered_connection.ts index 0689dfe2b8f..430bc89e02e 100644 --- a/core/rendered_connection.ts +++ b/core/rendered_connection.ts @@ -70,14 +70,14 @@ export class RenderedConnection extends Connection { * Connection database for connections of this type on the current * workspace. */ - this.db_ = source.workspace!.connectionDBList[type]; + this.db_ = source.workspace.connectionDBList[type]; /** * Connection database for connections compatible with this type on the * current workspace. */ this.dbOpposite_ = - source.workspace! + source.workspace .connectionDBList[internalConstants.OPPOSITE_TYPE[type]]; /** Workspace units, (0, 0) is top left of block. */ @@ -134,7 +134,7 @@ export class RenderedConnection extends Connection { * @internal */ bumpAwayFrom(staticConnection: RenderedConnection) { - if (this.sourceBlock_.workspace!.isDragging()) { + if (this.sourceBlock_.workspace.isDragging()) { // Don't move blocks around while the user is doing the same. return; } @@ -271,7 +271,7 @@ export class RenderedConnection extends Connection { let steps; const sourceBlockSvg = (this.sourceBlock_); const renderConstants = - sourceBlockSvg.workspace!.getRenderer().getConstants(); + sourceBlockSvg.workspace.getRenderer().getConstants(); const shape = renderConstants.shapeFor(this); if (this.type === ConnectionType.INPUT_VALUE || this.type === ConnectionType.OUTPUT_VALUE) { diff --git a/core/serialization/blocks.ts b/core/serialization/blocks.ts index 8b57aa17a07..5f2f03f77e8 100644 --- a/core/serialization/blocks.ts +++ b/core/serialization/blocks.ts @@ -162,7 +162,7 @@ function saveAttributes(block: Block, state: State) { * @param state The state object to append to. */ function saveCoords(block: Block, state: State) { - const workspace = block.workspace!; + const workspace = block.workspace; const xy = block.getRelativeToSurfaceXY(); state['x'] = Math.round(workspace.RTL ? workspace.getWidth() - xy.x : xy.x); state['y'] = Math.round(xy.y); @@ -416,7 +416,7 @@ function loadCoords(block: Block, state: State) { let x = state['x'] === undefined ? 0 : state['x']; const y = state['y'] === undefined ? 0 : state['y']; - const workspace = block.workspace!; + const workspace = block.workspace; x = workspace.RTL ? workspace.getWidth() - x : x; block.moveBy(x, y); @@ -492,7 +492,7 @@ function tryToConnectParent( } if (!connected) { - const checker = child.workspace!.connectionChecker; + const checker = child.workspace.connectionChecker; throw new BadConnectionCheck( checker.getErrorMessage( checker.canConnectWithReason( @@ -606,7 +606,7 @@ function loadConnection( } if (connectionState['block']) { appendPrivate( - connectionState['block'], connection.getSourceBlock().workspace!, + connectionState['block'], connection.getSourceBlock().workspace, {parentConnection: connection}); } } diff --git a/core/shortcut_items.ts b/core/shortcut_items.ts index 072da602e15..dfdeb0f1c35 100644 --- a/core/shortcut_items.ts +++ b/core/shortcut_items.ts @@ -142,7 +142,7 @@ export function registerCut() { return !!( !workspace.options.readOnly && !Gesture.inProgress() && selected && selected instanceof BlockSvg && selected.isDeletable() && - selected.isMovable() && !selected.workspace!.isFlyout); + selected.isMovable() && !selected.workspace.isFlyout); }, callback() { const selected = common.getSelected(); diff --git a/core/xml.ts b/core/xml.ts index 414b8e54e14..677b9edf6aa 100644 --- a/core/xml.ts +++ b/core/xml.ts @@ -109,7 +109,7 @@ export function blockToDomWithXY(block: Block, opt_noId?: boolean): Element| } let width = 0; // Not used in LTR. - if (block.workspace?.RTL) { + if (block.workspace.RTL) { width = block.workspace.getWidth(); } @@ -118,8 +118,7 @@ export function blockToDomWithXY(block: Block, opt_noId?: boolean): Element| // AnyDuringMigration because: Property 'setAttribute' does not exist on type // 'Element | DocumentFragment'. (element as AnyDuringMigration) - .setAttribute( - 'x', Math.round(block.workspace?.RTL ? width - xy.x : xy.x)); + .setAttribute('x', Math.round(block.workspace.RTL ? width - xy.x : xy.x)); // AnyDuringMigration because: Property 'setAttribute' does not exist on type // 'Element | DocumentFragment'. (element as AnyDuringMigration).setAttribute('y', Math.round(xy.y));