mirror of
https://github.com/google/blockly.git
synced 2026-01-07 00:50:27 +01:00
refactor: add better types to field configs (#6317)
* fix: add config types in all fields * fix: add interfaces to fromJson * chore: cleanup from cherry-pick * chore: add docs to exported properties * chore: format * chore: remove unnecessary test case * fix: replacing message references in tooltip * chore: fix format * chore: rename interfaces to be more explicit * chore: format * fix: add proper visibility keywords * chore: fix label field config name * chore: formatting * chore: remove unnecessarily renamed imports
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
(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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
(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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 = '';
|
||||
(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;
|
||||
}
|
||||
|
||||
@@ -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 = '';
|
||||
(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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user