mirror of
https://github.com/google/blockly.git
synced 2026-01-09 10:00:09 +01:00
Merge branch 'develop' into merge-v11
This commit is contained in:
@@ -1086,14 +1086,22 @@ export abstract class Field<T = any>
|
||||
}
|
||||
|
||||
const classValidation = this.doClassValidation_(newValue);
|
||||
const classValue = this.processValidation_(newValue, classValidation);
|
||||
const classValue = this.processValidation_(
|
||||
newValue,
|
||||
classValidation,
|
||||
fireChangeEvent,
|
||||
);
|
||||
if (classValue instanceof Error) {
|
||||
doLogging && console.log('invalid class validation, return');
|
||||
return;
|
||||
}
|
||||
|
||||
const localValidation = this.getValidator()?.call(this, classValue);
|
||||
const localValue = this.processValidation_(classValue, localValidation);
|
||||
const localValue = this.processValidation_(
|
||||
classValue,
|
||||
localValidation,
|
||||
fireChangeEvent,
|
||||
);
|
||||
if (localValue instanceof Error) {
|
||||
doLogging && console.log('invalid local validation, return');
|
||||
return;
|
||||
@@ -1135,14 +1143,16 @@ export abstract class Field<T = any>
|
||||
*
|
||||
* @param newValue New value.
|
||||
* @param validatedValue Validated value.
|
||||
* @param fireChangeEvent Whether to fire a change event if the value changes.
|
||||
* @returns New value, or an Error object.
|
||||
*/
|
||||
private processValidation_(
|
||||
newValue: AnyDuringMigration,
|
||||
validatedValue: T | null | undefined,
|
||||
fireChangeEvent: boolean,
|
||||
): T | Error {
|
||||
if (validatedValue === null) {
|
||||
this.doValueInvalid_(newValue);
|
||||
this.doValueInvalid_(newValue, fireChangeEvent);
|
||||
if (this.isDirty_) {
|
||||
this.forceRerender();
|
||||
}
|
||||
@@ -1209,8 +1219,12 @@ export abstract class Field<T = any>
|
||||
* No-op by default.
|
||||
*
|
||||
* @param _invalidValue The input value that was determined to be invalid.
|
||||
* @param _fireChangeEvent Whether to fire a change event if the value changes.
|
||||
*/
|
||||
protected doValueInvalid_(_invalidValue: AnyDuringMigration) {}
|
||||
protected doValueInvalid_(
|
||||
_invalidValue: AnyDuringMigration,
|
||||
_fireChangeEvent: boolean = true,
|
||||
) {}
|
||||
// NOP
|
||||
|
||||
/**
|
||||
@@ -1419,6 +1433,22 @@ export abstract class Field<T = any>
|
||||
workspace.getMarker(MarkerManager.LOCAL_MARKER)!.draw();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses should reimplement this method to construct their Field
|
||||
* subclass from a JSON arg object.
|
||||
*
|
||||
* It is an error to attempt to register a field subclass in the
|
||||
* FieldRegistry if that subclass has not overridden this method.
|
||||
*
|
||||
* @param _options JSON configuration object with properties needed
|
||||
* to configure a specific field.
|
||||
*/
|
||||
static fromJson(_options: FieldConfig): Field {
|
||||
throw new Error(
|
||||
`Attempted to instantiate a field from the registry that hasn't defined a 'fromJson' method.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1429,12 +1459,14 @@ export interface FieldConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* For use by Field and descendants of Field. Constructors can change
|
||||
* Represents an object that has all the prototype properties of the `Field`
|
||||
* class. This is necessary because constructors can change
|
||||
* in descendants, though they should contain all of Field's prototype methods.
|
||||
*
|
||||
* @internal
|
||||
* This type should only be used in places where we directly access the prototype
|
||||
* of a Field class or subclass.
|
||||
*/
|
||||
export type FieldProto = Pick<typeof Field, 'prototype'>;
|
||||
type FieldProto = Pick<typeof Field, 'prototype'>;
|
||||
|
||||
/**
|
||||
* Represents an error where the field is trying to access its block or
|
||||
|
||||
@@ -226,7 +226,9 @@ export class FieldCheckbox extends Field<CheckboxBool> {
|
||||
* @nocollapse
|
||||
* @internal
|
||||
*/
|
||||
static fromJson(options: FieldCheckboxFromJsonConfig): FieldCheckbox {
|
||||
static override 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);
|
||||
|
||||
@@ -229,6 +229,9 @@ export class FieldDropdown extends Field<string> {
|
||||
: ' ' + FieldDropdown.ARROW_CHAR,
|
||||
),
|
||||
);
|
||||
if (this.getConstants()!.FIELD_TEXT_BASELINE_CENTER) {
|
||||
this.arrow.setAttribute('dominant-baseline', 'central');
|
||||
}
|
||||
if (this.getSourceBlock()?.RTL) {
|
||||
this.getTextElement().insertBefore(this.arrow, this.textContent_);
|
||||
} else {
|
||||
@@ -644,7 +647,9 @@ export class FieldDropdown extends Field<string> {
|
||||
* @nocollapse
|
||||
* @internal
|
||||
*/
|
||||
static fromJson(options: FieldDropdownFromJsonConfig): FieldDropdown {
|
||||
static override fromJson(
|
||||
options: FieldDropdownFromJsonConfig,
|
||||
): FieldDropdown {
|
||||
if (!options.options) {
|
||||
throw new Error(
|
||||
'options are required for the dropdown field. The ' +
|
||||
|
||||
@@ -250,7 +250,7 @@ export class FieldImage extends Field<string> {
|
||||
* @nocollapse
|
||||
* @internal
|
||||
*/
|
||||
static fromJson(options: FieldImageFromJsonConfig): FieldImage {
|
||||
static override fromJson(options: FieldImageFromJsonConfig): FieldImage {
|
||||
if (!options.src || !options.width || !options.height) {
|
||||
throw new Error(
|
||||
'src, width, and height values for an image field are' +
|
||||
|
||||
@@ -166,17 +166,26 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
|
||||
* value while allowing the display text to be handled by the htmlInput_.
|
||||
*
|
||||
* @param _invalidValue The input value that was determined to be invalid.
|
||||
* This is not used by the text input because its display value is stored
|
||||
* on the htmlInput_.
|
||||
* This is not used by the text input because its display value is stored
|
||||
* on the htmlInput_.
|
||||
* @param fireChangeEvent Whether to fire a change event if the value changes.
|
||||
*/
|
||||
protected override doValueInvalid_(_invalidValue: AnyDuringMigration) {
|
||||
protected override doValueInvalid_(
|
||||
_invalidValue: AnyDuringMigration,
|
||||
fireChangeEvent: boolean = true,
|
||||
) {
|
||||
if (this.isBeingEdited_) {
|
||||
this.isDirty_ = true;
|
||||
this.isTextValid_ = false;
|
||||
const oldValue = this.value_;
|
||||
// Revert value when the text becomes invalid.
|
||||
this.value_ = this.htmlInput_!.getAttribute('data-untyped-default-value');
|
||||
if (this.sourceBlock_ && eventUtils.isEnabled()) {
|
||||
this.value_ = this.valueWhenEditorWasOpened_;
|
||||
if (
|
||||
this.sourceBlock_ &&
|
||||
eventUtils.isEnabled() &&
|
||||
this.value_ !== oldValue &&
|
||||
fireChangeEvent
|
||||
) {
|
||||
eventUtils.fire(
|
||||
new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
|
||||
this.sourceBlock_,
|
||||
@@ -566,7 +575,10 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
|
||||
// intermediate changes that do not get recorded in undo history.
|
||||
const oldValue = this.value_;
|
||||
// Change the field's value without firing the normal change event.
|
||||
this.setValue(this.getValueFromEditorText_(this.htmlInput_!.value), false);
|
||||
this.setValue(
|
||||
this.getValueFromEditorText_(this.htmlInput_!.value),
|
||||
/* fireChangeEvent= */ false,
|
||||
);
|
||||
if (
|
||||
this.sourceBlock_ &&
|
||||
eventUtils.isEnabled() &&
|
||||
|
||||
@@ -117,7 +117,7 @@ export class FieldLabel extends Field<string> {
|
||||
* @nocollapse
|
||||
* @internal
|
||||
*/
|
||||
static fromJson(options: FieldLabelFromJsonConfig): FieldLabel {
|
||||
static override 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.
|
||||
|
||||
@@ -315,7 +315,7 @@ export class FieldNumber extends FieldInput<number> {
|
||||
* @nocollapse
|
||||
* @internal
|
||||
*/
|
||||
static fromJson(options: FieldNumberFromJsonConfig): 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(
|
||||
|
||||
@@ -6,12 +6,46 @@
|
||||
|
||||
// Former goog.module ID: Blockly.fieldRegistry
|
||||
|
||||
import type {Field, FieldProto} from './field.js';
|
||||
import type {Field, FieldConfig} from './field.js';
|
||||
import * as registry from './registry.js';
|
||||
|
||||
interface RegistryOptions {
|
||||
/**
|
||||
* When constructing a field from JSON using the registry, the
|
||||
* `fromJson` method in this file is called with an options parameter
|
||||
* object consisting of the "type" which is the name of the field, and
|
||||
* other options that are part of the field's config object.
|
||||
*
|
||||
* These options are then passed to the field's static `fromJson`
|
||||
* method. That method accepts an options parameter with a type that usually
|
||||
* extends from FieldConfig, and may or may not have a "type" attribute (in
|
||||
* fact, it shouldn't, because we'd overwrite it as described above!)
|
||||
*
|
||||
* Unfortunately the registry has no way of knowing the actual Field subclass
|
||||
* that will be returned from passing in the name of the field. Therefore it
|
||||
* also has no way of knowing that the options object not only implements
|
||||
* `FieldConfig`, but it also should satisfy the Config that belongs to that
|
||||
* specific class's `fromJson` method.
|
||||
*
|
||||
* Because of this uncertainty, we just give up on type checking the properties
|
||||
* passed to the `fromJson` method, and allow arbitrary string keys with
|
||||
* unknown types.
|
||||
*/
|
||||
type RegistryOptions = FieldConfig & {
|
||||
// The name of the field, e.g. field_dropdown
|
||||
type: string;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents the static methods that must be defined on any
|
||||
* field that is registered, i.e. the constructor and fromJson methods.
|
||||
*
|
||||
* Because we don't know which Field subclass will be registered, we
|
||||
* are unable to typecheck the parameters of the constructor.
|
||||
*/
|
||||
export interface RegistrableField {
|
||||
new (...args: any[]): Field;
|
||||
fromJson(options: FieldConfig): Field;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -25,7 +59,7 @@ interface RegistryOptions {
|
||||
* @throws {Error} if the type name is empty, the field is already registered,
|
||||
* or the fieldClass is not an object containing a fromJson function.
|
||||
*/
|
||||
export function register(type: string, fieldClass: FieldProto) {
|
||||
export function register(type: string, fieldClass: RegistrableField) {
|
||||
registry.register(registry.Type.FIELD, type, fieldClass);
|
||||
}
|
||||
|
||||
@@ -59,7 +93,10 @@ export function fromJson<T>(options: RegistryOptions): Field<T> | null {
|
||||
* @param options
|
||||
*/
|
||||
function fromJsonInternal<T>(options: RegistryOptions): Field<T> | null {
|
||||
const fieldObject = registry.getObject(registry.Type.FIELD, options.type);
|
||||
const fieldObject = registry.getObject(
|
||||
registry.Type.FIELD,
|
||||
options.type,
|
||||
) as unknown as RegistrableField;
|
||||
if (!fieldObject) {
|
||||
console.warn(
|
||||
'Blockly could not create a field of type ' +
|
||||
@@ -69,12 +106,8 @@ function fromJsonInternal<T>(options: RegistryOptions): Field<T> | null {
|
||||
' #1584), or the registration is not being reached.',
|
||||
);
|
||||
return null;
|
||||
} else if (typeof (fieldObject as any).fromJson !== 'function') {
|
||||
throw new TypeError('returned Field was not a IRegistrableField');
|
||||
} else {
|
||||
type fromJson = (options: {}) => Field<T>;
|
||||
return (fieldObject as unknown as {fromJson: fromJson}).fromJson(options);
|
||||
}
|
||||
return fieldObject.fromJson(options);
|
||||
}
|
||||
|
||||
export const TEST_ONLY = {
|
||||
|
||||
@@ -73,7 +73,9 @@ export class FieldTextInput extends FieldInput<string> {
|
||||
* @nocollapse
|
||||
* @internal
|
||||
*/
|
||||
static fromJson(options: FieldTextInputFromJsonConfig): FieldTextInput {
|
||||
static override 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.
|
||||
|
||||
@@ -574,16 +574,7 @@ export abstract class Flyout
|
||||
* @param contents - The array of items for the flyout.
|
||||
*/
|
||||
setContents(contents: FlyoutItem[]): void {
|
||||
const blocksAndButtons = contents.map((item) => {
|
||||
if (item.type === 'block' && item.block) {
|
||||
return item.block as BlockSvg;
|
||||
}
|
||||
if (item.type === 'button' && item.button) {
|
||||
return item.button as FlyoutButton;
|
||||
}
|
||||
});
|
||||
|
||||
this.contents = blocksAndButtons as FlyoutItem[];
|
||||
this.contents = contents;
|
||||
}
|
||||
/**
|
||||
* Update the display property of the flyout based whether it thinks it should
|
||||
|
||||
@@ -12,6 +12,7 @@ import type {Coordinate} from '../utils/coordinate.js';
|
||||
import type {FlyoutDefinition} from '../utils/toolbox.js';
|
||||
import type {Svg} from '../utils/svg.js';
|
||||
import type {IRegistrable} from './i_registrable.js';
|
||||
import {FlyoutItem} from '../flyout_base.js';
|
||||
|
||||
/**
|
||||
* Interface for a flyout.
|
||||
@@ -117,6 +118,16 @@ export interface IFlyout extends IRegistrable {
|
||||
*/
|
||||
show(flyoutDef: FlyoutDefinition | string): void;
|
||||
|
||||
/**
|
||||
* Returns the list of flyout items currently present in the flyout.
|
||||
* The `show` method parses the flyout definition into a list of actual
|
||||
* flyout items. This method should return those concrete items, which
|
||||
* may be used for e.g. keyboard navigation.
|
||||
*
|
||||
* @returns List of flyout items.
|
||||
*/
|
||||
getContents(): FlyoutItem[];
|
||||
|
||||
/**
|
||||
* Create a copy of this block on the workspace.
|
||||
*
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
// Former goog.module ID: Blockly.ASTNode
|
||||
|
||||
import type {Block} from '../block.js';
|
||||
import {Block} from '../block.js';
|
||||
import type {Connection} from '../connection.js';
|
||||
import {ConnectionType} from '../connection_type.js';
|
||||
import type {Field} from '../field.js';
|
||||
@@ -23,7 +23,7 @@ import {Coordinate} from '../utils/coordinate.js';
|
||||
import type {Workspace} from '../workspace.js';
|
||||
import {FlyoutButton} from '../flyout_button.js';
|
||||
import {WorkspaceSvg} from '../workspace_svg.js';
|
||||
import {Flyout} from '../flyout_base.js';
|
||||
import {FlyoutItem} from '../flyout_base.js';
|
||||
|
||||
/**
|
||||
* Class for an AST node.
|
||||
@@ -337,21 +337,59 @@ export class ASTNode {
|
||||
return null;
|
||||
}
|
||||
|
||||
const flyout = targetWorkspace.getFlyout() as Flyout;
|
||||
const flyoutContents = flyout.getContents() as (Block | FlyoutButton)[];
|
||||
const flyout = targetWorkspace.getFlyout();
|
||||
if (!flyout) return null;
|
||||
|
||||
const nextItem = this.findNextLocationInFlyout(
|
||||
flyout.getContents(),
|
||||
location,
|
||||
forward,
|
||||
);
|
||||
if (!nextItem) return null;
|
||||
|
||||
if (nextItem.type === 'button' && nextItem.button) {
|
||||
return ASTNode.createButtonNode(nextItem.button);
|
||||
} else if (nextItem.type === 'block' && nextItem.block) {
|
||||
return ASTNode.createStackNode(nextItem.block);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the next (or previous if navigating backward) item in the flyout that should be navigated to.
|
||||
*
|
||||
* @param flyoutContents Contents of the current flyout.
|
||||
* @param currentLocation Current ASTNode location.
|
||||
* @param forward True if we're navigating forward, else false.
|
||||
* @returns The next (or previous) FlyoutItem, or null if there is none.
|
||||
*/
|
||||
private findNextLocationInFlyout(
|
||||
flyoutContents: FlyoutItem[],
|
||||
currentLocation: IASTNodeLocation,
|
||||
forward: boolean,
|
||||
): FlyoutItem | null {
|
||||
const currentIndex = flyoutContents.findIndex((item: FlyoutItem) => {
|
||||
if (currentLocation instanceof Block && item.block === currentLocation) {
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
currentLocation instanceof FlyoutButton &&
|
||||
item.button === currentLocation
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (currentIndex < 0) return null;
|
||||
|
||||
const currentIndex = flyoutContents.indexOf(location);
|
||||
const resultIndex = forward ? currentIndex + 1 : currentIndex - 1;
|
||||
if (resultIndex === -1 || resultIndex === flyoutContents.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const newLocation = flyoutContents[resultIndex];
|
||||
if (newLocation instanceof FlyoutButton) {
|
||||
return ASTNode.createButtonNode(newLocation);
|
||||
} else {
|
||||
return ASTNode.createStackNode(newLocation);
|
||||
}
|
||||
return flyoutContents[resultIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -126,6 +126,16 @@ AppController.prototype.exportBlockLibraryToFile = function() {
|
||||
}
|
||||
};
|
||||
|
||||
AppController.prototype.exportBlockLibraryAsJson = function() {
|
||||
const blockJson = this.blockLibraryController.getBlockLibraryAsJson();
|
||||
if (blockJson.length === 0) {
|
||||
alert('No blocks in library to export');
|
||||
return;
|
||||
}
|
||||
const filename = 'legacy_block_factory_export.txt';
|
||||
FactoryUtils.createAndDownloadFile(JSON.stringify(blockJson), filename, 'plain');
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts an object mapping block type to XML to text file for output.
|
||||
* @param {!Object} blockXmlMap Object mapping block type to XML.
|
||||
@@ -491,6 +501,10 @@ AppController.prototype.assignBlockFactoryClickHandlers = function() {
|
||||
self.exportBlockLibraryToFile();
|
||||
});
|
||||
|
||||
document.getElementById('exportAsJson').addEventListener('click', function() {
|
||||
self.exportBlockLibraryAsJson();
|
||||
});
|
||||
|
||||
document.getElementById('helpButton').addEventListener('click',
|
||||
function() {
|
||||
open('https://developers.google.com/blockly/custom-blocks/block-factory',
|
||||
|
||||
@@ -173,6 +173,29 @@ BlockLibraryController.prototype.getBlockLibrary = function() {
|
||||
return this.storage.getBlockXmlTextMap();
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {Object[]} Array of JSON data, where each item is the data for one block type.
|
||||
*/
|
||||
BlockLibraryController.prototype.getBlockLibraryAsJson = function() {
|
||||
const xmlBlocks = this.storage.getBlockXmlMap(this.storage.getBlockTypes());
|
||||
const jsonBlocks = [];
|
||||
const headlessWorkspace = new Blockly.Workspace();
|
||||
|
||||
for (const blockName in xmlBlocks) {
|
||||
// Load the block XML into a workspace so we can save it as JSON
|
||||
headlessWorkspace.clear();
|
||||
const blockXml = xmlBlocks[blockName];
|
||||
Blockly.Xml.domToWorkspace(blockXml, headlessWorkspace);
|
||||
const block = headlessWorkspace.getBlocksByType('factory_base', false)[0];
|
||||
|
||||
if (!block) continue;
|
||||
|
||||
const json = Blockly.serialization.blocks.save(block, {addCoordinates: false, saveIds: false});
|
||||
jsonBlocks.push(json);
|
||||
}
|
||||
return jsonBlocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return stored XML of a given block type.
|
||||
* @param {string} blockType The type of block.
|
||||
|
||||
@@ -339,6 +339,9 @@
|
||||
<button id="localSaveButton" title="Save block library XML to a local file.">
|
||||
<span>Download Block Library</span>
|
||||
</button>
|
||||
<button id="exportAsJson" title="Export block library for import into the new Block Factory.">
|
||||
<span>Export Block Library</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -1 +1,12 @@
|
||||
{"MATH_HUE": "230", "LOOPS_HUE": "120", "LISTS_HUE": "260", "LOGIC_HUE": "210", "VARIABLES_HUE": "330", "TEXTS_HUE": "160", "PROCEDURES_HUE": "290", "COLOUR_HUE": "20", "VARIABLES_DYNAMIC_HUE": "310"}
|
||||
{
|
||||
"#": "Automatically generated, do not edit this file!",
|
||||
"COLOUR_HUE": "20",
|
||||
"LISTS_HUE": "260",
|
||||
"LOGIC_HUE": "210",
|
||||
"LOOPS_HUE": "120",
|
||||
"MATH_HUE": "230",
|
||||
"PROCEDURES_HUE": "290",
|
||||
"TEXTS_HUE": "160",
|
||||
"VARIABLES_DYNAMIC_HUE": "310",
|
||||
"VARIABLES_HUE": "330"
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"@metadata": {
|
||||
"author": "Ellen Spertus <ellen.spertus@gmail.com>",
|
||||
"lastupdated": "2024-03-08 22:38:32.330785",
|
||||
"lastupdated": "2024-04-16 23:19:53.668551",
|
||||
"locale": "en",
|
||||
"messagedocumentation" : "qqq"
|
||||
},
|
||||
@@ -291,10 +291,11 @@
|
||||
"LISTS_ISEMPTY_TITLE": "%1 is empty",
|
||||
"LISTS_ISEMPTY_TOOLTIP": "Returns true if the list is empty.",
|
||||
"LISTS_INLIST": "in list",
|
||||
"LISTS_INDEX_OF_HELPURL": "https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list",
|
||||
"LISTS_INDEX_OF_HELPURL": "https://github.com/google/blockly/wiki/Lists#finding-items-in-a-list",
|
||||
"LISTS_INDEX_OF_FIRST": "find first occurrence of item",
|
||||
"LISTS_INDEX_OF_LAST": "find last occurrence of item",
|
||||
"LISTS_INDEX_OF_TOOLTIP": "Returns the index of the first/last occurrence of the item in the list. Returns %1 if item is not found.",
|
||||
"LISTS_GET_INDEX_HELPURL": "https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list",
|
||||
"LISTS_GET_INDEX_GET": "get",
|
||||
"LISTS_GET_INDEX_GET_REMOVE": "get and remove",
|
||||
"LISTS_GET_INDEX_REMOVE": "remove",
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
"COLOUR_RANDOM_HELPURL": "{{Optional}} url - A link that displays a random colour each time you visit it.",
|
||||
"COLOUR_RANDOM_TITLE": "block text - Title of block that generates a colour at random.",
|
||||
"COLOUR_RANDOM_TOOLTIP": "tooltip - See [https://github.com/google/blockly/wiki/Colour#generating-a-random-colour https://github.com/google/blockly/wiki/Colour#generating-a-random-colour].",
|
||||
"COLOUR_RGB_HELPURL": "{{Ignored}} url - A link for colour codes with percentages (0-100%) for each component, instead of the more common 0-255, which may be more difficult for beginners.",
|
||||
"COLOUR_RGB_HELPURL": "{{Optional}} url - A link for colour codes with percentages (0-100%) for each component, instead of the more common 0-255, which may be more difficult for beginners.",
|
||||
"COLOUR_RGB_TITLE": "block text - Title of block for [https://github.com/google/blockly/wiki/Colour#creating-a-colour-from-red-green-and-blue-components https://github.com/google/blockly/wiki/Colour#creating-a-colour-from-red-green-and-blue-components].",
|
||||
"COLOUR_RGB_RED": "block input text - The amount of red (from 0 to 100) to use when [https://github.com/google/blockly/wiki/Colour#creating-a-colour-from-red-green-and-blue-components https://github.com/google/blockly/wiki/Colour#creating-a-colour-from-red-green-and-blue-components].\n{{Identical|Red}}",
|
||||
"COLOUR_RGB_GREEN": "block input text - The amount of green (from 0 to 100) to use when [https://github.com/google/blockly/wiki/Colour#creating-a-colour-from-red-green-and-blue-components https://github.com/google/blockly/wiki/Colour#creating-a-colour-from-red-green-and-blue-components].",
|
||||
@@ -250,7 +250,7 @@
|
||||
"TEXT_GET_SUBSTRING_END_FROM_START": "dropdown - Indicates that the following number specifies the position (relative to the start position) of the end of the region of text that should be obtained from the preceding piece of text. See [https://github.com/google/blockly/wiki/Text#extracting-a-region-of-text https://github.com/google/blockly/wiki/Text#extracting-a-region-of-text]. [[File:Blockly-get-substring.png]]",
|
||||
"TEXT_GET_SUBSTRING_END_FROM_END": "dropdown - Indicates that the following number specifies the position (relative to the end position) of the end of the region of text that should be obtained from the preceding piece of text. See [https://github.com/google/blockly/wiki/Text#extracting-a-region-of-text https://github.com/google/blockly/wiki/Text#extracting-a-region-of-text]. [[File:Blockly-get-substring.png]]",
|
||||
"TEXT_GET_SUBSTRING_END_LAST": "block text - Indicates that a region ending with the last letter of the preceding piece of text should be extracted. See [https://github.com/google/blockly/wiki/Text#extracting-a-region-of-text https://github.com/google/blockly/wiki/Text#extracting-a-region-of-text]. [[File:Blockly-get-substring.png]]",
|
||||
"TEXT_GET_SUBSTRING_TAIL": "{{Optional|Supply translation only if your language requires it. Most do not.}}\nblock text - Text that should go after the rightmost block/dropdown when [https://github.com/google/blockly/wiki/Text#extracting-a-region-of-text extracting a region of text]. In most languages, this will be the empty string. [[File:Blockly-get-substring.png]]",
|
||||
"TEXT_GET_SUBSTRING_TAIL": "{{Optional|Supply translation only if your language requires it. Most do not.}} block text - Text that should go after the rightmost block/dropdown when [https://github.com/google/blockly/wiki/Text#extracting-a-region-of-text extracting a region of text]. In most languages, this will be the empty string. [[File:Blockly-get-substring.png]]",
|
||||
"TEXT_CHANGECASE_HELPURL": "{{Optional}} url - Information about the case of letters (upper-case and lower-case).",
|
||||
"TEXT_CHANGECASE_TOOLTIP": "tooltip - Describes a block to adjust the case of letters. For more information on this block, see [https://github.com/google/blockly/wiki/Text#adjusting-text-case https://github.com/google/blockly/wiki/Text#adjusting-text-case].",
|
||||
"TEXT_CHANGECASE_OPERATOR_UPPERCASE": "block text - Indicates that all of the letters in the following piece of text should be capitalized. If your language does not use case, you may indicate that this is not applicable to your language. For more information on this block, see [https://github.com/google/blockly/wiki/Text#adjusting-text-case https://github.com/google/blockly/wiki/Text#adjusting-text-case].",
|
||||
@@ -297,10 +297,11 @@
|
||||
"LISTS_ISEMPTY_TITLE": "block text - See [https://github.com/google/blockly/wiki/Lists#is-empty https://github.com/google/blockly/wiki/Lists#is-empty]. \n\nParameters:\n* %1 - the list to test",
|
||||
"LISTS_ISEMPTY_TOOLTIP": "block tooltip - See [https://github.com/google/blockly/wiki/Lists#is-empty https://github.com/google/blockly/wiki/Lists#is-empty].",
|
||||
"LISTS_INLIST": "block text - Title of blocks operating on [https://github.com/google/blockly/wiki/Lists lists].",
|
||||
"LISTS_INDEX_OF_HELPURL": "{{Optional}} url - See [https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list].",
|
||||
"LISTS_INDEX_OF_HELPURL": "{{Optional}} url - See [https://github.com/google/blockly/wiki/Lists#finding-items-in-a-list https://github.com/google/blockly/wiki/Lists#finding-items-in-a-list].",
|
||||
"LISTS_INDEX_OF_FIRST": "dropdown - See [https://github.com/google/blockly/wiki/Lists#finding-items-in-a-list Lists#finding-items-in-a-list]. [[File:Blockly-list-find.png]]",
|
||||
"LISTS_INDEX_OF_LAST": "dropdown - See [https://github.com/google/blockly/wiki/Lists#finding-items-in-a-list https://github.com/google/blockly/wiki/Lists#finding-items-in-a-list]. [[File:Blockly-list-find.png]]",
|
||||
"LISTS_INDEX_OF_TOOLTIP": "tooltip - %1 will be replaced by either the number 0 or -1 depending on the indexing mode. See [https://github.com/google/blockly/wiki/Lists#finding-items-in-a-list https://github.com/google/blockly/wiki/Lists#finding-items-in-a-list]. [[File:Blockly-list-find.png]]",
|
||||
"LISTS_GET_INDEX_HELPURL": "{{Optional}} url - See [https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list].",
|
||||
"LISTS_GET_INDEX_GET": "dropdown - Indicates that the user wishes to [https://github.com/google/blockly/wiki/Lists#getting-a-single-item get an item from a list] without removing it from the list.",
|
||||
"LISTS_GET_INDEX_GET_REMOVE": "dropdown - Indicates that the user wishes to [https://github.com/google/blockly/wiki/Lists#getting-a-single-item get and remove an item from a list], as opposed to merely getting it without modifying the list.",
|
||||
"LISTS_GET_INDEX_REMOVE": "dropdown - Indicates that the user wishes to [https://github.com/google/blockly/wiki/Lists#removing-an-item remove an item from a list].\n{{Identical|Remove}}",
|
||||
@@ -309,7 +310,7 @@
|
||||
"LISTS_GET_INDEX_FIRST": "dropdown - Indicates that the '''first''' item should be [https://github.com/google/blockly/wiki/Lists#getting-a-single-item accessed in a list]. [[File:Blockly-list-get-item.png]]",
|
||||
"LISTS_GET_INDEX_LAST": "dropdown - Indicates that the '''last''' item should be [https://github.com/google/blockly/wiki/Lists#getting-a-single-item accessed in a list]. [[File:Blockly-list-get-item.png]]",
|
||||
"LISTS_GET_INDEX_RANDOM": "dropdown - Indicates that a '''random''' item should be [https://github.com/google/blockly/wiki/Lists#getting-a-single-item accessed in a list]. [[File:Blockly-list-get-item.png]]",
|
||||
"LISTS_GET_INDEX_TAIL": "{{Optional|Supply translation only if your language requires it. Most do not.}}\n\nblock text - Text that should go after the rightmost block/dropdown when [https://github.com/google/blockly/wiki/Lists#getting-a-single-item accessing an item from a list]. In most languages, this will be the empty string. [[File:Blockly-list-get-item.png]]",
|
||||
"LISTS_GET_INDEX_TAIL": "{{Optional|Supply translation only if your language requires it. Most do not.}} block text - Text that should go after the rightmost block/dropdown when [https://github.com/google/blockly/wiki/Lists#getting-a-single-item accessing an item from a list]. In most languages, this will be the empty string. [[File:Blockly-list-get-item.png]]",
|
||||
"LISTS_INDEX_FROM_START_TOOLTIP": "tooltip - Indicates the ordinal number that the first item in a list is referenced by. %1 will be replaced by either '#0' or '#1' depending on the indexing mode.",
|
||||
"LISTS_INDEX_FROM_END_TOOLTIP": "tooltip - Indicates the ordinal number that the last item in a list is referenced by. %1 will be replaced by either '#0' or '#1' depending on the indexing mode.",
|
||||
"LISTS_GET_INDEX_TOOLTIP_GET_FROM": "tooltip - See [https://github.com/google/blockly/wiki/Lists#getting-a-single-item https://github.com/google/blockly/wiki/Lists#getting-a-single-item] for more information.",
|
||||
@@ -343,7 +344,7 @@
|
||||
"LISTS_GET_SUBLIST_END_FROM_START": "dropdown - Indicates that an index relative to the front of the list should be used to specify the end of the range from which to [https://github.com/google/blockly/wiki/Lists#getting-a-sublist get a sublist]. [[File:Blockly-get-sublist.png]]",
|
||||
"LISTS_GET_SUBLIST_END_FROM_END": "dropdown - Indicates that an index relative to the end of the list should be used to specify the end of the range from which to [https://github.com/google/blockly/wiki/Lists#getting-a-sublist get a sublist]. [[File:Blockly-get-sublist.png]]",
|
||||
"LISTS_GET_SUBLIST_END_LAST": "dropdown - Indicates that the '''last''' item in the given list should be [https://github.com/google/blockly/wiki/Lists#getting-a-sublist the end of the selected sublist]. [[File:Blockly-get-sublist.png]]",
|
||||
"LISTS_GET_SUBLIST_TAIL": "{{Optional}}\nblock text - This appears in the rightmost position ('tail') of the sublist block, as described at [https://github.com/google/blockly/wiki/Lists#getting-a-sublist https://github.com/google/blockly/wiki/Lists#getting-a-sublist]. In English and most other languages, this is the empty string. [[File:Blockly-get-sublist.png]]",
|
||||
"LISTS_GET_SUBLIST_TAIL": "{{Optional|Supply translation only if your language requires it. Most do not.}} block text - This appears in the rightmost position ('tail') of the sublist block, as described at [https://github.com/google/blockly/wiki/Lists#getting-a-sublist https://github.com/google/blockly/wiki/Lists#getting-a-sublist]. In English and most other languages, this is the empty string. [[File:Blockly-get-sublist.png]]",
|
||||
"LISTS_GET_SUBLIST_TOOLTIP": "tooltip - See [https://github.com/google/blockly/wiki/Lists#getting-a-sublist https://github.com/google/blockly/wiki/Lists#getting-a-sublist] for more information. [[File:Blockly-get-sublist.png]]",
|
||||
"LISTS_SORT_HELPURL": "{{Optional}} url - Information describing sorting a list.",
|
||||
"LISTS_SORT_TITLE": "Sort as type %1 (numeric or alphabetic) in order %2 (ascending or descending) a list of items %3.\n{{Identical|Sort}}",
|
||||
@@ -362,7 +363,7 @@
|
||||
"LISTS_REVERSE_HELPURL": "{{Optional}} url - Information describing reversing a list.",
|
||||
"LISTS_REVERSE_MESSAGE0": "block text - Title of block that returns a copy of a list (%1) with the order of items reversed.",
|
||||
"LISTS_REVERSE_TOOLTIP": "tooltip - Short description for a block that reverses a copy of a list.",
|
||||
"ORDINAL_NUMBER_SUFFIX": "{{Optional}}\ngrammar - Text that follows an ordinal number (a number that indicates position relative to other numbers). In most languages, such text appears before the number, so this should be blank. An exception is Hungarian. See [[Translating:Blockly#Ordinal_numbers]] for more information.",
|
||||
"ORDINAL_NUMBER_SUFFIX": "{{Optional|Supply translation only if your language requires it. Most do not.}} grammar - Text that follows an ordinal number (a number that indicates position relative to other numbers). In most languages, such text appears before the number, so this should be blank. An exception is Hungarian. See [[Translating:Blockly#Ordinal_numbers]] for more information.",
|
||||
"VARIABLES_GET_HELPURL": "{{Optional}} url - Information about ''variables'' in computer programming. Consider using your language's translation of [https://en.wikipedia.org/wiki/Variable_(computer_science) https://en.wikipedia.org/wiki/Variable_(computer_science)], if it exists.",
|
||||
"VARIABLES_GET_TOOLTIP": "tooltip - This gets the value of the named variable without modifying it.",
|
||||
"VARIABLES_GET_CREATE_SET": "context menu - Selecting this creates a block to set (change) the value of this variable. \n\nParameters:\n* %1 - the name of the variable.",
|
||||
@@ -376,7 +377,7 @@
|
||||
"PROCEDURES_BEFORE_PARAMS": "block text - This precedes the list of parameters on a function's definition block. See [https://blockly-demo.appspot.com/static/apps/code/index.html?lang=en#voztpd this sample function with parameters].",
|
||||
"PROCEDURES_CALL_BEFORE_PARAMS": "block text - This precedes the list of parameters on a function's caller block. See [https://blockly-demo.appspot.com/static/apps/code/index.html?lang=en#voztpd this sample function with parameters].",
|
||||
"PROCEDURES_CALL_DISABLED_DEF_WARNING": "warning - This appears if a block that runs a function can't run because the function definition block is disabled. See [https://blockly-demo.appspot.com/static/demos/code/index.html#q947d7 this sample of a disabled function definition and call block].",
|
||||
"PROCEDURES_DEFNORETURN_DO": "{{Optional}}\nblock text - This appears next to the function's 'body', the blocks that should be run when the function is called, as shown in [https://blockly-demo.appspot.com/static/apps/code/index.html?lang=en#voztpd this sample function definition].",
|
||||
"PROCEDURES_DEFNORETURN_DO": "{{Optional|Supply translation only if your language requires it. Most do not.}} block text - This appears next to the function's 'body', the blocks that should be run when the function is called, as shown in [https://blockly-demo.appspot.com/static/apps/code/index.html?lang=en#voztpd this sample function definition].",
|
||||
"PROCEDURES_DEFNORETURN_TOOLTIP": "tooltip",
|
||||
"PROCEDURES_DEFNORETURN_COMMENT": "Placeholder text that the user is encouraged to replace with a description of what their function does.",
|
||||
"PROCEDURES_DEFRETURN_HELPURL": "{{Optional}} url - Information about defining [https://en.wikipedia.org/wiki/Subroutine functions] that have return values.",
|
||||
|
||||
@@ -1 +1,22 @@
|
||||
{"CONTROLS_FOREACH_INPUT_DO": "CONTROLS_REPEAT_INPUT_DO", "CONTROLS_FOR_INPUT_DO": "CONTROLS_REPEAT_INPUT_DO", "CONTROLS_IF_ELSEIF_TITLE_ELSEIF": "CONTROLS_IF_MSG_ELSEIF", "CONTROLS_IF_ELSE_TITLE_ELSE": "CONTROLS_IF_MSG_ELSE", "CONTROLS_IF_IF_TITLE_IF": "CONTROLS_IF_MSG_IF", "CONTROLS_IF_MSG_THEN": "CONTROLS_REPEAT_INPUT_DO", "CONTROLS_WHILEUNTIL_INPUT_DO": "CONTROLS_REPEAT_INPUT_DO", "LISTS_CREATE_WITH_ITEM_TITLE": "VARIABLES_DEFAULT_NAME", "LISTS_GET_INDEX_HELPURL": "LISTS_INDEX_OF_HELPURL", "LISTS_GET_INDEX_INPUT_IN_LIST": "LISTS_INLIST", "LISTS_GET_SUBLIST_INPUT_IN_LIST": "LISTS_INLIST", "LISTS_INDEX_OF_INPUT_IN_LIST": "LISTS_INLIST", "LISTS_SET_INDEX_INPUT_IN_LIST": "LISTS_INLIST", "MATH_CHANGE_TITLE_ITEM": "VARIABLES_DEFAULT_NAME", "PROCEDURES_DEFRETURN_COMMENT": "PROCEDURES_DEFNORETURN_COMMENT", "PROCEDURES_DEFRETURN_DO": "PROCEDURES_DEFNORETURN_DO", "PROCEDURES_DEFRETURN_PROCEDURE": "PROCEDURES_DEFNORETURN_PROCEDURE", "PROCEDURES_DEFRETURN_TITLE": "PROCEDURES_DEFNORETURN_TITLE", "TEXT_APPEND_VARIABLE": "VARIABLES_DEFAULT_NAME", "TEXT_CREATE_JOIN_ITEM_TITLE_ITEM": "VARIABLES_DEFAULT_NAME"}
|
||||
{
|
||||
"#": "Automatically generated, do not edit this file!",
|
||||
"CONTROLS_FOREACH_INPUT_DO": "CONTROLS_REPEAT_INPUT_DO",
|
||||
"CONTROLS_FOR_INPUT_DO": "CONTROLS_REPEAT_INPUT_DO",
|
||||
"CONTROLS_IF_ELSEIF_TITLE_ELSEIF": "CONTROLS_IF_MSG_ELSEIF",
|
||||
"CONTROLS_IF_ELSE_TITLE_ELSE": "CONTROLS_IF_MSG_ELSE",
|
||||
"CONTROLS_IF_IF_TITLE_IF": "CONTROLS_IF_MSG_IF",
|
||||
"CONTROLS_IF_MSG_THEN": "CONTROLS_REPEAT_INPUT_DO",
|
||||
"CONTROLS_WHILEUNTIL_INPUT_DO": "CONTROLS_REPEAT_INPUT_DO",
|
||||
"LISTS_CREATE_WITH_ITEM_TITLE": "VARIABLES_DEFAULT_NAME",
|
||||
"LISTS_GET_INDEX_INPUT_IN_LIST": "LISTS_INLIST",
|
||||
"LISTS_GET_SUBLIST_INPUT_IN_LIST": "LISTS_INLIST",
|
||||
"LISTS_INDEX_OF_INPUT_IN_LIST": "LISTS_INLIST",
|
||||
"LISTS_SET_INDEX_INPUT_IN_LIST": "LISTS_INLIST",
|
||||
"MATH_CHANGE_TITLE_ITEM": "VARIABLES_DEFAULT_NAME",
|
||||
"PROCEDURES_DEFRETURN_COMMENT": "PROCEDURES_DEFNORETURN_COMMENT",
|
||||
"PROCEDURES_DEFRETURN_DO": "PROCEDURES_DEFNORETURN_DO",
|
||||
"PROCEDURES_DEFRETURN_PROCEDURE": "PROCEDURES_DEFNORETURN_PROCEDURE",
|
||||
"PROCEDURES_DEFRETURN_TITLE": "PROCEDURES_DEFNORETURN_TITLE",
|
||||
"TEXT_APPEND_VARIABLE": "VARIABLES_DEFAULT_NAME",
|
||||
"TEXT_CREATE_JOIN_ITEM_TITLE_ITEM": "VARIABLES_DEFAULT_NAME"
|
||||
}
|
||||
@@ -1154,9 +1154,9 @@ Blockly.Msg.LISTS_ISEMPTY_TOOLTIP = 'Returns true if the list is empty.';
|
||||
Blockly.Msg.LISTS_INLIST = 'in list';
|
||||
|
||||
/** @type {string} */
|
||||
/// {{Optional}} url - See [https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list
|
||||
/// https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list].
|
||||
Blockly.Msg.LISTS_INDEX_OF_HELPURL = 'https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list';
|
||||
/// {{Optional}} url - See [https://github.com/google/blockly/wiki/Lists#finding-items-in-a-list
|
||||
/// https://github.com/google/blockly/wiki/Lists#finding-items-in-a-list].
|
||||
Blockly.Msg.LISTS_INDEX_OF_HELPURL = 'https://github.com/google/blockly/wiki/Lists#finding-items-in-a-list';
|
||||
/** @type {string} */
|
||||
Blockly.Msg.LISTS_INDEX_OF_INPUT_IN_LIST = Blockly.Msg.LISTS_INLIST;
|
||||
/** @type {string} */
|
||||
@@ -1176,7 +1176,9 @@ Blockly.Msg.LISTS_INDEX_OF_LAST = 'find last occurrence of item';
|
||||
Blockly.Msg.LISTS_INDEX_OF_TOOLTIP = 'Returns the index of the first/last occurrence of the item in the list. Returns %1 if item is not found.';
|
||||
|
||||
/** @type {string} */
|
||||
Blockly.Msg.LISTS_GET_INDEX_HELPURL = Blockly.Msg.LISTS_INDEX_OF_HELPURL;
|
||||
/// {{Optional}} url - See [https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list
|
||||
/// https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list].
|
||||
Blockly.Msg.LISTS_GET_INDEX_HELPURL = 'https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list';
|
||||
/** @type {string} */
|
||||
/// dropdown - Indicates that the user wishes to
|
||||
/// [https://github.com/google/blockly/wiki/Lists#getting-a-single-item
|
||||
|
||||
@@ -37,12 +37,13 @@ def string_is_ascii(s):
|
||||
def load_constants(filename):
|
||||
"""Read in constants file, which must be output in every language."""
|
||||
constant_defs = read_json_file(filename)
|
||||
if '#' in constant_defs: # Delete any comment.
|
||||
del constant_defs['#']
|
||||
constants_text = '\n'
|
||||
for key in constant_defs:
|
||||
value = constant_defs[key]
|
||||
value = value.replace('"', '\\"')
|
||||
constants_text += u'\nBlockly.Msg["{0}"] = \"{1}\";'.format(
|
||||
key, value)
|
||||
constants_text += u'\nBlockly.Msg["{0}"] = \"{1}\";'.format(key, value)
|
||||
return constants_text
|
||||
|
||||
def main():
|
||||
@@ -86,6 +87,8 @@ def main():
|
||||
# Read in synonyms file, which must be output in every language.
|
||||
synonym_defs = read_json_file(os.path.join(
|
||||
os.curdir, args.source_synonym_file))
|
||||
if '#' in synonym_defs: # Delete any comment.
|
||||
del synonym_defs['#']
|
||||
|
||||
# synonym_defs is also being sorted to ensure the same order is kept
|
||||
synonym_text = '\n'.join([u'Blockly.Msg["{0}"] = Blockly.Msg["{1}"];'
|
||||
|
||||
@@ -114,29 +114,22 @@ def main():
|
||||
write_files(args.author, args.lang, args.output_dir, results, False)
|
||||
|
||||
# Create synonyms.json.
|
||||
synonyms_sorted = sort_dict(synonyms)
|
||||
synonym_file_name = os.path.join(os.curdir, args.output_dir, 'synonyms.json')
|
||||
synonyms['#'] = 'Automatically generated, do not edit this file!'
|
||||
with open(synonym_file_name, 'w') as outfile:
|
||||
json.dump(synonyms_sorted, outfile)
|
||||
json.dump(synonyms, outfile, indent=2, sort_keys=True)
|
||||
if not args.quiet:
|
||||
print("Wrote {0} synonym pairs to {1}.".format(
|
||||
len(synonyms_sorted), synonym_file_name))
|
||||
len(synonyms) - 1, synonym_file_name))
|
||||
|
||||
# Create constants.json
|
||||
constants_sorted = sort_dict(constants)
|
||||
constants_file_name = os.path.join(os.curdir, args.output_dir, 'constants.json')
|
||||
constants['#'] = 'Automatically generated, do not edit this file!'
|
||||
with open(constants_file_name, 'w') as outfile:
|
||||
json.dump(constants_sorted, outfile)
|
||||
json.dump(constants, outfile, indent=2, sort_keys=True)
|
||||
if not args.quiet:
|
||||
print("Wrote {0} constant pairs to {1}.".format(
|
||||
len(constants_sorted), synonym_file_name))
|
||||
|
||||
def sort_dict(unsorted_dict):
|
||||
# Sort the dictionary (thereby enabling better diffing of changes).
|
||||
myKeys = list(unsorted_dict.keys())
|
||||
myKeys.sort()
|
||||
sorted_dict = {i: unsorted_dict[i] for i in myKeys}
|
||||
return sorted_dict
|
||||
len(constants) - 1, synonym_file_name))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
@@ -261,6 +261,7 @@ suite('Number Fields', function () {
|
||||
suite('Validators', function () {
|
||||
setup(function () {
|
||||
this.field = new Blockly.FieldNumber(1);
|
||||
this.field.valueWhenEditorWasOpened_ = this.field.getValue();
|
||||
this.field.htmlInput_ = document.createElement('input');
|
||||
this.field.htmlInput_.setAttribute('data-old-value', '1');
|
||||
this.field.htmlInput_.setAttribute('data-untyped-default-value', '1');
|
||||
@@ -276,7 +277,7 @@ suite('Number Fields', function () {
|
||||
return null;
|
||||
},
|
||||
value: 2,
|
||||
expectedValue: '1',
|
||||
expectedValue: 1,
|
||||
},
|
||||
{
|
||||
title: 'Force End with 6 Validator',
|
||||
|
||||
@@ -42,12 +42,10 @@ suite('Field Registry', function () {
|
||||
}, 'Invalid name');
|
||||
});
|
||||
test('No fromJson', function () {
|
||||
const fromJson = CustomFieldType.fromJson;
|
||||
delete CustomFieldType.fromJson;
|
||||
class IncorrectField {}
|
||||
chai.assert.throws(function () {
|
||||
Blockly.fieldRegistry.register('field_custom_test', CustomFieldType);
|
||||
Blockly.fieldRegistry.register('field_custom_test', IncorrectField);
|
||||
}, 'must have a fromJson function');
|
||||
CustomFieldType.fromJson = fromJson;
|
||||
});
|
||||
test('fromJson not a function', function () {
|
||||
const fromJson = CustomFieldType.fromJson;
|
||||
@@ -97,5 +95,21 @@ suite('Field Registry', function () {
|
||||
chai.assert.isNotNull(field);
|
||||
chai.assert.equal(field.getValue(), 'ok');
|
||||
});
|
||||
test('Did not override fromJson', function () {
|
||||
// This class will have a fromJson method, so it can be registered
|
||||
// but it doesn't override the abstract class's method so it throws
|
||||
class IncorrectField extends Blockly.Field {}
|
||||
|
||||
Blockly.fieldRegistry.register('field_custom_test', IncorrectField);
|
||||
|
||||
const json = {
|
||||
type: 'field_custom_test',
|
||||
value: 'ok',
|
||||
};
|
||||
|
||||
chai.assert.throws(function () {
|
||||
Blockly.fieldRegistry.fromJson(json);
|
||||
}, 'Attempted to instantiate a field from the registry');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -129,6 +129,7 @@ suite('Text Input Fields', function () {
|
||||
suite('Validators', function () {
|
||||
setup(function () {
|
||||
this.field = new Blockly.FieldTextInput('value');
|
||||
this.field.valueWhenEditorWasOpened_ = this.field.getValue();
|
||||
this.field.htmlInput_ = document.createElement('input');
|
||||
this.field.htmlInput_.setAttribute('data-old-value', 'value');
|
||||
this.field.htmlInput_.setAttribute('data-untyped-default-value', 'value');
|
||||
|
||||
Reference in New Issue
Block a user