chore: cleaned up several type cases in core/field.ts and impacted files (#6363)

* chore: cleaned up several type cases in core/field.ts and impacted files

* chore: updated instances of `sourceBlock_!` to `getSourceBlock()`

* chore: updated instances of `fieldGroup_!` to `getSvgRoot()`

* chore: updated nullable variables in `field.ts` to use internal functions

* chore: updated getSourceBlock and getSvgRoot to handle nullability

* chore: updated comments to reference throwing an error

* fix: reverted `getSvgRoot` to `fieldGroup_` in null-accepting areas

* fix: updated `getSvgRoot` to allow null and added null handling methods

* fix: moved click target error handling to their specific cases

* fix: updated drawer.ts to handle cast svg group to defined
This commit is contained in:
Blake Thomas Williams
2022-09-30 10:53:19 -05:00
committed by GitHub
parent dd0d0f6bcf
commit fa925e8c35
11 changed files with 151 additions and 124 deletions

View File

@@ -72,9 +72,7 @@ export abstract class Field implements IASTNodeLocationSvg,
protected value_: AnyDuringMigration;
/** Validation function called when user edits an editable field. */
// AnyDuringMigration because: Type 'null' is not assignable to type
// 'Function'.
protected validator_: Function = null as AnyDuringMigration;
protected validator_: Function|null = null;
/**
* Used to cache the field's tooltip value if setTooltip is called when the
@@ -87,44 +85,31 @@ export abstract class Field implements IASTNodeLocationSvg,
* Holds the cursors svg element when the cursor is attached to the field.
* This is null if there is no cursor on the field.
*/
// AnyDuringMigration because: Type 'null' is not assignable to type
// 'SVGElement'.
private cursorSvg_: SVGElement = null as AnyDuringMigration;
private cursorSvg_: SVGElement|null = null;
/**
* Holds the markers svg element when the marker is attached to the field.
* This is null if there is no marker on the field.
*/
// AnyDuringMigration because: Type 'null' is not assignable to type
// 'SVGElement'.
private markerSvg_: SVGElement = null as AnyDuringMigration;
private markerSvg_: SVGElement|null = null;
/** The rendered field's SVG group element. */
// AnyDuringMigration because: Type 'null' is not assignable to type
// 'SVGGElement'.
protected fieldGroup_: SVGGElement = null as AnyDuringMigration;
protected fieldGroup_: SVGGElement|null = null;
/** The rendered field's SVG border element. */
// AnyDuringMigration because: Type 'null' is not assignable to type
// 'SVGRectElement'.
protected borderRect_: SVGRectElement = null as AnyDuringMigration;
protected borderRect_: SVGRectElement|null = null;
/** The rendered field's SVG text element. */
// AnyDuringMigration because: Type 'null' is not assignable to type
// 'SVGTextElement'.
protected textElement_: SVGTextElement = null as AnyDuringMigration;
protected textElement_: SVGTextElement|null = null;
/** The rendered field's text content element. */
// AnyDuringMigration because: Type 'null' is not assignable to type 'Text'.
protected textContent_: Text = null as AnyDuringMigration;
protected textContent_: Text|null = null;
/** Mouse down event listener data. */
private mouseDownWrapper_: browserEvents.Data|null = null;
/** Constants associated with the source block's renderer. */
// AnyDuringMigration because: Type 'null' is not assignable to type
// 'ConstantProvider'.
protected constants_: ConstantProvider = null as AnyDuringMigration;
protected constants_: ConstantProvider|null = null;
/**
* Has this field been disposed of?
@@ -137,8 +122,7 @@ export abstract class Field implements IASTNodeLocationSvg,
maxDisplayLength = 50;
/** Block this field is attached to. Starts as null, then set in init. */
// AnyDuringMigration because: Type 'null' is not assignable to type 'Block'.
protected sourceBlock_: Block = null as AnyDuringMigration;
protected sourceBlock_: Block|null = null;
/** Does this block need to be re-rendered? */
protected isDirty_ = true;
@@ -152,9 +136,7 @@ export abstract class Field implements IASTNodeLocationSvg,
protected enabled_ = true;
/** The element the click handler is bound to. */
// AnyDuringMigration because: Type 'null' is not assignable to type
// 'Element'.
protected clickTarget_: Element = null as AnyDuringMigration;
protected clickTarget_: Element|null = null;
/**
* The prefix field.
@@ -271,8 +253,12 @@ export abstract class Field implements IASTNodeLocationSvg,
* Get the block this field is attached to.
*
* @returns The block containing this field.
* @throws An error if the source block is not defined.
*/
getSourceBlock(): Block {
if (!this.sourceBlock_) {
throw new Error(`The source block is ${this.sourceBlock_}.`);
}
return this.sourceBlock_;
}
@@ -361,9 +347,11 @@ export abstract class Field implements IASTNodeLocationSvg,
* do custom input handling.
*/
protected bindEvents_() {
Tooltip.bindMouseEvents(this.getClickTarget_());
const clickTarget = this.getClickTarget_();
if (!clickTarget) throw new Error('A click target has not been set.');
Tooltip.bindMouseEvents(clickTarget);
this.mouseDownWrapper_ = browserEvents.conditionalBind(
this.getClickTarget_(), 'mousedown', this, this.onMouseDown_);
clickTarget, 'mousedown', this, this.onMouseDown_);
}
/**
@@ -431,7 +419,7 @@ export abstract class Field implements IASTNodeLocationSvg,
* Used to see if `this` has overridden any relevant hooks.
* @returns The stringified version of the XML state, or null.
*/
protected saveLegacyState(callingClass: AnyDuringMigration): string|null {
protected saveLegacyState(callingClass: FieldProto): string|null {
if (callingClass.prototype.saveState === this.saveState &&
callingClass.prototype.toXml !== this.toXml) {
const elem = utilsXml.createElement('field');
@@ -454,7 +442,7 @@ export abstract class Field implements IASTNodeLocationSvg,
* @param state The state to apply to the field.
* @returns Whether the state was applied or not.
*/
loadLegacyState(callingClass: AnyDuringMigration, state: AnyDuringMigration):
loadLegacyState(callingClass: FieldProto, state: AnyDuringMigration):
boolean {
if (callingClass.prototype.loadState === this.loadState &&
callingClass.prototype.fromXml !== this.fromXml) {
@@ -491,7 +479,7 @@ export abstract class Field implements IASTNodeLocationSvg,
if (!this.EDITABLE || !group) {
return;
}
if (this.enabled_ && this.sourceBlock_.isEditable()) {
if (this.enabled_ && this.getSourceBlock().isEditable()) {
dom.addClass(group, 'blocklyEditableText');
dom.removeClass(group, 'blocklyNonEditableText');
group.style.cursor = this.CURSOR;
@@ -590,7 +578,7 @@ export abstract class Field implements IASTNodeLocationSvg,
return;
}
this.visible_ = visible;
const root = this.getSvgRoot();
const root = this.fieldGroup_;
if (root) {
root.style.display = visible ? 'block' : 'none';
}
@@ -630,10 +618,49 @@ export abstract class Field implements IASTNodeLocationSvg,
*
* @returns The group element.
*/
getSvgRoot(): SVGGElement {
getSvgRoot(): SVGGElement|null {
return this.fieldGroup_;
}
/**
* Gets the border rectangle element.
*
* @returns The border rectangle element.
* @throws An error if the border rectangle element is not defined.
*/
protected getBorderRect(): SVGRectElement {
if (!this.borderRect_) {
throw new Error(`The border rectangle is ${this.borderRect_}.`);
}
return this.borderRect_;
}
/**
* Gets the text element.
*
* @returns The text element.
* @throws An error if the text element is not defined.
*/
protected getTextElement(): SVGTextElement {
if (!this.textElement_) {
throw new Error(`The text element is ${this.textElement_}.`);
}
return this.textElement_;
}
/**
* Gets the text content.
*
* @returns The text content.
* @throws An error if the text content is not defined.
*/
protected getTextContent(): Text {
if (!this.textContent_) {
throw new Error(`The text content is ${this.textContent_}.`);
}
return this.textContent_;
}
/**
* Updates the field to match the colour/style of the block. Should only be
* called by BlockSvg.applyColour().
@@ -726,20 +753,19 @@ export abstract class Field implements IASTNodeLocationSvg,
const constants = this.getConstants();
const halfHeight = this.size_.height / 2;
// AnyDuringMigration because: Argument of type 'number' is not assignable
// to parameter of type 'string'.
this.textElement_.setAttribute(
'x',
(this.sourceBlock_.RTL ? this.size_.width - contentWidth - xOffset :
xOffset) as AnyDuringMigration);
// AnyDuringMigration because: Argument of type 'number' is not assignable
// to parameter of type 'string'.
`${
this.getSourceBlock().RTL ?
this.size_.width - contentWidth - xOffset :
xOffset}`);
this.textElement_.setAttribute(
'y',
(constants!.FIELD_TEXT_BASELINE_CENTER ?
halfHeight :
halfHeight - constants!.FIELD_TEXT_HEIGHT / 2 +
constants!.FIELD_TEXT_BASELINE) as AnyDuringMigration);
`${
constants!.FIELD_TEXT_BASELINE_CENTER ?
halfHeight :
halfHeight - constants!.FIELD_TEXT_HEIGHT / 2 +
constants!.FIELD_TEXT_BASELINE}`);
}
/** Position a field's border rect after a size change. */
@@ -747,24 +773,12 @@ export abstract class Field implements IASTNodeLocationSvg,
if (!this.borderRect_) {
return;
}
// AnyDuringMigration because: Argument of type 'number' is not assignable
// to parameter of type 'string'.
this.borderRect_.setAttribute('width', `${this.size_.width}`);
this.borderRect_.setAttribute('height', `${this.size_.height}`);
this.borderRect_.setAttribute(
'width', this.size_.width as AnyDuringMigration);
// AnyDuringMigration because: Argument of type 'number' is not assignable
// to parameter of type 'string'.
'rx', `${this.getConstants()!.FIELD_BORDER_RECT_RADIUS}`);
this.borderRect_.setAttribute(
'height', this.size_.height as AnyDuringMigration);
// AnyDuringMigration because: Argument of type 'number' is not assignable
// to parameter of type 'string'.
this.borderRect_.setAttribute(
'rx',
this.getConstants()!.FIELD_BORDER_RECT_RADIUS as AnyDuringMigration);
// AnyDuringMigration because: Argument of type 'number' is not assignable
// to parameter of type 'string'.
this.borderRect_.setAttribute(
'ry',
this.getConstants()!.FIELD_BORDER_RECT_RADIUS as AnyDuringMigration);
'ry', `${this.getConstants()!.FIELD_BORDER_RECT_RADIUS}`);
}
/**
@@ -810,7 +824,7 @@ export abstract class Field implements IASTNodeLocationSvg,
// - Webkit / Blink: fill-box / object bounding box
// - Gecko: stroke-box
const bBox = (this.sourceBlock_ as BlockSvg).getHeightWidth();
const scale = (this.sourceBlock_.workspace as WorkspaceSvg).scale;
const scale = (this.getSourceBlock().workspace as WorkspaceSvg).scale;
xy = this.getAbsoluteXY_();
scaledWidth = (bBox.width + 1) * scale;
scaledHeight = (bBox.height + 1) * scale;
@@ -896,9 +910,7 @@ export abstract class Field implements IASTNodeLocationSvg,
*/
markDirty() {
this.isDirty_ = true;
// AnyDuringMigration because: Type 'null' is not assignable to type
// 'ConstantProvider'.
this.constants_ = null as AnyDuringMigration;
this.constants_ = null;
}
/**
@@ -1101,7 +1113,7 @@ export abstract class Field implements IASTNodeLocationSvg,
*
* @returns Element to bind click handler to.
*/
protected getClickTarget_(): Element {
protected getClickTarget_(): Element|null {
return this.clickTarget_ || this.getSvgRoot();
}
@@ -1145,7 +1157,7 @@ export abstract class Field implements IASTNodeLocationSvg,
*/
getParentInput(): Input {
let parentInput = null;
const block = this.sourceBlock_;
const block = this.getSourceBlock();
const inputs = block.inputList;
for (let idx = 0; idx < block.inputList.length; idx++) {
@@ -1158,9 +1170,7 @@ export abstract class Field implements IASTNodeLocationSvg,
}
}
}
// AnyDuringMigration because: Type 'Input | null' is not assignable to
// type 'Input'.
return parentInput as AnyDuringMigration;
return parentInput!;
}
/**
@@ -1199,12 +1209,13 @@ export abstract class Field implements IASTNodeLocationSvg,
*/
setCursorSvg(cursorSvg: SVGElement) {
if (!cursorSvg) {
// AnyDuringMigration because: Type 'null' is not assignable to type
// 'SVGElement'.
this.cursorSvg_ = null as AnyDuringMigration;
this.cursorSvg_ = null;
return;
}
if (!this.fieldGroup_) {
throw new Error(`The field group is ${this.fieldGroup_}.`);
}
this.fieldGroup_.appendChild(cursorSvg);
this.cursorSvg_ = cursorSvg;
}
@@ -1217,19 +1228,20 @@ export abstract class Field implements IASTNodeLocationSvg,
*/
setMarkerSvg(markerSvg: SVGElement) {
if (!markerSvg) {
// AnyDuringMigration because: Type 'null' is not assignable to type
// 'SVGElement'.
this.markerSvg_ = null as AnyDuringMigration;
this.markerSvg_ = null;
return;
}
if (!this.fieldGroup_) {
throw new Error(`The field group is ${this.fieldGroup_}.`);
}
this.fieldGroup_.appendChild(markerSvg);
this.markerSvg_ = markerSvg;
}
/** Redraw any attached marker or cursor svgs if needed. */
protected updateMarkers_() {
const workspace = this.sourceBlock_.workspace as WorkspaceSvg;
const workspace = this.getSourceBlock().workspace as WorkspaceSvg;
if (workspace.keyboardAccessibilityMode && this.cursorSvg_) {
workspace.getCursor()!.draw();
}
@@ -1246,3 +1258,9 @@ export abstract class Field implements IASTNodeLocationSvg,
export interface FieldConfig {
tooltip?: string;
}
/**
* For use by Field and descendants of Field. Constructors can change
* in descendants, though they should contain all of Field's prototype methods.
*/
export type FieldProto = Pick<typeof Field, 'prototype'>;

View File

@@ -202,7 +202,7 @@ export class FieldAngle extends FieldTextInput {
// #2380)
this.symbol_ = dom.createSvgElement(Svg.TSPAN, {});
this.symbol_.appendChild(document.createTextNode('°'));
this.textElement_.appendChild(this.symbol_);
this.getTextElement().appendChild(this.symbol_);
}
/** Updates the graph when the field rerenders. */
@@ -436,12 +436,12 @@ export class FieldAngle extends FieldTextInput {
// 'Event'.
if ((e as AnyDuringMigration).keyCode === KeyCodes.LEFT) {
// decrement (increment in RTL)
multiplier = this.sourceBlock_.RTL ? 1 : -1;
multiplier = this.getSourceBlock().RTL ? 1 : -1;
// AnyDuringMigration because: Property 'keyCode' does not exist on type
// 'Event'.
} else if ((e as AnyDuringMigration).keyCode === KeyCodes.RIGHT) {
// increment (decrement in RTL)
multiplier = this.sourceBlock_.RTL ? -1 : 1;
multiplier = this.getSourceBlock().RTL ? -1 : 1;
// AnyDuringMigration because: Property 'keyCode' does not exist on type
// 'Event'.
} else if ((e as AnyDuringMigration).keyCode === KeyCodes.DOWN) {

View File

@@ -112,8 +112,9 @@ export class FieldCheckbox extends Field {
override initView() {
super.initView();
dom.addClass(this.textElement_, 'blocklyCheckbox');
this.textElement_.style.display = this.value_ ? 'block' : 'none';
const textElement = this.getTextElement();
dom.addClass(textElement, 'blocklyCheckbox');
textElement.style.display = this.value_ ? 'block' : 'none';
}
override render_() {

View File

@@ -191,7 +191,7 @@ export class FieldColour extends Field {
this.getConstants()!.FIELD_COLOUR_DEFAULT_HEIGHT);
if (!this.getConstants()!.FIELD_COLOUR_FULL_BLOCK) {
this.createBorderRect_();
this.borderRect_.style['fillOpacity'] = '1';
this.getBorderRect().style['fillOpacity'] = '1';
} else if (this.sourceBlock_ instanceof BlockSvg) {
this.clickTarget_ = this.sourceBlock_.getSvgRoot();
}

View File

@@ -217,24 +217,24 @@ export class FieldDropdown extends Field {
protected shouldAddBorderRect_(): boolean {
return !this.getConstants()!.FIELD_DROPDOWN_NO_BORDER_RECT_SHADOW ||
this.getConstants()!.FIELD_DROPDOWN_NO_BORDER_RECT_SHADOW &&
!this.sourceBlock_.isShadow();
!this.getSourceBlock().isShadow();
}
/** Create a tspan based arrow. */
protected createTextArrow_() {
this.arrow_ = dom.createSvgElement(Svg.TSPAN, {}, this.textElement_);
this.arrow_!.appendChild(document.createTextNode(
this.sourceBlock_.RTL ? FieldDropdown.ARROW_CHAR + ' ' :
' ' + FieldDropdown.ARROW_CHAR));
if (this.sourceBlock_.RTL) {
this.getSourceBlock().RTL ? FieldDropdown.ARROW_CHAR + ' ' :
' ' + FieldDropdown.ARROW_CHAR));
if (this.getSourceBlock().RTL) {
// AnyDuringMigration because: Argument of type 'SVGTSpanElement | null'
// is not assignable to parameter of type 'Node'.
this.textElement_.insertBefore(
this.getTextElement().insertBefore(
this.arrow_ as AnyDuringMigration, this.textContent_);
} else {
// AnyDuringMigration because: Argument of type 'SVGTSpanElement | null'
// is not assignable to parameter of type 'Node'.
this.textElement_.appendChild(this.arrow_ as AnyDuringMigration);
this.getTextElement().appendChild(this.arrow_ as AnyDuringMigration);
}
}
@@ -279,11 +279,11 @@ export class FieldDropdown extends Field {
dom.addClass(menuElement, 'blocklyDropdownMenu');
if (this.getConstants()!.FIELD_DROPDOWN_COLOURED_DIV) {
const primaryColour = this.sourceBlock_.isShadow() ?
this.sourceBlock_.getParent()!.getColour() :
this.sourceBlock_.getColour();
const borderColour = this.sourceBlock_.isShadow() ?
(this.sourceBlock_.getParent() as BlockSvg).style.colourTertiary :
const primaryColour = this.getSourceBlock().isShadow() ?
this.getSourceBlock().getParent()!.getColour() :
this.getSourceBlock().getColour();
const borderColour = this.getSourceBlock().isShadow() ?
(this.getSourceBlock().getParent() as BlockSvg).style.colourTertiary :
(this.sourceBlock_ as BlockSvg).style.colourTertiary;
if (!borderColour) {
throw new Error(
@@ -326,7 +326,7 @@ export class FieldDropdown extends Field {
}
const menuItem = new MenuItem(content, value);
menuItem.setRole(aria.Role.OPTION);
menuItem.setRightToLeft(this.sourceBlock_.RTL);
menuItem.setRightToLeft(this.getSourceBlock().RTL);
menuItem.setCheckable(true);
menu.addChild(menuItem);
menuItem.setChecked(value === this.value_);
@@ -532,7 +532,7 @@ export class FieldDropdown extends Field {
/** Draws the border with the correct width. */
protected override render_() {
// Hide both elements.
this.textContent_.nodeValue = '';
this.getTextContent().nodeValue = '';
this.imageElement_!.style.display = 'none';
// Show correct element.
@@ -590,12 +590,12 @@ export class FieldDropdown extends Field {
this.size_.height = height;
let arrowX = 0;
if (this.sourceBlock_.RTL) {
if (this.getSourceBlock().RTL) {
const imageX = xPadding + arrowWidth;
this.imageElement_!.setAttribute('x', imageX.toString());
} else {
arrowX = imageWidth + arrowWidth;
this.textElement_.setAttribute('text-anchor', 'end');
this.getTextElement().setAttribute('text-anchor', 'end');
this.imageElement_!.setAttribute('x', xPadding.toString());
}
this.imageElement_!.setAttribute(
@@ -607,9 +607,10 @@ export class FieldDropdown extends Field {
/** Renders the selected option, which must be text. */
private renderSelectedText_() {
// Retrieves the selected option to display through getText_.
this.textContent_.nodeValue = this.getDisplayText_();
dom.addClass(this.textElement_, 'blocklyDropdownText');
this.textElement_.setAttribute('text-anchor', 'start');
this.getTextContent().nodeValue = this.getDisplayText_();
const textElement = this.getTextElement();
dom.addClass(textElement, 'blocklyDropdownText');
textElement.setAttribute('text-anchor', 'start');
// Height and width include the border rect.
const hasBorder = !!this.borderRect_;
@@ -617,7 +618,7 @@ export class FieldDropdown extends Field {
hasBorder ? this.getConstants()!.FIELD_DROPDOWN_BORDER_RECT_HEIGHT : 0,
this.getConstants()!.FIELD_TEXT_HEIGHT);
const textWidth = dom.getFastTextWidth(
this.textElement_, this.getConstants()!.FIELD_TEXT_FONTSIZE,
this.getTextElement(), this.getConstants()!.FIELD_TEXT_FONTSIZE,
this.getConstants()!.FIELD_TEXT_FONTWEIGHT,
this.getConstants()!.FIELD_TEXT_FONTFAMILY);
const xPadding =
@@ -650,7 +651,7 @@ export class FieldDropdown extends Field {
hasBorder ? this.getConstants()!.FIELD_BORDER_RECT_X_PADDING : 0;
const textPadding = this.getConstants()!.FIELD_DROPDOWN_SVG_ARROW_PADDING;
const svgArrowSize = this.getConstants()!.FIELD_DROPDOWN_SVG_ARROW_SIZE;
const arrowX = this.sourceBlock_.RTL ? xPadding : x + textPadding;
const arrowX = this.getSourceBlock().RTL ? xPadding : x + textPadding;
this.svgArrow_.setAttribute(
'transform', 'translate(' + arrowX + ',' + y + ')');
return svgArrowSize + textPadding;

View File

@@ -76,7 +76,7 @@ export class FieldLabel extends Field {
override initView() {
this.createTextElement_();
if (this.class_) {
dom.addClass(this.textElement_, this.class_);
dom.addClass(this.getTextElement(), this.class_);
}
}

View File

@@ -189,8 +189,8 @@ export class FieldMultilineInput extends FieldTextInput {
textLines += '\n';
}
}
if (this.sourceBlock_.RTL) {
// The SVG is LTR, force value to be RTL by adding an RLM.
if (this.getSourceBlock().RTL) {
// The SVG is LTR, force value to be RTL.
textLines += '\u200F';
}
return textLines;
@@ -248,7 +248,7 @@ export class FieldMultilineInput extends FieldTextInput {
this.updateSize_();
if (this.isBeingEdited_) {
if (this.sourceBlock_.RTL) {
if (this.getSourceBlock().RTL) {
// in RTL, we need to let the browser reflow before resizing
// in order to get the correct bounding box of the borderRect
// avoiding issue #2777.

View File

@@ -133,7 +133,7 @@ export class FieldTextInput extends Field {
let nFields = 0;
let nConnections = 0;
// Count the number of fields, excluding text fields
for (let i = 0, input; input = this.sourceBlock_.inputList[i]; i++) {
for (let i = 0, input; input = this.getSourceBlock().inputList[i]; i++) {
for (let j = 0; input.fieldRow[j]; j++) {
nFields++;
}
@@ -143,8 +143,8 @@ export class FieldTextInput extends Field {
}
// The special case is when this is the only non-label field on the block
// and it has an output but no inputs.
this.fullBlockClickTarget_ =
nFields <= 1 && this.sourceBlock_.outputConnection && !nConnections;
this.fullBlockClickTarget_ = nFields <= 1 &&
this.getSourceBlock().outputConnection && !nConnections;
} else {
this.fullBlockClickTarget_ = false;
}
@@ -311,7 +311,8 @@ export class FieldTextInput extends Field {
* @param quietInput True if editor should be created without focus.
*/
private showInlineEditor_(quietInput: boolean) {
WidgetDiv.show(this, this.sourceBlock_.RTL, this.widgetDispose_.bind(this));
WidgetDiv.show(
this, this.getSourceBlock().RTL, this.widgetDispose_.bind(this));
this.htmlInput_ = this.widgetCreate_() as HTMLInputElement;
this.isBeingEdited_ = true;
@@ -332,7 +333,9 @@ export class FieldTextInput extends Field {
eventUtils.setGroup(true);
const div = WidgetDiv.getDiv();
dom.addClass(this.getClickTarget_(), 'editing');
const clickTarget = this.getClickTarget_();
if (!clickTarget) throw new Error('A click target has not been set.');
dom.addClass(clickTarget, 'editing');
const htmlInput = (document.createElement('input'));
htmlInput.className = 'blocklyHtmlInput';
@@ -352,8 +355,8 @@ export class FieldTextInput extends Field {
// Override border radius.
borderRadius = (bBox.bottom - bBox.top) / 2 + 'px';
// Pull stroke colour from the existing shadow block
const strokeColour = this.sourceBlock_.getParent() ?
(this.sourceBlock_.getParent() as BlockSvg).style.colourTertiary :
const strokeColour = this.getSourceBlock().getParent() ?
(this.getSourceBlock().getParent() as BlockSvg).style.colourTertiary :
(this.sourceBlock_ as BlockSvg).style.colourTertiary;
htmlInput.style.border = 1 * scale + 'px solid ' + strokeColour;
div!.style.borderRadius = borderRadius;
@@ -401,7 +404,9 @@ export class FieldTextInput extends Field {
style.boxShadow = '';
this.htmlInput_ = null;
dom.removeClass(this.getClickTarget_(), 'editing');
const clickTarget = this.getClickTarget_();
if (!clickTarget) throw new Error('A click target has not been set.');
dom.removeClass(clickTarget, 'editing');
}
/**
@@ -516,7 +521,8 @@ export class FieldTextInput extends Field {
// In RTL mode block fields and LTR input fields the left edge moves,
// whereas the right edge is fixed. Reposition the editor.
const x = this.sourceBlock_.RTL ? bBox.right - div!.offsetWidth : bBox.left;
const x =
this.getSourceBlock().RTL ? bBox.right - div!.offsetWidth : bBox.left;
const xy = new Coordinate(x, bBox.top);
div!.style.left = xy.x + 'px';

View File

@@ -139,7 +139,7 @@ export class FieldVariable extends FieldDropdown {
return; // Initialization already happened.
}
const variable = Variables.getOrCreateVariablePackage(
this.sourceBlock_.workspace, null, this.defaultVariableName,
this.getSourceBlock().workspace, null, this.defaultVariableName,
this.defaultType_);
// Don't call setValue because we don't want to cause a rerender.
this.doValueUpdate_(variable.getId());
@@ -148,7 +148,7 @@ export class FieldVariable extends FieldDropdown {
override shouldAddBorderRect_() {
return super.shouldAddBorderRect_() &&
(!this.getConstants()!.FIELD_DROPDOWN_NO_BORDER_RECT_SHADOW ||
this.sourceBlock_.type !== 'variables_get');
this.getSourceBlock().type !== 'variables_get');
}
/**
@@ -168,7 +168,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.getSourceBlock().workspace, id, variableName as AnyDuringMigration,
variableType);
// This should never happen :)
@@ -238,7 +238,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.getSourceBlock().workspace, state['id'] || null, state['name'],
state['type'] || '');
this.setValue(variable.getId());
}
@@ -316,7 +316,8 @@ 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.getSourceBlock().workspace, newId);
if (!variable) {
console.warn(
'Variable id doesn\'t point to a real variable! ' +
@@ -343,7 +344,7 @@ export class FieldVariable extends FieldDropdown {
*/
protected override doValueUpdate_(newId: AnyDuringMigration) {
this.variable_ =
Variables.getVariable(this.sourceBlock_.workspace, newId as string);
Variables.getVariable(this.getSourceBlock().workspace, newId as string);
super.doValueUpdate_(newId);
}

View File

@@ -295,7 +295,7 @@ export class Drawer {
*/
protected layoutField_(fieldInfo: Icon|Field) {
const svgGroup = Types.isField(fieldInfo) ?
(fieldInfo as Field).field.getSvgRoot() :
(fieldInfo as Field).field.getSvgRoot()! :
(fieldInfo as Icon).icon.iconGroup_!; // Never null in rendered case.
const yPos = fieldInfo.centerline - fieldInfo.height / 2;

View File

@@ -247,7 +247,7 @@ export function bindMouseEvents(element: Element) {
* @param element SVG element onto which tooltip is bound.
* @alias Blockly.Tooltip.unbindMouseEvents
*/
export function unbindMouseEvents(element: Element) {
export function unbindMouseEvents(element: Element|null) {
if (!element) {
return;
}