diff --git a/core/field.ts b/core/field.ts index 8f4fa456d..ba1de9ef2 100644 --- a/core/field.ts +++ b/core/field.ts @@ -209,7 +209,7 @@ export abstract class Field implements IASTNodeLocationSvg, */ constructor( value: AnyDuringMigration, opt_validator?: Function|null, - opt_config?: AnyDuringMigration) { + opt_config?: FieldConfig) { /** * A generic value possessed by the field. * Should generally be non-null, only null when the field is created. @@ -237,17 +237,14 @@ export abstract class Field implements IASTNodeLocationSvg, * individual field's documentation for a list of properties this * parameter supports. */ - protected configure_(config: AnyDuringMigration) { - let tooltip = config['tooltip']; - if (typeof tooltip === 'string') { - tooltip = parsing.replaceMessageReferences(config['tooltip']); + protected configure_(config: FieldConfig) { + // TODO (#2884): Possibly add CSS class config option. + // TODO (#2885): Possibly add cursor config option. + if (config.tooltip) { + this.setTooltip(parsing.replaceMessageReferences(config.tooltip)); } - tooltip && this.setTooltip(tooltip); } - // TODO (#2884): Possibly add CSS class config option. - // TODO (#2885): Possibly add cursor config option. - /** * Attach this field to a block. * @param block The block containing this field. @@ -1200,3 +1197,10 @@ export abstract class Field implements IASTNodeLocationSvg, } } } + +/** + * Extra configuration options for the base field. + */ +export interface FieldConfig { + tooltip?: string; +} diff --git a/core/field_angle.ts b/core/field_angle.ts index 1f3880b30..f313ee6ba 100644 --- a/core/field_angle.ts +++ b/core/field_angle.ts @@ -21,7 +21,7 @@ import * as Css from './css.js'; import * as dropDownDiv from './dropdowndiv.js'; import {Field} from './field.js'; import * as fieldRegistry from './field_registry.js'; -import {FieldTextInput} from './field_textinput.js'; +import {FieldTextInputConfig, FieldTextInput} from './field_textinput.js'; import * as dom from './utils/dom.js'; import {KeyCodes} from './utils/keycodes.js'; import * as math from './utils/math.js'; @@ -121,7 +121,7 @@ export class FieldAngle extends FieldTextInput { */ constructor( opt_value?: string|number|Sentinel, opt_validator?: Function, - opt_config?: AnyDuringMigration) { + opt_config?: FieldAngleConfig) { super(Field.SKIP_SETUP); /** @@ -165,15 +165,15 @@ export class FieldAngle extends FieldTextInput { * Configure the field based on the given map of options. * @param config A map of options to configure the field based on. */ - override configure_(config: AnyDuringMigration) { + protected override configure_(config: FieldAngleConfig) { super.configure_(config); - switch (config['mode']) { - case 'compass': + switch (config.mode) { + case Mode.COMPASS: this.clockwise_ = true; this.offset_ = 90; break; - case 'protractor': + case Mode.PROTRACTOR: // This is the default mode, so we could do nothing. But just to // future-proof, we'll set it anyway. this.clockwise_ = false; @@ -182,33 +182,10 @@ export class FieldAngle extends FieldTextInput { } // Allow individual settings to override the mode setting. - const clockwise = config['clockwise']; - if (typeof clockwise === 'boolean') { - this.clockwise_ = clockwise; - } - - // If these are passed as null then we should leave them on the default. - let offset = config['offset']; - if (offset !== null) { - offset = Number(offset); - if (!isNaN(offset)) { - this.offset_ = offset; - } - } - let wrap = config['wrap']; - if (wrap !== null) { - wrap = Number(wrap); - if (!isNaN(wrap)) { - this.wrap_ = wrap; - } - } - let round = config['round']; - if (round !== null) { - round = Number(round); - if (!isNaN(round)) { - this.round_ = round; - } - } + if (config.clockwise) this.clockwise_ = config.clockwise; + if (config.offset) this.offset_ = config.offset; + if (config.wrap) this.wrap_ = config.wrap; + if (config.round) this.round_ = config.round; } /** @@ -509,10 +486,10 @@ export class FieldAngle extends FieldTextInput { * @nocollapse * @internal */ - static override fromJson(options: AnyDuringMigration): FieldAngle { + static override fromJson(options: FieldAngleFromJsonConfig): FieldAngle { // `this` might be a subclass of FieldAngle if that class doesn't override // the static fromJson method. - return new this(options['angle'], undefined, options); + return new this(options.angle, undefined, options); } } @@ -546,4 +523,41 @@ Css.register(` fieldRegistry.register('field_angle', FieldAngle); -(FieldAngle.prototype as AnyDuringMigration).DEFAULT_VALUE = 0; \ No newline at end of file +(FieldAngle.prototype as AnyDuringMigration).DEFAULT_VALUE = 0; + +/** + * The two main modes of the angle field. + * Compass specifies: + * - clockwise: true + * - offset: 90 + * - wrap: 0 + * - round: 15 + * + * Protractor specifies: + * - clockwise: false + * - offset: 0 + * - wrap: 0 + * - round: 15 + */ +export enum Mode { + COMPASS = 'compass', + PROTRACTOR = 'protractor', +} + +/** + * Extra configuration options for the angle field. + */ +export interface FieldAngleConfig extends FieldTextInputConfig { + mode?: Mode; + clockwise?: boolean; + offset?: number; + wrap?: number; + round?: number; +} + +/** + * fromJson configuration options for the angle field. + */ +export interface FieldAngleFromJsonConfig extends FieldAngleConfig { + angle?: number; +} diff --git a/core/field_checkbox.ts b/core/field_checkbox.ts index b4eb49127..e1ad4bcfd 100644 --- a/core/field_checkbox.ts +++ b/core/field_checkbox.ts @@ -18,7 +18,7 @@ goog.declareModuleId('Blockly.FieldCheckbox'); // Unused import preserved for side-effects. Remove if unneeded. import './events/events_block_change.js'; -import {Field} from './field.js'; +import {FieldConfig, Field} from './field.js'; import * as fieldRegistry from './field_registry.js'; import * as dom from './utils/dom.js'; import type {Sentinel} from './utils/sentinel.js'; @@ -61,7 +61,7 @@ export class FieldCheckbox extends Field { */ constructor( opt_value?: string|boolean|Sentinel, opt_validator?: Function, - opt_config?: AnyDuringMigration) { + opt_config?: FieldCheckboxConfig) { super(Field.SKIP_SETUP); /** @@ -86,11 +86,9 @@ export class FieldCheckbox extends Field { * Configure the field based on the given map of options. * @param config A map of options to configure the field based on. */ - protected override configure_(config: AnyDuringMigration) { + protected override configure_(config: FieldCheckboxConfig) { super.configure_(config); - if (config['checkCharacter']) { - this.checkChar_ = config['checkCharacter']; - } + if (config.checkCharacter) this.checkChar_ = config.checkCharacter; } /** @@ -219,13 +217,27 @@ export class FieldCheckbox extends Field { * @nocollapse * @internal */ - static fromJson(options: AnyDuringMigration): FieldCheckbox { + static fromJson(options: FieldCheckboxFromJsonConfig): FieldCheckbox { // `this` might be a subclass of FieldCheckbox if that class doesn't // 'override' the static fromJson method. - return new this(options['checked'], undefined, options); + return new this(options.checked, undefined, options); } } fieldRegistry.register('field_checkbox', FieldCheckbox); -(FieldCheckbox.prototype as AnyDuringMigration).DEFAULT_VALUE = false; \ No newline at end of file +(FieldCheckbox.prototype as AnyDuringMigration).DEFAULT_VALUE = false; + +/** + * Config options for the checkbox field. + */ +export interface FieldCheckboxConfig extends FieldConfig { + checkCharacter?: string; +} + +/** + * fromJson config options for the checkbox field. + */ +export interface FieldCheckboxFromJsonConfig extends FieldCheckboxConfig { + checked?: boolean; +} diff --git a/core/field_colour.ts b/core/field_colour.ts index 354f7f8c3..0e91e8a19 100644 --- a/core/field_colour.ts +++ b/core/field_colour.ts @@ -22,7 +22,7 @@ import {BlockSvg} from './block_svg.js'; import * as browserEvents from './browser_events.js'; import * as Css from './css.js'; import * as dropDownDiv from './dropdowndiv.js'; -import {Field} from './field.js'; +import {FieldConfig, Field} from './field.js'; import * as fieldRegistry from './field_registry.js'; import * as aria from './utils/aria.js'; import * as colour from './utils/colour.js'; @@ -155,7 +155,7 @@ export class FieldColour extends Field { */ constructor( opt_value?: string|Sentinel, opt_validator?: Function, - opt_config?: AnyDuringMigration) { + opt_config?: FieldColourConfig) { super(Field.SKIP_SETUP); if (opt_value === Field.SKIP_SETUP) { @@ -174,15 +174,11 @@ export class FieldColour extends Field { * Configure the field based on the given map of options. * @param config A map of options to configure the field based on. */ - protected override configure_(config: AnyDuringMigration) { + protected override configure_(config: FieldColourConfig) { super.configure_(config); - if (config['colourOptions']) { - this.colours_ = config['colourOptions']; - this.titles_ = config['colourTitles']; - } - if (config['columns']) { - this.columns_ = config['columns']; - } + if (config.colourOptions) this.colours_ = config.colourOptions; + if (config.colourTitles) this.titles_ = config.colourTitles; + if (config.columns) this.columns_ = config.columns; } /** @@ -572,7 +568,7 @@ export class FieldColour extends Field { * @nocollapse * @internal */ - static fromJson(options: AnyDuringMigration): FieldColour { + static fromJson(options: FieldColourFromJsonConfig): FieldColour { // `this` might be a subclass of FieldColour if that class doesn't override // the static fromJson method. return new this(options['colour'], undefined, options); @@ -618,3 +614,19 @@ Css.register(` `); fieldRegistry.register('field_colour', FieldColour); + +/** + * Config options for the colour field. + */ +export interface FieldColourConfig extends FieldConfig { + colourOptions?: string[]; + colourTitles?: string[]; + columns?: number; +} + +/** + * fromJson config options for the colour field. + */ +export interface FieldColourFromJsonConfig extends FieldColourConfig { + colour?: string; +} diff --git a/core/field_dropdown.ts b/core/field_dropdown.ts index b864385e6..ffb2b6195 100644 --- a/core/field_dropdown.ts +++ b/core/field_dropdown.ts @@ -21,7 +21,7 @@ goog.declareModuleId('Blockly.FieldDropdown'); import type {BlockSvg} from './block_svg.js'; import * as dropDownDiv from './dropdowndiv.js'; -import {Field} from './field.js'; +import {FieldConfig, Field} from './field.js'; import * as fieldRegistry from './field_registry.js'; import {Menu} from './menu.js'; import {MenuItem} from './menuitem.js'; @@ -117,7 +117,7 @@ export class FieldDropdown extends Field { */ constructor( menuGenerator: AnyDuringMigration[][]|Function|Sentinel, - opt_validator?: Function, opt_config?: AnyDuringMigration) { + opt_validator?: Function, opt_config?: FieldConfig) { super(Field.SKIP_SETUP); // If we pass SKIP_SETUP, don't do *anything* with the menu generator. @@ -656,10 +656,16 @@ export class FieldDropdown extends Field { * @nocollapse * @internal */ - static fromJson(options: AnyDuringMigration): FieldDropdown { + static fromJson(options: FieldDropdownFromJsonConfig): FieldDropdown { + if (!options.options) { + throw new Error( + 'options are required for the dropdown field. The ' + + 'options property must be assigned an array of ' + + '[humanReadableValue, languageNeutralValue] tuples.'); + } // `this` might be a subclass of FieldDropdown if that class doesn't // override the static fromJson method. - return new this(options['options'], undefined, options); + return new this(options.options, undefined, options); } /** @@ -686,14 +692,30 @@ export class FieldDropdown extends Field { } } -/** Dropdown image properties. */ -interface ImageProperties { +/** + * Definition of a human-readable image dropdown option. + */ +export interface ImageProperties { src: string; alt: string; width: number; height: number; } +/** + * An individual option in the dropdown menu. The first element is the human- + * readable value (text or image), and the second element is the language- + * neutral value. + */ +export type MenuOption = [string | ImageProperties, string]; + +/** + * fromJson config for the dropdown field. + */ +export interface FieldDropdownFromJsonConfig extends FieldConfig { + options?: MenuOption[]; +} + /** * The y offset from the top of the field to the top of the image, if an image * is selected. diff --git a/core/field_image.ts b/core/field_image.ts index 7e81de0be..cad0e6b1e 100644 --- a/core/field_image.ts +++ b/core/field_image.ts @@ -15,7 +15,7 @@ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.FieldImage'); -import {Field} from './field.js'; +import {FieldConfig, Field} from './field.js'; import * as fieldRegistry from './field_registry.js'; import * as dom from './utils/dom.js'; import * as parsing from './utils/parsing.js'; @@ -84,13 +84,9 @@ export class FieldImage extends Field { constructor( src: string|Sentinel, width: string|number, height: string|number, opt_alt?: string, opt_onClick?: (p1: FieldImage) => AnyDuringMigration, - opt_flipRtl?: boolean, opt_config?: AnyDuringMigration) { + opt_flipRtl?: boolean, opt_config?: FieldImageConfig) { super(Field.SKIP_SETUP); - // Return early. - if (!src) { - throw Error('Src value of an image field is required'); - } const imageHeight = Number(parsing.replaceMessageReferences(height)); const imageWidth = Number(parsing.replaceMessageReferences(width)); if (isNaN(imageHeight) || isNaN(imageWidth)) { @@ -133,10 +129,12 @@ export class FieldImage extends Field { * Configure the field based on the given map of options. * @param config A map of options to configure the field based on. */ - protected override configure_(config: AnyDuringMigration) { + protected override configure_(config: FieldImageConfig) { super.configure_(config); - this.flipRtl_ = !!config['flipRtl']; - this.altText_ = parsing.replaceMessageReferences(config['alt']) || ''; + if (config.flipRtl) this.flipRtl_ = config.flipRtl; + if (config.alt) { + this.altText_ = parsing.replaceMessageReferences(config.alt); + } } /** @@ -248,15 +246,37 @@ export class FieldImage extends Field { * @nocollapse * @internal */ - static fromJson(options: AnyDuringMigration): FieldImage { + static fromJson(options: FieldImageFromJsonConfig): FieldImage { + if (!options.src || !options.width || !options.height) { + throw new Error( + 'src, width, and height values for an image field are' + + 'required. The width and height must be non-zero.'); + } // `this` might be a subclass of FieldImage if that class doesn't override // the static fromJson method. return new this( - options['src'], options['width'], options['height'], undefined, - undefined, undefined, options); + options.src, options.width, options.height, undefined, undefined, + undefined, options); } } fieldRegistry.register('field_image', FieldImage); -(FieldImage.prototype as AnyDuringMigration).DEFAULT_VALUE = ''; \ No newline at end of file +(FieldImage.prototype as AnyDuringMigration).DEFAULT_VALUE = ''; + +/** + * Config options for the image field. + */ +export interface FieldImageConfig extends FieldConfig { + flipRtl?: boolean; + alt?: string; +} + +/** + * fromJson config options for the colour field. + */ +export interface FieldImageFromJsonConfig extends FieldImageConfig { + src?: string; + width?: number; + height?: number; +} diff --git a/core/field_label.ts b/core/field_label.ts index 0e03c11cb..f464fef6b 100644 --- a/core/field_label.ts +++ b/core/field_label.ts @@ -17,7 +17,7 @@ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.FieldLabel'); -import {Field} from './field.js'; +import {FieldConfig, Field} from './field.js'; import * as fieldRegistry from './field_registry.js'; import * as dom from './utils/dom.js'; import * as parsing from './utils/parsing.js'; @@ -52,7 +52,7 @@ export class FieldLabel extends Field { */ constructor( opt_value?: string|Sentinel, opt_class?: string, - opt_config?: AnyDuringMigration) { + opt_config?: FieldLabelConfig) { super(Field.SKIP_SETUP); if (opt_value === Field.SKIP_SETUP) { @@ -66,9 +66,9 @@ export class FieldLabel extends Field { this.setValue(opt_value); } - override configure_(config: AnyDuringMigration) { + protected override configure_(config: FieldLabelConfig) { super.configure_(config); - this.class_ = config['class']; + if (config.class) this.class_ = config.class; } /** @@ -121,8 +121,8 @@ export class FieldLabel extends Field { * @nocollapse * @internal */ - static fromJson(options: AnyDuringMigration): FieldLabel { - const text = parsing.replaceMessageReferences(options['text']); + static fromJson(options: FieldLabelFromJsonConfig): FieldLabel { + const text = parsing.replaceMessageReferences(options.text); // `this` might be a subclass of FieldLabel if that class doesn't override // the static fromJson method. return new this(text, undefined, options); @@ -131,4 +131,22 @@ export class FieldLabel extends Field { fieldRegistry.register('field_label', FieldLabel); -(FieldLabel.prototype as AnyDuringMigration).DEFAULT_VALUE = ''; \ No newline at end of file +(FieldLabel.prototype as AnyDuringMigration).DEFAULT_VALUE = ''; + +// clang-format off +// Clang does not like the 'class' keyword being used as a property. +/** + * Config options for the label field. + */ +export interface FieldLabelConfig extends FieldConfig { + class?: string; +} +// clang-format on + + +/** + * fromJson config options for the label field. + */ +export interface FieldLabelFromJsonConfig extends FieldLabelConfig { + text?: string; +} diff --git a/core/field_label_serializable.ts b/core/field_label_serializable.ts index 51b300b05..3ff52f262 100644 --- a/core/field_label_serializable.ts +++ b/core/field_label_serializable.ts @@ -19,7 +19,7 @@ import * as goog from '../closure/goog/goog.js'; goog.declareModuleId('Blockly.FieldLabelSerializable'); -import {FieldLabel} from './field_label.js'; +import {FieldLabelConfig, FieldLabelFromJsonConfig, FieldLabel} from './field_label.js'; import * as fieldRegistry from './field_registry.js'; import * as parsing from './utils/parsing.js'; @@ -52,7 +52,7 @@ export class FieldLabelSerializable extends FieldLabel { * for a list of properties this parameter supports. */ constructor( - opt_value?: string, opt_class?: string, opt_config?: AnyDuringMigration) { + opt_value?: string, opt_class?: string, opt_config?: FieldLabelConfig) { super(String(opt_value ?? ''), opt_class, opt_config); } @@ -64,9 +64,9 @@ export class FieldLabelSerializable extends FieldLabel { * @nocollapse * @internal */ - static override fromJson(options: AnyDuringMigration): + static override fromJson(options: FieldLabelFromJsonConfig): FieldLabelSerializable { - const text = parsing.replaceMessageReferences(options['text']); + const text = parsing.replaceMessageReferences(options.text); // `this` might be a subclass of FieldLabelSerializable if that class // doesn't override the static fromJson method. return new this(text, undefined, options); diff --git a/core/field_multilineinput.ts b/core/field_multilineinput.ts index 55dcc4a85..7835816dd 100644 --- a/core/field_multilineinput.ts +++ b/core/field_multilineinput.ts @@ -18,7 +18,7 @@ goog.declareModuleId('Blockly.FieldMultilineInput'); import * as Css from './css.js'; import {Field} from './field.js'; import * as fieldRegistry from './field_registry.js'; -import {FieldTextInput} from './field_textinput.js'; +import {FieldTextInputConfig, FieldTextInput} from './field_textinput.js'; import * as aria from './utils/aria.js'; import * as dom from './utils/dom.js'; import {KeyCodes} from './utils/keycodes.js'; @@ -68,7 +68,7 @@ export class FieldMultilineInput extends FieldTextInput { */ constructor( opt_value?: string|Sentinel, opt_validator?: Function, - opt_config?: AnyDuringMigration) { + opt_config?: FieldMultilineInputConfig) { super(Field.SKIP_SETUP); if (opt_value === Field.SKIP_SETUP) { @@ -83,9 +83,9 @@ export class FieldMultilineInput extends FieldTextInput { } } - override configure_(config: AnyDuringMigration) { + protected override configure_(config: FieldMultilineInputConfig) { super.configure_(config); - config['maxLines'] && this.setMaxLines(config['maxLines']); + if (config.maxLines) this.setMaxLines(config.maxLines); } /** @@ -424,8 +424,9 @@ export class FieldMultilineInput extends FieldTextInput { * @nocollapse * @internal */ - static override fromJson(options: AnyDuringMigration): FieldMultilineInput { - const text = parsing.replaceMessageReferences(options['text']); + static override fromJson(options: FieldMultilineInputFromJsonConfig): + FieldMultilineInput { + const text = parsing.replaceMessageReferences(options.text); // `this` might be a subclass of FieldMultilineInput if that class doesn't // override the static fromJson method. return new this(text, undefined, options); @@ -448,3 +449,18 @@ Css.register(` `); fieldRegistry.register('field_multilinetext', FieldMultilineInput); + +/** + * Config options for the multiline input field. + */ +export interface FieldMultilineInputConfig extends FieldTextInputConfig { + maxLines?: number; +} + +/** + * fromJson config options for the multiline input field. + */ +export interface FieldMultilineInputFromJsonConfig extends + FieldMultilineInputConfig { + text?: string; +} diff --git a/core/field_number.ts b/core/field_number.ts index dd0938782..0285b2a15 100644 --- a/core/field_number.ts +++ b/core/field_number.ts @@ -17,7 +17,7 @@ goog.declareModuleId('Blockly.FieldNumber'); import {Field} from './field.js'; import * as fieldRegistry from './field_registry.js'; -import {FieldTextInput} from './field_textinput.js'; +import {FieldTextInputConfig, FieldTextInput} from './field_textinput.js'; import * as aria from './utils/aria.js'; import type {Sentinel} from './utils/sentinel.js'; @@ -70,7 +70,7 @@ export class FieldNumber extends FieldTextInput { constructor( opt_value?: string|number|Sentinel, opt_min?: string|number|null, opt_max?: string|number|null, opt_precision?: string|number|null, - opt_validator?: Function|null, opt_config?: AnyDuringMigration) { + opt_validator?: Function|null, opt_config?: FieldNumberConfig) { // Pass SENTINEL so that we can define properties before value validation. super(Field.SKIP_SETUP); @@ -92,11 +92,11 @@ export class FieldNumber extends FieldTextInput { * Configure the field based on the given map of options. * @param config A map of options to configure the field based on. */ - override configure_(config: AnyDuringMigration) { + protected override configure_(config: FieldNumberConfig) { super.configure_(config); - this.setMinInternal_(config['min']); - this.setMaxInternal_(config['max']); - this.setPrecisionInternal_(config['precision']); + this.setMinInternal_(config.min); + this.setMaxInternal_(config.max); + this.setPrecisionInternal_(config.precision); } /** @@ -298,14 +298,30 @@ export class FieldNumber extends FieldTextInput { * @nocollapse * @internal */ - static override fromJson(options: AnyDuringMigration): FieldNumber { + static override fromJson(options: FieldNumberFromJsonConfig): FieldNumber { // `this` might be a subclass of FieldNumber if that class doesn't override // the static fromJson method. return new this( - options['value'], undefined, undefined, undefined, undefined, options); + options.value, undefined, undefined, undefined, undefined, options); } } fieldRegistry.register('field_number', FieldNumber); (FieldNumber.prototype as AnyDuringMigration).DEFAULT_VALUE = 0; + +/** + * Config options for the number field. + */ +export interface FieldNumberConfig extends FieldTextInputConfig { + min?: number; + max?: number; + precision?: number; +} + +/** + * fromJson config options for the number field. + */ +export interface FieldNumberFromJsonConfig extends FieldNumberConfig { + value?: number; +} diff --git a/core/field_textinput.ts b/core/field_textinput.ts index f154485a8..ed36b6eba 100644 --- a/core/field_textinput.ts +++ b/core/field_textinput.ts @@ -23,7 +23,7 @@ import * as browserEvents from './browser_events.js'; import * as dialog from './dialog.js'; import * as dropDownDiv from './dropdowndiv.js'; import * as eventUtils from './events/utils.js'; -import {Field} from './field.js'; +import {FieldConfig, Field} from './field.js'; import * as fieldRegistry from './field_registry.js'; import {Msg} from './msg.js'; import * as aria from './utils/aria.js'; @@ -105,7 +105,7 @@ export class FieldTextInput extends Field { */ constructor( opt_value?: string|Sentinel, opt_validator?: Function|null, - opt_config?: AnyDuringMigration) { + opt_config?: FieldTextInputConfig) { super(Field.SKIP_SETUP); if (opt_value === Field.SKIP_SETUP) { @@ -120,10 +120,10 @@ export class FieldTextInput extends Field { } } - override configure_(config: AnyDuringMigration) { + protected override configure_(config: FieldTextInputConfig) { super.configure_(config); - if (typeof config['spellcheck'] === 'boolean') { - this.spellcheck_ = config['spellcheck']; + if (config.spellcheck !== undefined) { + this.spellcheck_ = config.spellcheck; } } @@ -564,8 +564,8 @@ export class FieldTextInput extends Field { * @nocollapse * @internal */ - static fromJson(options: AnyDuringMigration): FieldTextInput { - const text = parsing.replaceMessageReferences(options['text']); + static fromJson(options: FieldTextInputFromJsonConfig): FieldTextInput { + const text = parsing.replaceMessageReferences(options.text); // `this` might be a subclass of FieldTextInput if that class doesn't // override the static fromJson method. return new this(text, undefined, options); @@ -575,3 +575,17 @@ export class FieldTextInput extends Field { fieldRegistry.register('field_input', FieldTextInput); (FieldTextInput.prototype as AnyDuringMigration).DEFAULT_VALUE = ''; + +/** + * Config options for the text input field. + */ +export interface FieldTextInputConfig extends FieldConfig { + spellcheck?: boolean; +} + +/** + * fromJson config options for the text input field. + */ +export interface FieldTextInputFromJsonConfig extends FieldTextInputConfig { + text?: string; +} diff --git a/core/field_variable.ts b/core/field_variable.ts index 39fe3f3ba..bd118ef3e 100644 --- a/core/field_variable.ts +++ b/core/field_variable.ts @@ -19,7 +19,7 @@ goog.declareModuleId('Blockly.FieldVariable'); import './events/events_block_change.js'; import type {Block} from './block.js'; -import {Field} from './field.js'; +import {Field, FieldConfig} from './field.js'; import {FieldDropdown} from './field_dropdown.js'; import * as fieldRegistry from './field_registry.js'; import * as internalConstants from './internal_constants.js'; @@ -84,7 +84,7 @@ export class FieldVariable extends FieldDropdown { constructor( varName: string|null|Sentinel, opt_validator?: Function, opt_variableTypes?: string[], opt_defaultType?: string, - opt_config?: AnyDuringMigration) { + opt_config?: FieldVariableConfig) { super(Field.SKIP_SETUP); /** @@ -123,9 +123,9 @@ export class FieldVariable extends FieldDropdown { * Configure the field based on the given map of options. * @param config A map of options to configure the field based on. */ - protected override configure_(config: AnyDuringMigration) { + protected override configure_(config: FieldVariableConfig) { super.configure_(config); - this.setTypes_(config['variableTypes'], config['defaultType']); + this.setTypes_(config.variableTypes, config.defaultType); } /** @@ -475,8 +475,9 @@ export class FieldVariable extends FieldDropdown { * @nocollapse * @internal */ - static override fromJson(options: AnyDuringMigration): FieldVariable { - const varName = parsing.replaceMessageReferences(options['variable']); + static override fromJson(options: FieldVariableFromJsonConfig): + FieldVariable { + const varName = parsing.replaceMessageReferences(options.variable); // `this` might be a subclass of FieldVariable if that class doesn't // override the static fromJson method. return new this(varName, undefined, undefined, undefined, options); @@ -527,3 +528,18 @@ export class FieldVariable extends FieldDropdown { } fieldRegistry.register('field_variable', FieldVariable); + +/** + * Config options for the variable field. + */ +export interface FieldVariableConfig extends FieldConfig { + variableTypes?: string[]; + defaultType?: string; +} + +/** + * fromJson config options for the variable field. + */ +export interface FieldVariableFromJsonConfig extends FieldVariableConfig { + variable?: string; +} diff --git a/tests/mocha/field_image_test.js b/tests/mocha/field_image_test.js index 62826398a..4a20a790f 100644 --- a/tests/mocha/field_image_test.js +++ b/tests/mocha/field_image_test.js @@ -22,7 +22,6 @@ suite('Image Fields', function() { * @type {!Array} */ const invalidValueTestCases = [ - {title: 'Undefined Src', value: undefined, args: [undefined, 1, 1]}, {title: 'Undefined Size', value: 'src', args: ['src', undefined, undefined]}, {title: 'Zero Size', value: 'src', args: ['src', 0, 0]}, {title: 'Non-Parsable String for Size', value: 'src', args: ['src', 'bad', 'bad']},