mirror of
https://github.com/google/blockly.git
synced 2026-01-04 23:50:12 +01:00
release: Merge branch 'rc/v11.2.0' into rc/v12.0.0
This commit is contained in:
@@ -1,28 +0,0 @@
|
|||||||
# Build Artifacts
|
|
||||||
/msg/*
|
|
||||||
/build/*
|
|
||||||
/dist/*
|
|
||||||
/typings/*
|
|
||||||
/docs/*
|
|
||||||
|
|
||||||
# Tests other than mocha unit tests
|
|
||||||
/tests/blocks/*
|
|
||||||
/tests/themes/*
|
|
||||||
/tests/compile/*
|
|
||||||
/tests/jsunit/*
|
|
||||||
/tests/generators/*
|
|
||||||
/tests/mocha/webdriver.js
|
|
||||||
/tests/screenshot/*
|
|
||||||
/tests/test_runner.js
|
|
||||||
/tests/workspace_svg/*
|
|
||||||
|
|
||||||
# Demos, scripts, misc
|
|
||||||
/node_modules/*
|
|
||||||
/generators/*
|
|
||||||
/demos/*
|
|
||||||
/appengine/*
|
|
||||||
/externs/*
|
|
||||||
/closure/*
|
|
||||||
/scripts/gulpfiles/*
|
|
||||||
CHANGELOG.md
|
|
||||||
PULL_REQUEST_TEMPLATE.md
|
|
||||||
187
.eslintrc.js
187
.eslintrc.js
@@ -1,187 +0,0 @@
|
|||||||
const rules = {
|
|
||||||
'no-unused-vars': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
'args': 'after-used',
|
|
||||||
// Ignore vars starting with an underscore.
|
|
||||||
'varsIgnorePattern': '^_',
|
|
||||||
// Ignore arguments starting with an underscore.
|
|
||||||
'argsIgnorePattern': '^_',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
// Blockly uses for exporting symbols. no-self-assign added in eslint 5.
|
|
||||||
'no-self-assign': ['off'],
|
|
||||||
// Blockly uses single quotes except for JSON blobs, which must use double
|
|
||||||
// quotes.
|
|
||||||
'quotes': ['off'],
|
|
||||||
// Blockly uses 'use strict' in files.
|
|
||||||
'strict': ['off'],
|
|
||||||
// Closure style allows redeclarations.
|
|
||||||
'no-redeclare': ['off'],
|
|
||||||
'valid-jsdoc': ['error'],
|
|
||||||
'no-console': ['off'],
|
|
||||||
'spaced-comment': [
|
|
||||||
'error',
|
|
||||||
'always',
|
|
||||||
{
|
|
||||||
'block': {
|
|
||||||
'balanced': true,
|
|
||||||
},
|
|
||||||
'exceptions': ['*'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
// Blockly uses prefixes for optional arguments and test-only functions.
|
|
||||||
'camelcase': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
'properties': 'never',
|
|
||||||
'allow': ['^opt_', '^_opt_', '^testOnly_'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
// Blockly uses capital letters for some non-constructor namespaces.
|
|
||||||
// Keep them for legacy reasons.
|
|
||||||
'new-cap': ['off'],
|
|
||||||
// Blockly uses objects as maps, but uses Object.create(null) to
|
|
||||||
// instantiate them.
|
|
||||||
'guard-for-in': ['off'],
|
|
||||||
'prefer-spread': ['off'],
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build shared settings for TS linting and add in the config differences.
|
|
||||||
* @return {Object} The override TS linting for given files and a given
|
|
||||||
* tsconfig.
|
|
||||||
*/
|
|
||||||
function buildTSOverride({files, tsconfig}) {
|
|
||||||
return {
|
|
||||||
'files': files,
|
|
||||||
'plugins': ['@typescript-eslint/eslint-plugin', 'jsdoc'],
|
|
||||||
'settings': {
|
|
||||||
'jsdoc': {
|
|
||||||
'mode': 'typescript',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'parser': '@typescript-eslint/parser',
|
|
||||||
'parserOptions': {
|
|
||||||
'project': tsconfig,
|
|
||||||
'tsconfigRootDir': '.',
|
|
||||||
'ecmaVersion': 2020,
|
|
||||||
'sourceType': 'module',
|
|
||||||
},
|
|
||||||
'extends': [
|
|
||||||
'plugin:@typescript-eslint/recommended',
|
|
||||||
'plugin:jsdoc/recommended',
|
|
||||||
'prettier', // Extend again so that these rules are applied last
|
|
||||||
],
|
|
||||||
'rules': {
|
|
||||||
// TS rules
|
|
||||||
// Blockly uses namespaces to do declaration merging in some cases.
|
|
||||||
'@typescript-eslint/no-namespace': ['off'],
|
|
||||||
// Use the updated TypeScript-specific rule.
|
|
||||||
'no-invalid-this': ['off'],
|
|
||||||
'@typescript-eslint/no-invalid-this': ['error'],
|
|
||||||
// Needs decision. 601 problems.
|
|
||||||
'@typescript-eslint/no-non-null-assertion': ['off'],
|
|
||||||
// Use TS-specific rule.
|
|
||||||
'no-unused-vars': ['off'],
|
|
||||||
'@typescript-eslint/no-unused-vars': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
'argsIgnorePattern': '^_',
|
|
||||||
'varsIgnorePattern': '^_',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
// Temporarily disable. 23 problems.
|
|
||||||
'@typescript-eslint/no-explicit-any': ['off'],
|
|
||||||
// Temporarily disable. 128 problems.
|
|
||||||
'require-jsdoc': ['off'],
|
|
||||||
// Temporarily disable. 55 problems.
|
|
||||||
'@typescript-eslint/ban-types': ['off'],
|
|
||||||
// Temporarily disable. 33 problems.
|
|
||||||
'@typescript-eslint/no-empty-function': ['off'],
|
|
||||||
// Temporarily disable. 3 problems.
|
|
||||||
'@typescript-eslint/no-empty-interface': ['off'],
|
|
||||||
|
|
||||||
// TsDoc rules (using JsDoc plugin)
|
|
||||||
// Disable built-in jsdoc verifier.
|
|
||||||
'valid-jsdoc': ['off'],
|
|
||||||
// Don't require types in params and returns docs.
|
|
||||||
'jsdoc/require-param-type': ['off'],
|
|
||||||
'jsdoc/require-returns-type': ['off'],
|
|
||||||
// params and returns docs are optional.
|
|
||||||
'jsdoc/require-param-description': ['off'],
|
|
||||||
'jsdoc/require-returns': ['off'],
|
|
||||||
// Disable for now (breaks on `this` which is not really a param).
|
|
||||||
'jsdoc/require-param': ['off'],
|
|
||||||
// Don't auto-add missing jsdoc. Only required on exported items.
|
|
||||||
'jsdoc/require-jsdoc': [
|
|
||||||
'warn',
|
|
||||||
{
|
|
||||||
'enableFixer': false,
|
|
||||||
'publicOnly': true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'jsdoc/check-tag-names': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
'definedTags': [
|
|
||||||
'sealed',
|
|
||||||
'typeParam',
|
|
||||||
'remarks',
|
|
||||||
'define',
|
|
||||||
'nocollapse',
|
|
||||||
'suppress',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
// Re-enable after Closure is removed. There shouldn't even be
|
|
||||||
// types in the TsDoc.
|
|
||||||
// These are "types" because of Closure's @suppress {warningName}
|
|
||||||
'jsdoc/no-undefined-types': ['off'],
|
|
||||||
'jsdoc/valid-types': ['off'],
|
|
||||||
// Disabled due to not handling `this`. If re-enabled,
|
|
||||||
// checkDestructured option
|
|
||||||
// should be left as false.
|
|
||||||
'jsdoc/check-param-names': ['off', {'checkDestructured': false}],
|
|
||||||
// Allow any text in the license tag. Other checks are not relevant.
|
|
||||||
'jsdoc/check-values': ['off'],
|
|
||||||
// Ensure there is a blank line between the body and any @tags,
|
|
||||||
// as required by the tsdoc spec (see #6353).
|
|
||||||
'jsdoc/tag-lines': ['error', 'any', {'startLines': 1}],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: When this output is put directly in `module.exports`, the formatter
|
|
||||||
// does not align with the linter.
|
|
||||||
const eslintJSON = {
|
|
||||||
'rules': rules,
|
|
||||||
'env': {
|
|
||||||
'es2020': true,
|
|
||||||
'browser': true,
|
|
||||||
},
|
|
||||||
'globals': {
|
|
||||||
'goog': true,
|
|
||||||
'exports': true,
|
|
||||||
},
|
|
||||||
'extends': ['eslint:recommended', 'google', 'prettier'],
|
|
||||||
// TypeScript-specific config. Uses above rules plus these.
|
|
||||||
'overrides': [
|
|
||||||
buildTSOverride({
|
|
||||||
files: ['./**/*.ts', './**/*.tsx'],
|
|
||||||
tsconfig: './tsconfig.json',
|
|
||||||
}),
|
|
||||||
buildTSOverride({
|
|
||||||
files: ['./tests/typescript/**/*.ts', './tests/typescript/**/*.tsx'],
|
|
||||||
tsconfig: './tests/typescript/tsconfig.json',
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
'files': ['./.eslintrc.js'],
|
|
||||||
'env': {
|
|
||||||
'node': true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = eslintJSON;
|
|
||||||
2
.github/workflows/appengine_deploy.yml
vendored
2
.github/workflows/appengine_deploy.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
|||||||
path: _deploy/
|
path: _deploy/
|
||||||
|
|
||||||
- name: Deploy to App Engine
|
- name: Deploy to App Engine
|
||||||
uses: google-github-actions/deploy-appengine@v2.1.2
|
uses: google-github-actions/deploy-appengine@v2.1.4
|
||||||
# For parameters see:
|
# For parameters see:
|
||||||
# https://github.com/google-github-actions/deploy-appengine#inputs
|
# https://github.com/google-github-actions/deploy-appengine#inputs
|
||||||
with:
|
with:
|
||||||
|
|||||||
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
@@ -18,8 +18,7 @@ jobs:
|
|||||||
# TODO (#2114): re-enable osx build.
|
# TODO (#2114): re-enable osx build.
|
||||||
# os: [ubuntu-latest, macos-latest]
|
# os: [ubuntu-latest, macos-latest]
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
# TODO(#8392): unpin v22 once npm issue fixed.
|
node-version: [18.x, 20.x, 22.x]
|
||||||
node-version: [18.x, 20.x, 22.4.1]
|
|
||||||
# See supported Node.js release schedule at
|
# See supported Node.js release schedule at
|
||||||
# https://nodejs.org/en/about/releases/
|
# https://nodejs.org/en/about/releases/
|
||||||
|
|
||||||
|
|||||||
@@ -10,4 +10,6 @@ module.exports = {
|
|||||||
bracketSpacing: false,
|
bracketSpacing: false,
|
||||||
// Put HTML tag closing brackets on same line as last attribute.
|
// Put HTML tag closing brackets on same line as last attribute.
|
||||||
bracketSameLine: true,
|
bracketSameLine: true,
|
||||||
|
// Organise imports using a plugin.
|
||||||
|
'plugins': ['prettier-plugin-organize-imports'],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,6 +6,6 @@ var msg = 'Compiled Blockly files should be loaded from https://unpkg.com/blockl
|
|||||||
console.log(msg);
|
console.log(msg);
|
||||||
try {
|
try {
|
||||||
alert(msg);
|
alert(msg);
|
||||||
} catch (_e) {
|
} catch {
|
||||||
// Can't alert? Probably node.js.
|
// Can't alert? Probably node.js.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
// Former goog.module ID: Blockly.libraryBlocks
|
// Former goog.module ID: Blockly.libraryBlocks
|
||||||
|
|
||||||
|
import type {BlockDefinition} from '../core/blocks.js';
|
||||||
import * as lists from './lists.js';
|
import * as lists from './lists.js';
|
||||||
import * as logic from './logic.js';
|
import * as logic from './logic.js';
|
||||||
import * as loops from './loops.js';
|
import * as loops from './loops.js';
|
||||||
@@ -14,7 +15,6 @@ import * as procedures from './procedures.js';
|
|||||||
import * as texts from './text.js';
|
import * as texts from './text.js';
|
||||||
import * as variables from './variables.js';
|
import * as variables from './variables.js';
|
||||||
import * as variablesDynamic from './variables_dynamic.js';
|
import * as variablesDynamic from './variables_dynamic.js';
|
||||||
import type {BlockDefinition} from '../core/blocks.js';
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
lists,
|
lists,
|
||||||
|
|||||||
155
blocks/lists.ts
155
blocks/lists.ts
@@ -6,22 +6,22 @@
|
|||||||
|
|
||||||
// Former goog.module ID: Blockly.libraryBlocks.lists
|
// Former goog.module ID: Blockly.libraryBlocks.lists
|
||||||
|
|
||||||
import * as fieldRegistry from '../core/field_registry.js';
|
|
||||||
import * as xmlUtils from '../core/utils/xml.js';
|
|
||||||
import {Align} from '../core/inputs/align.js';
|
|
||||||
import type {Block} from '../core/block.js';
|
import type {Block} from '../core/block.js';
|
||||||
import type {Connection} from '../core/connection.js';
|
|
||||||
import type {BlockSvg} from '../core/block_svg.js';
|
import type {BlockSvg} from '../core/block_svg.js';
|
||||||
import type {FieldDropdown} from '../core/field_dropdown.js';
|
|
||||||
import {Msg} from '../core/msg.js';
|
|
||||||
import {MutatorIcon} from '../core/icons/mutator_icon.js';
|
|
||||||
import type {Workspace} from '../core/workspace.js';
|
|
||||||
import {
|
import {
|
||||||
createBlockDefinitionsFromJsonArray,
|
createBlockDefinitionsFromJsonArray,
|
||||||
defineBlocks,
|
defineBlocks,
|
||||||
} from '../core/common.js';
|
} from '../core/common.js';
|
||||||
|
import type {Connection} from '../core/connection.js';
|
||||||
import '../core/field_dropdown.js';
|
import '../core/field_dropdown.js';
|
||||||
|
import type {FieldDropdown} from '../core/field_dropdown.js';
|
||||||
|
import * as fieldRegistry from '../core/field_registry.js';
|
||||||
|
import {MutatorIcon} from '../core/icons/mutator_icon.js';
|
||||||
|
import {Align} from '../core/inputs/align.js';
|
||||||
import {ValueInput} from '../core/inputs/value_input.js';
|
import {ValueInput} from '../core/inputs/value_input.js';
|
||||||
|
import {Msg} from '../core/msg.js';
|
||||||
|
import * as xmlUtils from '../core/utils/xml.js';
|
||||||
|
import type {Workspace} from '../core/workspace.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dictionary of the block definitions provided by this module.
|
* A dictionary of the block definitions provided by this module.
|
||||||
@@ -412,6 +412,24 @@ const LISTS_GETINDEX = {
|
|||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
.appendField(modeMenu, 'MODE')
|
.appendField(modeMenu, 'MODE')
|
||||||
.appendField('', 'SPACE');
|
.appendField('', 'SPACE');
|
||||||
|
const menu = fieldRegistry.fromJson({
|
||||||
|
type: 'field_dropdown',
|
||||||
|
options: this.WHERE_OPTIONS,
|
||||||
|
}) as FieldDropdown;
|
||||||
|
menu.setValidator(
|
||||||
|
/** @param value The input value. */
|
||||||
|
function (this: FieldDropdown, value: string) {
|
||||||
|
const oldValue: string | null = this.getValue();
|
||||||
|
const oldAt = oldValue === 'FROM_START' || oldValue === 'FROM_END';
|
||||||
|
const newAt = value === 'FROM_START' || value === 'FROM_END';
|
||||||
|
if (newAt !== oldAt) {
|
||||||
|
const block = this.getSourceBlock() as GetIndexBlock;
|
||||||
|
block.updateAt_(newAt);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
this.appendDummyInput().appendField(menu, 'WHERE');
|
||||||
this.appendDummyInput('AT');
|
this.appendDummyInput('AT');
|
||||||
if (Msg['LISTS_GET_INDEX_TAIL']) {
|
if (Msg['LISTS_GET_INDEX_TAIL']) {
|
||||||
this.appendDummyInput('TAIL').appendField(Msg['LISTS_GET_INDEX_TAIL']);
|
this.appendDummyInput('TAIL').appendField(Msg['LISTS_GET_INDEX_TAIL']);
|
||||||
@@ -577,31 +595,6 @@ const LISTS_GETINDEX = {
|
|||||||
} else {
|
} else {
|
||||||
this.appendDummyInput('AT');
|
this.appendDummyInput('AT');
|
||||||
}
|
}
|
||||||
const menu = fieldRegistry.fromJson({
|
|
||||||
type: 'field_dropdown',
|
|
||||||
options: this.WHERE_OPTIONS,
|
|
||||||
}) as FieldDropdown;
|
|
||||||
menu.setValidator(
|
|
||||||
/**
|
|
||||||
* @param value The input value.
|
|
||||||
* @returns Null if the field has been replaced; otherwise undefined.
|
|
||||||
*/
|
|
||||||
function (this: FieldDropdown, value: string) {
|
|
||||||
const newAt = value === 'FROM_START' || value === 'FROM_END';
|
|
||||||
// The 'isAt' variable is available due to this function being a
|
|
||||||
// closure.
|
|
||||||
if (newAt !== isAt) {
|
|
||||||
const block = this.getSourceBlock() as GetIndexBlock;
|
|
||||||
block.updateAt_(newAt);
|
|
||||||
// This menu has been destroyed and replaced. Update the
|
|
||||||
// replacement.
|
|
||||||
block.setFieldValue(value, 'WHERE');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
this.getInput('AT')!.appendField(menu, 'WHERE');
|
|
||||||
if (Msg['LISTS_GET_INDEX_TAIL']) {
|
if (Msg['LISTS_GET_INDEX_TAIL']) {
|
||||||
this.moveInputBefore('TAIL', null);
|
this.moveInputBefore('TAIL', null);
|
||||||
}
|
}
|
||||||
@@ -644,6 +637,24 @@ const LISTS_SETINDEX = {
|
|||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
.appendField(operationDropdown, 'MODE')
|
.appendField(operationDropdown, 'MODE')
|
||||||
.appendField('', 'SPACE');
|
.appendField('', 'SPACE');
|
||||||
|
const menu = fieldRegistry.fromJson({
|
||||||
|
type: 'field_dropdown',
|
||||||
|
options: this.WHERE_OPTIONS,
|
||||||
|
}) as FieldDropdown;
|
||||||
|
menu.setValidator(
|
||||||
|
/** @param value The input value. */
|
||||||
|
function (this: FieldDropdown, value: string) {
|
||||||
|
const oldValue: string | null = this.getValue();
|
||||||
|
const oldAt = oldValue === 'FROM_START' || oldValue === 'FROM_END';
|
||||||
|
const newAt = value === 'FROM_START' || value === 'FROM_END';
|
||||||
|
if (newAt !== oldAt) {
|
||||||
|
const block = this.getSourceBlock() as SetIndexBlock;
|
||||||
|
block.updateAt_(newAt);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
this.appendDummyInput().appendField(menu, 'WHERE');
|
||||||
this.appendDummyInput('AT');
|
this.appendDummyInput('AT');
|
||||||
this.appendValueInput('TO').appendField(Msg['LISTS_SET_INDEX_INPUT_TO']);
|
this.appendValueInput('TO').appendField(Msg['LISTS_SET_INDEX_INPUT_TO']);
|
||||||
this.setInputsInline(true);
|
this.setInputsInline(true);
|
||||||
@@ -756,36 +767,10 @@ const LISTS_SETINDEX = {
|
|||||||
} else {
|
} else {
|
||||||
this.appendDummyInput('AT');
|
this.appendDummyInput('AT');
|
||||||
}
|
}
|
||||||
const menu = fieldRegistry.fromJson({
|
|
||||||
type: 'field_dropdown',
|
|
||||||
options: this.WHERE_OPTIONS,
|
|
||||||
}) as FieldDropdown;
|
|
||||||
menu.setValidator(
|
|
||||||
/**
|
|
||||||
* @param value The input value.
|
|
||||||
* @returns Null if the field has been replaced; otherwise undefined.
|
|
||||||
*/
|
|
||||||
function (this: FieldDropdown, value: string) {
|
|
||||||
const newAt = value === 'FROM_START' || value === 'FROM_END';
|
|
||||||
// The 'isAt' variable is available due to this function being a
|
|
||||||
// closure.
|
|
||||||
if (newAt !== isAt) {
|
|
||||||
const block = this.getSourceBlock() as SetIndexBlock;
|
|
||||||
block.updateAt_(newAt);
|
|
||||||
// This menu has been destroyed and replaced. Update the
|
|
||||||
// replacement.
|
|
||||||
block.setFieldValue(value, 'WHERE');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
this.moveInputBefore('AT', 'TO');
|
this.moveInputBefore('AT', 'TO');
|
||||||
if (this.getInput('ORDINAL')) {
|
if (this.getInput('ORDINAL')) {
|
||||||
this.moveInputBefore('ORDINAL', 'TO');
|
this.moveInputBefore('ORDINAL', 'TO');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getInput('AT')!.appendField(menu, 'WHERE');
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
blocks['lists_setIndex'] = LISTS_SETINDEX;
|
blocks['lists_setIndex'] = LISTS_SETINDEX;
|
||||||
@@ -818,7 +803,30 @@ const LISTS_GETSUBLIST = {
|
|||||||
this.appendValueInput('LIST')
|
this.appendValueInput('LIST')
|
||||||
.setCheck('Array')
|
.setCheck('Array')
|
||||||
.appendField(Msg['LISTS_GET_SUBLIST_INPUT_IN_LIST']);
|
.appendField(Msg['LISTS_GET_SUBLIST_INPUT_IN_LIST']);
|
||||||
|
const createMenu = (n: 1 | 2): FieldDropdown => {
|
||||||
|
const menu = fieldRegistry.fromJson({
|
||||||
|
type: 'field_dropdown',
|
||||||
|
options:
|
||||||
|
this[('WHERE_OPTIONS_' + n) as 'WHERE_OPTIONS_1' | 'WHERE_OPTIONS_2'],
|
||||||
|
}) as FieldDropdown;
|
||||||
|
menu.setValidator(
|
||||||
|
/** @param value The input value. */
|
||||||
|
function (this: FieldDropdown, value: string) {
|
||||||
|
const oldValue: string | null = this.getValue();
|
||||||
|
const oldAt = oldValue === 'FROM_START' || oldValue === 'FROM_END';
|
||||||
|
const newAt = value === 'FROM_START' || value === 'FROM_END';
|
||||||
|
if (newAt !== oldAt) {
|
||||||
|
const block = this.getSourceBlock() as GetSublistBlock;
|
||||||
|
block.updateAt_(n, newAt);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return menu;
|
||||||
|
};
|
||||||
|
this.appendDummyInput('WHERE1_INPUT').appendField(createMenu(1), 'WHERE1');
|
||||||
this.appendDummyInput('AT1');
|
this.appendDummyInput('AT1');
|
||||||
|
this.appendDummyInput('WHERE2_INPUT').appendField(createMenu(2), 'WHERE2');
|
||||||
this.appendDummyInput('AT2');
|
this.appendDummyInput('AT2');
|
||||||
if (Msg['LISTS_GET_SUBLIST_TAIL']) {
|
if (Msg['LISTS_GET_SUBLIST_TAIL']) {
|
||||||
this.appendDummyInput('TAIL').appendField(Msg['LISTS_GET_SUBLIST_TAIL']);
|
this.appendDummyInput('TAIL').appendField(Msg['LISTS_GET_SUBLIST_TAIL']);
|
||||||
@@ -896,35 +904,10 @@ const LISTS_GETSUBLIST = {
|
|||||||
} else {
|
} else {
|
||||||
this.appendDummyInput('AT' + n);
|
this.appendDummyInput('AT' + n);
|
||||||
}
|
}
|
||||||
const menu = fieldRegistry.fromJson({
|
|
||||||
type: 'field_dropdown',
|
|
||||||
options:
|
|
||||||
this[('WHERE_OPTIONS_' + n) as 'WHERE_OPTIONS_1' | 'WHERE_OPTIONS_2'],
|
|
||||||
}) as FieldDropdown;
|
|
||||||
menu.setValidator(
|
|
||||||
/**
|
|
||||||
* @param value The input value.
|
|
||||||
* @returns Null if the field has been replaced; otherwise undefined.
|
|
||||||
*/
|
|
||||||
function (this: FieldDropdown, value: string) {
|
|
||||||
const newAt = value === 'FROM_START' || value === 'FROM_END';
|
|
||||||
// The 'isAt' variable is available due to this function being a
|
|
||||||
// closure.
|
|
||||||
if (newAt !== isAt) {
|
|
||||||
const block = this.getSourceBlock() as GetSublistBlock;
|
|
||||||
block.updateAt_(n, newAt);
|
|
||||||
// This menu has been destroyed and replaced.
|
|
||||||
// Update the replacement.
|
|
||||||
block.setFieldValue(value, 'WHERE' + n);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
this.getInput('AT' + n)!.appendField(menu, 'WHERE' + n);
|
|
||||||
if (n === 1) {
|
if (n === 1) {
|
||||||
this.moveInputBefore('AT1', 'AT2');
|
this.moveInputBefore('AT1', 'WHERE2_INPUT');
|
||||||
if (this.getInput('ORDINAL1')) {
|
if (this.getInput('ORDINAL1')) {
|
||||||
this.moveInputBefore('ORDINAL1', 'AT2');
|
this.moveInputBefore('ORDINAL1', 'WHERE2_INPUT');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Msg['LISTS_GET_SUBLIST_TAIL']) {
|
if (Msg['LISTS_GET_SUBLIST_TAIL']) {
|
||||||
|
|||||||
@@ -6,22 +6,22 @@
|
|||||||
|
|
||||||
// Former goog.module ID: Blockly.libraryBlocks.logic
|
// Former goog.module ID: Blockly.libraryBlocks.logic
|
||||||
|
|
||||||
import * as Events from '../core/events/events.js';
|
|
||||||
import * as Extensions from '../core/extensions.js';
|
|
||||||
import * as xmlUtils from '../core/utils/xml.js';
|
|
||||||
import type {Abstract as AbstractEvent} from '../core/events/events_abstract.js';
|
|
||||||
import type {Block} from '../core/block.js';
|
import type {Block} from '../core/block.js';
|
||||||
import type {BlockSvg} from '../core/block_svg.js';
|
import type {BlockSvg} from '../core/block_svg.js';
|
||||||
import type {Connection} from '../core/connection.js';
|
|
||||||
import {Msg} from '../core/msg.js';
|
|
||||||
import type {Workspace} from '../core/workspace.js';
|
|
||||||
import {
|
import {
|
||||||
createBlockDefinitionsFromJsonArray,
|
createBlockDefinitionsFromJsonArray,
|
||||||
defineBlocks,
|
defineBlocks,
|
||||||
} from '../core/common.js';
|
} from '../core/common.js';
|
||||||
|
import type {Connection} from '../core/connection.js';
|
||||||
|
import * as Events from '../core/events/events.js';
|
||||||
|
import type {Abstract as AbstractEvent} from '../core/events/events_abstract.js';
|
||||||
|
import * as Extensions from '../core/extensions.js';
|
||||||
import '../core/field_dropdown.js';
|
import '../core/field_dropdown.js';
|
||||||
import '../core/field_label.js';
|
import '../core/field_label.js';
|
||||||
import '../core/icons/mutator_icon.js';
|
import '../core/icons/mutator_icon.js';
|
||||||
|
import {Msg} from '../core/msg.js';
|
||||||
|
import * as xmlUtils from '../core/utils/xml.js';
|
||||||
|
import type {Workspace} from '../core/workspace.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dictionary of the block definitions provided by this module.
|
* A dictionary of the block definitions provided by this module.
|
||||||
|
|||||||
@@ -6,27 +6,27 @@
|
|||||||
|
|
||||||
// Former goog.module ID: Blockly.libraryBlocks.loops
|
// Former goog.module ID: Blockly.libraryBlocks.loops
|
||||||
|
|
||||||
import type {Abstract as AbstractEvent} from '../core/events/events_abstract.js';
|
|
||||||
import type {Block} from '../core/block.js';
|
import type {Block} from '../core/block.js';
|
||||||
|
import {
|
||||||
|
createBlockDefinitionsFromJsonArray,
|
||||||
|
defineBlocks,
|
||||||
|
} from '../core/common.js';
|
||||||
import * as ContextMenu from '../core/contextmenu.js';
|
import * as ContextMenu from '../core/contextmenu.js';
|
||||||
import type {
|
import type {
|
||||||
ContextMenuOption,
|
ContextMenuOption,
|
||||||
LegacyContextMenuOption,
|
LegacyContextMenuOption,
|
||||||
} from '../core/contextmenu_registry.js';
|
} from '../core/contextmenu_registry.js';
|
||||||
import * as Events from '../core/events/events.js';
|
import * as Events from '../core/events/events.js';
|
||||||
import * as Extensions from '../core/extensions.js';
|
import type {Abstract as AbstractEvent} from '../core/events/events_abstract.js';
|
||||||
import {Msg} from '../core/msg.js';
|
|
||||||
import {
|
|
||||||
createBlockDefinitionsFromJsonArray,
|
|
||||||
defineBlocks,
|
|
||||||
} from '../core/common.js';
|
|
||||||
import * as eventUtils from '../core/events/utils.js';
|
import * as eventUtils from '../core/events/utils.js';
|
||||||
|
import * as Extensions from '../core/extensions.js';
|
||||||
import '../core/field_dropdown.js';
|
import '../core/field_dropdown.js';
|
||||||
import '../core/field_label.js';
|
import '../core/field_label.js';
|
||||||
import '../core/field_number.js';
|
import '../core/field_number.js';
|
||||||
import '../core/field_variable.js';
|
import '../core/field_variable.js';
|
||||||
import '../core/icons/warning_icon.js';
|
|
||||||
import {FieldVariable} from '../core/field_variable.js';
|
import {FieldVariable} from '../core/field_variable.js';
|
||||||
|
import '../core/icons/warning_icon.js';
|
||||||
|
import {Msg} from '../core/msg.js';
|
||||||
import {WorkspaceSvg} from '../core/workspace_svg.js';
|
import {WorkspaceSvg} from '../core/workspace_svg.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -6,18 +6,18 @@
|
|||||||
|
|
||||||
// Former goog.module ID: Blockly.libraryBlocks.math
|
// Former goog.module ID: Blockly.libraryBlocks.math
|
||||||
|
|
||||||
import * as Extensions from '../core/extensions.js';
|
|
||||||
import type {FieldDropdown} from '../core/field_dropdown.js';
|
|
||||||
import * as xmlUtils from '../core/utils/xml.js';
|
|
||||||
import type {Block} from '../core/block.js';
|
import type {Block} from '../core/block.js';
|
||||||
import {
|
import {
|
||||||
createBlockDefinitionsFromJsonArray,
|
createBlockDefinitionsFromJsonArray,
|
||||||
defineBlocks,
|
defineBlocks,
|
||||||
} from '../core/common.js';
|
} from '../core/common.js';
|
||||||
|
import * as Extensions from '../core/extensions.js';
|
||||||
import '../core/field_dropdown.js';
|
import '../core/field_dropdown.js';
|
||||||
|
import type {FieldDropdown} from '../core/field_dropdown.js';
|
||||||
import '../core/field_label.js';
|
import '../core/field_label.js';
|
||||||
import '../core/field_number.js';
|
import '../core/field_number.js';
|
||||||
import '../core/field_variable.js';
|
import '../core/field_variable.js';
|
||||||
|
import * as xmlUtils from '../core/utils/xml.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dictionary of the block definitions provided by this module.
|
* A dictionary of the block definitions provided by this module.
|
||||||
|
|||||||
@@ -6,43 +6,43 @@
|
|||||||
|
|
||||||
// Former goog.module ID: Blockly.libraryBlocks.procedures
|
// Former goog.module ID: Blockly.libraryBlocks.procedures
|
||||||
|
|
||||||
import * as ContextMenu from '../core/contextmenu.js';
|
|
||||||
import * as Events from '../core/events/events.js';
|
|
||||||
import * as Procedures from '../core/procedures.js';
|
|
||||||
import * as Variables from '../core/variables.js';
|
|
||||||
import * as Xml from '../core/xml.js';
|
|
||||||
import * as fieldRegistry from '../core/field_registry.js';
|
|
||||||
import * as xmlUtils from '../core/utils/xml.js';
|
|
||||||
import type {Abstract as AbstractEvent} from '../core/events/events_abstract.js';
|
|
||||||
import {Align} from '../core/inputs/align.js';
|
|
||||||
import type {Block} from '../core/block.js';
|
import type {Block} from '../core/block.js';
|
||||||
import type {BlockSvg} from '../core/block_svg.js';
|
import type {BlockSvg} from '../core/block_svg.js';
|
||||||
import type {BlockCreate} from '../core/events/events_block_create.js';
|
|
||||||
import type {BlockChange} from '../core/events/events_block_change.js';
|
|
||||||
import type {BlockDefinition} from '../core/blocks.js';
|
import type {BlockDefinition} from '../core/blocks.js';
|
||||||
|
import * as common from '../core/common.js';
|
||||||
|
import {defineBlocks} from '../core/common.js';
|
||||||
|
import {config} from '../core/config.js';
|
||||||
import type {Connection} from '../core/connection.js';
|
import type {Connection} from '../core/connection.js';
|
||||||
|
import * as ContextMenu from '../core/contextmenu.js';
|
||||||
import type {
|
import type {
|
||||||
ContextMenuOption,
|
ContextMenuOption,
|
||||||
LegacyContextMenuOption,
|
LegacyContextMenuOption,
|
||||||
} from '../core/contextmenu_registry.js';
|
} from '../core/contextmenu_registry.js';
|
||||||
|
import * as Events from '../core/events/events.js';
|
||||||
|
import type {Abstract as AbstractEvent} from '../core/events/events_abstract.js';
|
||||||
|
import type {BlockChange} from '../core/events/events_block_change.js';
|
||||||
|
import type {BlockCreate} from '../core/events/events_block_create.js';
|
||||||
import * as eventUtils from '../core/events/utils.js';
|
import * as eventUtils from '../core/events/utils.js';
|
||||||
import {FieldCheckbox} from '../core/field_checkbox.js';
|
import {FieldCheckbox} from '../core/field_checkbox.js';
|
||||||
import {FieldLabel} from '../core/field_label.js';
|
import {FieldLabel} from '../core/field_label.js';
|
||||||
|
import * as fieldRegistry from '../core/field_registry.js';
|
||||||
import {FieldTextInput} from '../core/field_textinput.js';
|
import {FieldTextInput} from '../core/field_textinput.js';
|
||||||
import {Msg} from '../core/msg.js';
|
import '../core/icons/comment_icon.js';
|
||||||
import {MutatorIcon as Mutator} from '../core/icons/mutator_icon.js';
|
import {MutatorIcon as Mutator} from '../core/icons/mutator_icon.js';
|
||||||
import {Names} from '../core/names.js';
|
import '../core/icons/warning_icon.js';
|
||||||
|
import {Align} from '../core/inputs/align.js';
|
||||||
import type {
|
import type {
|
||||||
IVariableModel,
|
IVariableModel,
|
||||||
IVariableState,
|
IVariableState,
|
||||||
} from '../core/interfaces/i_variable_model.js';
|
} from '../core/interfaces/i_variable_model.js';
|
||||||
|
import {Msg} from '../core/msg.js';
|
||||||
|
import {Names} from '../core/names.js';
|
||||||
|
import * as Procedures from '../core/procedures.js';
|
||||||
|
import * as xmlUtils from '../core/utils/xml.js';
|
||||||
|
import * as Variables from '../core/variables.js';
|
||||||
import type {Workspace} from '../core/workspace.js';
|
import type {Workspace} from '../core/workspace.js';
|
||||||
import type {WorkspaceSvg} from '../core/workspace_svg.js';
|
import type {WorkspaceSvg} from '../core/workspace_svg.js';
|
||||||
import {config} from '../core/config.js';
|
import * as Xml from '../core/xml.js';
|
||||||
import {defineBlocks} from '../core/common.js';
|
|
||||||
import '../core/icons/comment_icon.js';
|
|
||||||
import '../core/icons/warning_icon.js';
|
|
||||||
import * as common from '../core/common.js';
|
|
||||||
|
|
||||||
/** A dictionary of the block definitions provided by this module. */
|
/** A dictionary of the block definitions provided by this module. */
|
||||||
export const blocks: {[key: string]: BlockDefinition} = {};
|
export const blocks: {[key: string]: BlockDefinition} = {};
|
||||||
@@ -1108,6 +1108,14 @@ const PROCEDURE_CALL_COMMON = {
|
|||||||
xml.appendChild(block);
|
xml.appendChild(block);
|
||||||
Xml.domToWorkspace(xml, this.workspace);
|
Xml.domToWorkspace(xml, this.workspace);
|
||||||
Events.setGroup(false);
|
Events.setGroup(false);
|
||||||
|
} else if (!def.isEnabled()) {
|
||||||
|
this.setDisabledReason(
|
||||||
|
true,
|
||||||
|
DISABLED_PROCEDURE_DEFINITION_DISABLED_REASON,
|
||||||
|
);
|
||||||
|
this.setWarningText(
|
||||||
|
Msg['PROCEDURES_CALL_DISABLED_DEF_WARNING'].replace('%1', name),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if (event.type === Events.BLOCK_DELETE) {
|
} else if (event.type === Events.BLOCK_DELETE) {
|
||||||
// Look for the case where a procedure definition has been deleted,
|
// Look for the case where a procedure definition has been deleted,
|
||||||
@@ -1215,7 +1223,7 @@ blocks['procedures_callreturn'] = {
|
|||||||
this.appendDummyInput('TOPROW').appendField('', 'NAME');
|
this.appendDummyInput('TOPROW').appendField('', 'NAME');
|
||||||
this.setOutput(true);
|
this.setOutput(true);
|
||||||
this.setStyle('procedure_blocks');
|
this.setStyle('procedure_blocks');
|
||||||
// Tooltip is set in domToMutation.
|
// Tooltip is set in renameProcedure.
|
||||||
this.setHelpUrl(Msg['PROCEDURES_CALLRETURN_HELPURL']);
|
this.setHelpUrl(Msg['PROCEDURES_CALLRETURN_HELPURL']);
|
||||||
this.arguments_ = [];
|
this.arguments_ = [];
|
||||||
this.argumentVarModels_ = [];
|
this.argumentVarModels_ = [];
|
||||||
|
|||||||
@@ -6,25 +6,25 @@
|
|||||||
|
|
||||||
// Former goog.module ID: Blockly.libraryBlocks.texts
|
// Former goog.module ID: Blockly.libraryBlocks.texts
|
||||||
|
|
||||||
import * as Extensions from '../core/extensions.js';
|
|
||||||
import * as fieldRegistry from '../core/field_registry.js';
|
|
||||||
import * as xmlUtils from '../core/utils/xml.js';
|
|
||||||
import {Align} from '../core/inputs/align.js';
|
|
||||||
import type {Block} from '../core/block.js';
|
import type {Block} from '../core/block.js';
|
||||||
import type {BlockSvg} from '../core/block_svg.js';
|
import type {BlockSvg} from '../core/block_svg.js';
|
||||||
import {Connection} from '../core/connection.js';
|
|
||||||
import {FieldImage} from '../core/field_image.js';
|
|
||||||
import {FieldDropdown} from '../core/field_dropdown.js';
|
|
||||||
import {FieldTextInput} from '../core/field_textinput.js';
|
|
||||||
import {Msg} from '../core/msg.js';
|
|
||||||
import {MutatorIcon} from '../core/icons/mutator_icon.js';
|
|
||||||
import type {Workspace} from '../core/workspace.js';
|
|
||||||
import {
|
import {
|
||||||
createBlockDefinitionsFromJsonArray,
|
createBlockDefinitionsFromJsonArray,
|
||||||
defineBlocks,
|
defineBlocks,
|
||||||
} from '../core/common.js';
|
} from '../core/common.js';
|
||||||
|
import {Connection} from '../core/connection.js';
|
||||||
|
import * as Extensions from '../core/extensions.js';
|
||||||
|
import {FieldDropdown} from '../core/field_dropdown.js';
|
||||||
|
import {FieldImage} from '../core/field_image.js';
|
||||||
|
import * as fieldRegistry from '../core/field_registry.js';
|
||||||
|
import {FieldTextInput} from '../core/field_textinput.js';
|
||||||
import '../core/field_variable.js';
|
import '../core/field_variable.js';
|
||||||
|
import {MutatorIcon} from '../core/icons/mutator_icon.js';
|
||||||
|
import {Align} from '../core/inputs/align.js';
|
||||||
import {ValueInput} from '../core/inputs/value_input.js';
|
import {ValueInput} from '../core/inputs/value_input.js';
|
||||||
|
import {Msg} from '../core/msg.js';
|
||||||
|
import * as xmlUtils from '../core/utils/xml.js';
|
||||||
|
import type {Workspace} from '../core/workspace.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dictionary of the block definitions provided by this module.
|
* A dictionary of the block definitions provided by this module.
|
||||||
@@ -216,7 +216,30 @@ const GET_SUBSTRING_BLOCK = {
|
|||||||
this.appendValueInput('STRING')
|
this.appendValueInput('STRING')
|
||||||
.setCheck('String')
|
.setCheck('String')
|
||||||
.appendField(Msg['TEXT_GET_SUBSTRING_INPUT_IN_TEXT']);
|
.appendField(Msg['TEXT_GET_SUBSTRING_INPUT_IN_TEXT']);
|
||||||
|
const createMenu = (n: 1 | 2): FieldDropdown => {
|
||||||
|
const menu = fieldRegistry.fromJson({
|
||||||
|
type: 'field_dropdown',
|
||||||
|
options:
|
||||||
|
this[('WHERE_OPTIONS_' + n) as 'WHERE_OPTIONS_1' | 'WHERE_OPTIONS_2'],
|
||||||
|
}) as FieldDropdown;
|
||||||
|
menu.setValidator(
|
||||||
|
/** @param value The input value. */
|
||||||
|
function (this: FieldDropdown, value: any): null | undefined {
|
||||||
|
const oldValue: string | null = this.getValue();
|
||||||
|
const oldAt = oldValue === 'FROM_START' || oldValue === 'FROM_END';
|
||||||
|
const newAt = value === 'FROM_START' || value === 'FROM_END';
|
||||||
|
if (newAt !== oldAt) {
|
||||||
|
const block = this.getSourceBlock() as GetSubstringBlock;
|
||||||
|
block.updateAt_(n, newAt);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return menu;
|
||||||
|
};
|
||||||
|
this.appendDummyInput('WHERE1_INPUT').appendField(createMenu(1), 'WHERE1');
|
||||||
this.appendDummyInput('AT1');
|
this.appendDummyInput('AT1');
|
||||||
|
this.appendDummyInput('WHERE2_INPUT').appendField(createMenu(2), 'WHERE2');
|
||||||
this.appendDummyInput('AT2');
|
this.appendDummyInput('AT2');
|
||||||
if (Msg['TEXT_GET_SUBSTRING_TAIL']) {
|
if (Msg['TEXT_GET_SUBSTRING_TAIL']) {
|
||||||
this.appendDummyInput('TAIL').appendField(Msg['TEXT_GET_SUBSTRING_TAIL']);
|
this.appendDummyInput('TAIL').appendField(Msg['TEXT_GET_SUBSTRING_TAIL']);
|
||||||
@@ -288,37 +311,10 @@ const GET_SUBSTRING_BLOCK = {
|
|||||||
this.removeInput('TAIL', true);
|
this.removeInput('TAIL', true);
|
||||||
this.appendDummyInput('TAIL').appendField(Msg['TEXT_GET_SUBSTRING_TAIL']);
|
this.appendDummyInput('TAIL').appendField(Msg['TEXT_GET_SUBSTRING_TAIL']);
|
||||||
}
|
}
|
||||||
const menu = fieldRegistry.fromJson({
|
|
||||||
type: 'field_dropdown',
|
|
||||||
options:
|
|
||||||
this[('WHERE_OPTIONS_' + n) as 'WHERE_OPTIONS_1' | 'WHERE_OPTIONS_2'],
|
|
||||||
}) as FieldDropdown;
|
|
||||||
menu.setValidator(
|
|
||||||
/**
|
|
||||||
* @param value The input value.
|
|
||||||
* @returns Null if the field has been replaced; otherwise undefined.
|
|
||||||
*/
|
|
||||||
function (this: FieldDropdown, value: any): null | undefined {
|
|
||||||
const newAt = value === 'FROM_START' || value === 'FROM_END';
|
|
||||||
// The 'isAt' variable is available due to this function being a
|
|
||||||
// closure.
|
|
||||||
if (newAt !== isAt) {
|
|
||||||
const block = this.getSourceBlock() as GetSubstringBlock;
|
|
||||||
block.updateAt_(n, newAt);
|
|
||||||
// This menu has been destroyed and replaced.
|
|
||||||
// Update the replacement.
|
|
||||||
block.setFieldValue(value, 'WHERE' + n);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
this.getInput('AT' + n)!.appendField(menu, 'WHERE' + n);
|
|
||||||
if (n === 1) {
|
if (n === 1) {
|
||||||
this.moveInputBefore('AT1', 'AT2');
|
this.moveInputBefore('AT1', 'WHERE2_INPUT');
|
||||||
if (this.getInput('ORDINAL1')) {
|
if (this.getInput('ORDINAL1')) {
|
||||||
this.moveInputBefore('ORDINAL1', 'AT2');
|
this.moveInputBefore('ORDINAL1', 'WHERE2_INPUT');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -438,6 +434,11 @@ const PROMPT_COMMON = {
|
|||||||
domToMutation: function (this: PromptCommonBlock, xmlElement: Element) {
|
domToMutation: function (this: PromptCommonBlock, xmlElement: Element) {
|
||||||
this.updateType_(xmlElement.getAttribute('type')!);
|
this.updateType_(xmlElement.getAttribute('type')!);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// These blocks do not need JSO serialization hooks (saveExtraState
|
||||||
|
// and loadExtraState) because the state of this object is already
|
||||||
|
// encoded in the dropdown values.
|
||||||
|
// XML hooks are kept for backwards compatibility.
|
||||||
};
|
};
|
||||||
|
|
||||||
blocks['text_prompt_ext'] = {
|
blocks['text_prompt_ext'] = {
|
||||||
@@ -468,16 +469,11 @@ blocks['text_prompt_ext'] = {
|
|||||||
: Msg['TEXT_PROMPT_TOOLTIP_NUMBER'];
|
: Msg['TEXT_PROMPT_TOOLTIP_NUMBER'];
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// This block does not need JSO serialization hooks (saveExtraState and
|
|
||||||
// loadExtraState) because the state of this object is already encoded in the
|
|
||||||
// dropdown values.
|
|
||||||
// XML hooks are kept for backwards compatibility.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type PromptBlock = Block & PromptCommonMixin & QuoteImageMixin;
|
type PromptBlock = Block & PromptCommonMixin & QuoteImageMixin;
|
||||||
|
|
||||||
const TEXT_PROMPT_BLOCK = {
|
blocks['text_prompt'] = {
|
||||||
...PROMPT_COMMON,
|
...PROMPT_COMMON,
|
||||||
/**
|
/**
|
||||||
* Block for prompt function (internal message).
|
* Block for prompt function (internal message).
|
||||||
@@ -520,8 +516,6 @@ const TEXT_PROMPT_BLOCK = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
blocks['text_prompt'] = TEXT_PROMPT_BLOCK;
|
|
||||||
|
|
||||||
blocks['text_count'] = {
|
blocks['text_count'] = {
|
||||||
/**
|
/**
|
||||||
* Block for counting how many times one string appears within another string.
|
* Block for counting how many times one string appears within another string.
|
||||||
@@ -666,7 +660,7 @@ const QUOTE_IMAGE_MIXIN = {
|
|||||||
* closing double quote. The selected quote will be adapted for RTL blocks.
|
* closing double quote. The selected quote will be adapted for RTL blocks.
|
||||||
*
|
*
|
||||||
* @param open If the image should be open quote (“ in LTR).
|
* @param open If the image should be open quote (“ in LTR).
|
||||||
* Otherwise, a closing quote is used (” in LTR).
|
* Otherwise, a closing quote is used (” in LTR).
|
||||||
* @returns The new field.
|
* @returns The new field.
|
||||||
*/
|
*/
|
||||||
newQuote_: function (this: QuoteImageBlock, open: boolean): FieldImage {
|
newQuote_: function (this: QuoteImageBlock, open: boolean): FieldImage {
|
||||||
|
|||||||
@@ -6,22 +6,22 @@
|
|||||||
|
|
||||||
// Former goog.module ID: Blockly.libraryBlocks.variables
|
// Former goog.module ID: Blockly.libraryBlocks.variables
|
||||||
|
|
||||||
import * as ContextMenu from '../core/contextmenu.js';
|
|
||||||
import * as Extensions from '../core/extensions.js';
|
|
||||||
import * as Variables from '../core/variables.js';
|
|
||||||
import type {Block} from '../core/block.js';
|
import type {Block} from '../core/block.js';
|
||||||
import type {
|
|
||||||
ContextMenuOption,
|
|
||||||
LegacyContextMenuOption,
|
|
||||||
} from '../core/contextmenu_registry.js';
|
|
||||||
import {FieldVariable} from '../core/field_variable.js';
|
|
||||||
import {Msg} from '../core/msg.js';
|
|
||||||
import type {WorkspaceSvg} from '../core/workspace_svg.js';
|
|
||||||
import {
|
import {
|
||||||
createBlockDefinitionsFromJsonArray,
|
createBlockDefinitionsFromJsonArray,
|
||||||
defineBlocks,
|
defineBlocks,
|
||||||
} from '../core/common.js';
|
} from '../core/common.js';
|
||||||
|
import * as ContextMenu from '../core/contextmenu.js';
|
||||||
|
import type {
|
||||||
|
ContextMenuOption,
|
||||||
|
LegacyContextMenuOption,
|
||||||
|
} from '../core/contextmenu_registry.js';
|
||||||
|
import * as Extensions from '../core/extensions.js';
|
||||||
import '../core/field_label.js';
|
import '../core/field_label.js';
|
||||||
|
import {FieldVariable} from '../core/field_variable.js';
|
||||||
|
import {Msg} from '../core/msg.js';
|
||||||
|
import * as Variables from '../core/variables.js';
|
||||||
|
import type {WorkspaceSvg} from '../core/workspace_svg.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dictionary of the block definitions provided by this module.
|
* A dictionary of the block definitions provided by this module.
|
||||||
|
|||||||
@@ -6,23 +6,23 @@
|
|||||||
|
|
||||||
// Former goog.module ID: Blockly.libraryBlocks.variablesDynamic
|
// Former goog.module ID: Blockly.libraryBlocks.variablesDynamic
|
||||||
|
|
||||||
import * as ContextMenu from '../core/contextmenu.js';
|
|
||||||
import * as Extensions from '../core/extensions.js';
|
|
||||||
import * as Variables from '../core/variables.js';
|
|
||||||
import {Abstract as AbstractEvent} from '../core/events/events_abstract.js';
|
|
||||||
import type {Block} from '../core/block.js';
|
import type {Block} from '../core/block.js';
|
||||||
import type {
|
|
||||||
ContextMenuOption,
|
|
||||||
LegacyContextMenuOption,
|
|
||||||
} from '../core/contextmenu_registry.js';
|
|
||||||
import {FieldVariable} from '../core/field_variable.js';
|
|
||||||
import {Msg} from '../core/msg.js';
|
|
||||||
import type {WorkspaceSvg} from '../core/workspace_svg.js';
|
|
||||||
import {
|
import {
|
||||||
createBlockDefinitionsFromJsonArray,
|
createBlockDefinitionsFromJsonArray,
|
||||||
defineBlocks,
|
defineBlocks,
|
||||||
} from '../core/common.js';
|
} from '../core/common.js';
|
||||||
|
import * as ContextMenu from '../core/contextmenu.js';
|
||||||
|
import type {
|
||||||
|
ContextMenuOption,
|
||||||
|
LegacyContextMenuOption,
|
||||||
|
} from '../core/contextmenu_registry.js';
|
||||||
|
import {Abstract as AbstractEvent} from '../core/events/events_abstract.js';
|
||||||
|
import * as Extensions from '../core/extensions.js';
|
||||||
import '../core/field_label.js';
|
import '../core/field_label.js';
|
||||||
|
import {FieldVariable} from '../core/field_variable.js';
|
||||||
|
import {Msg} from '../core/msg.js';
|
||||||
|
import * as Variables from '../core/variables.js';
|
||||||
|
import type {WorkspaceSvg} from '../core/workspace_svg.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dictionary of the block definitions provided by this module.
|
* A dictionary of the block definitions provided by this module.
|
||||||
|
|||||||
236
core/block.ts
236
core/block.ts
@@ -23,38 +23,39 @@ import * as common from './common.js';
|
|||||||
import {Connection} from './connection.js';
|
import {Connection} from './connection.js';
|
||||||
import {ConnectionType} from './connection_type.js';
|
import {ConnectionType} from './connection_type.js';
|
||||||
import * as constants from './constants.js';
|
import * as constants from './constants.js';
|
||||||
import {DuplicateIconType} from './icons/exceptions.js';
|
|
||||||
import type {Abstract} from './events/events_abstract.js';
|
import type {Abstract} from './events/events_abstract.js';
|
||||||
import type {BlockChange} from './events/events_block_change.js';
|
import type {BlockChange} from './events/events_block_change.js';
|
||||||
import type {BlockMove} from './events/events_block_move.js';
|
import type {BlockMove} from './events/events_block_move.js';
|
||||||
import * as deprecation from './utils/deprecation.js';
|
import {EventType} from './events/type.js';
|
||||||
import * as eventUtils from './events/utils.js';
|
import * as eventUtils from './events/utils.js';
|
||||||
import * as Extensions from './extensions.js';
|
import * as Extensions from './extensions.js';
|
||||||
import type {Field} from './field.js';
|
import type {Field} from './field.js';
|
||||||
import * as fieldRegistry from './field_registry.js';
|
import * as fieldRegistry from './field_registry.js';
|
||||||
import {Input} from './inputs/input.js';
|
import {DuplicateIconType} from './icons/exceptions.js';
|
||||||
import {Align} from './inputs/align.js';
|
import {IconType} from './icons/icon_types.js';
|
||||||
import type {IASTNodeLocation} from './interfaces/i_ast_node_location.js';
|
|
||||||
import {type IIcon} from './interfaces/i_icon.js';
|
|
||||||
import {isCommentIcon} from './interfaces/i_comment_icon.js';
|
|
||||||
import type {MutatorIcon} from './icons/mutator_icon.js';
|
import type {MutatorIcon} from './icons/mutator_icon.js';
|
||||||
|
import {Align} from './inputs/align.js';
|
||||||
|
import {DummyInput} from './inputs/dummy_input.js';
|
||||||
|
import {EndRowInput} from './inputs/end_row_input.js';
|
||||||
|
import {Input} from './inputs/input.js';
|
||||||
|
import {StatementInput} from './inputs/statement_input.js';
|
||||||
|
import {ValueInput} from './inputs/value_input.js';
|
||||||
|
import type {IASTNodeLocation} from './interfaces/i_ast_node_location.js';
|
||||||
|
import {isCommentIcon} from './interfaces/i_comment_icon.js';
|
||||||
|
import {type IIcon} from './interfaces/i_icon.js';
|
||||||
|
import * as registry from './registry.js';
|
||||||
import * as Tooltip from './tooltip.js';
|
import * as Tooltip from './tooltip.js';
|
||||||
import * as arrayUtils from './utils/array.js';
|
import * as arrayUtils from './utils/array.js';
|
||||||
import {Coordinate} from './utils/coordinate.js';
|
import {Coordinate} from './utils/coordinate.js';
|
||||||
|
import * as deprecation from './utils/deprecation.js';
|
||||||
import * as idGenerator from './utils/idgenerator.js';
|
import * as idGenerator from './utils/idgenerator.js';
|
||||||
import * as parsing from './utils/parsing.js';
|
import * as parsing from './utils/parsing.js';
|
||||||
import * as registry from './registry.js';
|
|
||||||
import {Size} from './utils/size.js';
|
import {Size} from './utils/size.js';
|
||||||
import type {
|
import type {
|
||||||
IVariableModel,
|
IVariableModel,
|
||||||
IVariableState,
|
IVariableState,
|
||||||
} from './interfaces/i_variable_model.js';
|
} from './interfaces/i_variable_model.js';
|
||||||
import type {Workspace} from './workspace.js';
|
import type {Workspace} from './workspace.js';
|
||||||
import {DummyInput} from './inputs/dummy_input.js';
|
|
||||||
import {EndRowInput} from './inputs/end_row_input.js';
|
|
||||||
import {ValueInput} from './inputs/value_input.js';
|
|
||||||
import {StatementInput} from './inputs/statement_input.js';
|
|
||||||
import {IconType} from './icons/icon_types.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for one block.
|
* Class for one block.
|
||||||
@@ -91,7 +92,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* Colour of the block as HSV hue value (0-360)
|
* Colour of the block as HSV hue value (0-360)
|
||||||
* This may be null if the block colour was not set via a hue number.
|
* This may be null if the block colour was not set via a hue number.
|
||||||
*/
|
*/
|
||||||
private hue_: number | null = null;
|
private hue: number | null = null;
|
||||||
|
|
||||||
/** Colour of the block in '#RRGGBB' format. */
|
/** Colour of the block in '#RRGGBB' format. */
|
||||||
protected colour_ = '#000000';
|
protected colour_ = '#000000';
|
||||||
@@ -146,24 +147,31 @@ export class Block implements IASTNodeLocation {
|
|||||||
suppressPrefixSuffix: boolean | null = false;
|
suppressPrefixSuffix: boolean | null = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An optional property for declaring developer variables. Return a list of
|
* An optional method for declaring developer variables, to be used
|
||||||
* variable names for use by generators. Developer variables are never
|
* by generators. Developer variables are never shown to the user,
|
||||||
* shown to the user, but are declared as global variables in the generated
|
* but are declared as global variables in the generated code.
|
||||||
* code.
|
*
|
||||||
|
* @returns a list of developer variable names.
|
||||||
*/
|
*/
|
||||||
getDeveloperVariables?: () => string[];
|
getDeveloperVariables?: () => string[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An optional function that reconfigures the block based on the contents of
|
* An optional method that reconfigures the block based on the
|
||||||
* the mutator dialog.
|
* contents of the mutator dialog.
|
||||||
|
*
|
||||||
|
* @param rootBlock The root block in the mutator flyout.
|
||||||
*/
|
*/
|
||||||
compose?: (p1: Block) => void;
|
compose?: (rootBlock: Block) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An optional function that populates the mutator's dialog with
|
* An optional function that populates the mutator flyout with
|
||||||
* this block's components.
|
* blocks representing this block's configuration.
|
||||||
|
*
|
||||||
|
* @param workspace The mutator flyout's workspace.
|
||||||
|
* @returns The root block created in the flyout's workspace.
|
||||||
*/
|
*/
|
||||||
decompose?: (p1: Workspace) => Block;
|
decompose?: (workspace: Workspace) => Block;
|
||||||
|
|
||||||
id: string;
|
id: string;
|
||||||
outputConnection: Connection | null = null;
|
outputConnection: Connection | null = null;
|
||||||
nextConnection: Connection | null = null;
|
nextConnection: Connection | null = null;
|
||||||
@@ -179,13 +187,13 @@ export class Block implements IASTNodeLocation {
|
|||||||
|
|
||||||
protected childBlocks_: this[] = [];
|
protected childBlocks_: this[] = [];
|
||||||
|
|
||||||
private deletable_ = true;
|
private deletable = true;
|
||||||
|
|
||||||
private movable_ = true;
|
private movable = true;
|
||||||
|
|
||||||
private editable_ = true;
|
private editable = true;
|
||||||
|
|
||||||
private isShadow_ = false;
|
private shadow = false;
|
||||||
|
|
||||||
protected collapsed_ = false;
|
protected collapsed_ = false;
|
||||||
protected outputShape_: number | null = null;
|
protected outputShape_: number | null = null;
|
||||||
@@ -202,7 +210,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
*/
|
*/
|
||||||
initialized = false;
|
initialized = false;
|
||||||
|
|
||||||
private readonly xy_: Coordinate;
|
private readonly xy: Coordinate;
|
||||||
isInFlyout: boolean;
|
isInFlyout: boolean;
|
||||||
isInMutator: boolean;
|
isInMutator: boolean;
|
||||||
RTL: boolean;
|
RTL: boolean;
|
||||||
@@ -219,10 +227,10 @@ export class Block implements IASTNodeLocation {
|
|||||||
/**
|
/**
|
||||||
* String for block help, or function that returns a URL. Null for no help.
|
* String for block help, or function that returns a URL. Null for no help.
|
||||||
*/
|
*/
|
||||||
helpUrl: string | Function | null = null;
|
helpUrl: string | (() => string) | null = null;
|
||||||
|
|
||||||
/** A bound callback function to use when the parent workspace changes. */
|
/** A bound callback function to use when the parent workspace changes. */
|
||||||
private onchangeWrapper_: ((p1: Abstract) => void) | null = null;
|
private onchangeWrapper: ((p1: Abstract) => void) | null = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A count of statement inputs on the block.
|
* A count of statement inputs on the block.
|
||||||
@@ -255,7 +263,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* The block's position in workspace units. (0, 0) is at the workspace's
|
* The block's position in workspace units. (0, 0) is at the workspace's
|
||||||
* origin; scale does not change this value.
|
* origin; scale does not change this value.
|
||||||
*/
|
*/
|
||||||
this.xy_ = new Coordinate(0, 0);
|
this.xy = new Coordinate(0, 0);
|
||||||
this.isInFlyout = workspace.isFlyout;
|
this.isInFlyout = workspace.isFlyout;
|
||||||
this.isInMutator = workspace.isMutator;
|
this.isInMutator = workspace.isMutator;
|
||||||
|
|
||||||
@@ -300,7 +308,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
|
|
||||||
// Fire a create event.
|
// Fire a create event.
|
||||||
if (eventUtils.isEnabled()) {
|
if (eventUtils.isEnabled()) {
|
||||||
eventUtils.fire(new (eventUtils.get(eventUtils.BLOCK_CREATE))(this));
|
eventUtils.fire(new (eventUtils.get(EventType.BLOCK_CREATE))(this));
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
eventUtils.setGroup(existingGroup);
|
eventUtils.setGroup(existingGroup);
|
||||||
@@ -328,14 +336,14 @@ export class Block implements IASTNodeLocation {
|
|||||||
// Dispose of this change listener before unplugging.
|
// Dispose of this change listener before unplugging.
|
||||||
// Technically not necessary due to the event firing delay.
|
// Technically not necessary due to the event firing delay.
|
||||||
// But future-proofing.
|
// But future-proofing.
|
||||||
if (this.onchangeWrapper_) {
|
if (this.onchangeWrapper) {
|
||||||
this.workspace.removeChangeListener(this.onchangeWrapper_);
|
this.workspace.removeChangeListener(this.onchangeWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.unplug(healStack);
|
this.unplug(healStack);
|
||||||
if (eventUtils.isEnabled()) {
|
if (eventUtils.isEnabled()) {
|
||||||
// Constructing the delete event is costly. Only perform if necessary.
|
// Constructing the delete event is costly. Only perform if necessary.
|
||||||
eventUtils.fire(new (eventUtils.get(eventUtils.BLOCK_DELETE))(this));
|
eventUtils.fire(new (eventUtils.get(EventType.BLOCK_DELETE))(this));
|
||||||
}
|
}
|
||||||
this.workspace.removeTopBlock(this);
|
this.workspace.removeTopBlock(this);
|
||||||
this.disposeInternal();
|
this.disposeInternal();
|
||||||
@@ -347,8 +355,8 @@ export class Block implements IASTNodeLocation {
|
|||||||
*/
|
*/
|
||||||
protected disposeInternal() {
|
protected disposeInternal() {
|
||||||
this.disposing = true;
|
this.disposing = true;
|
||||||
if (this.onchangeWrapper_) {
|
if (this.onchangeWrapper) {
|
||||||
this.workspace.removeChangeListener(this.onchangeWrapper_);
|
this.workspace.removeChangeListener(this.onchangeWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.workspace.removeTypedBlock(this);
|
this.workspace.removeTypedBlock(this);
|
||||||
@@ -398,10 +406,10 @@ export class Block implements IASTNodeLocation {
|
|||||||
*/
|
*/
|
||||||
unplug(opt_healStack?: boolean) {
|
unplug(opt_healStack?: boolean) {
|
||||||
if (this.outputConnection) {
|
if (this.outputConnection) {
|
||||||
this.unplugFromRow_(opt_healStack);
|
this.unplugFromRow(opt_healStack);
|
||||||
}
|
}
|
||||||
if (this.previousConnection) {
|
if (this.previousConnection) {
|
||||||
this.unplugFromStack_(opt_healStack);
|
this.unplugFromStack(opt_healStack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,7 +420,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @param opt_healStack Disconnect right-side block and connect to left-side
|
* @param opt_healStack Disconnect right-side block and connect to left-side
|
||||||
* block. Defaults to false.
|
* block. Defaults to false.
|
||||||
*/
|
*/
|
||||||
private unplugFromRow_(opt_healStack?: boolean) {
|
private unplugFromRow(opt_healStack?: boolean) {
|
||||||
let parentConnection = null;
|
let parentConnection = null;
|
||||||
if (this.outputConnection?.isConnected()) {
|
if (this.outputConnection?.isConnected()) {
|
||||||
parentConnection = this.outputConnection.targetConnection;
|
parentConnection = this.outputConnection.targetConnection;
|
||||||
@@ -425,7 +433,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const thisConnection = this.getOnlyValueConnection_();
|
const thisConnection = this.getOnlyValueConnection();
|
||||||
if (
|
if (
|
||||||
!thisConnection ||
|
!thisConnection ||
|
||||||
!thisConnection.isConnected() ||
|
!thisConnection.isConnected() ||
|
||||||
@@ -462,7 +470,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
*
|
*
|
||||||
* @returns The connection on the value input, or null.
|
* @returns The connection on the value input, or null.
|
||||||
*/
|
*/
|
||||||
private getOnlyValueConnection_(): Connection | null {
|
private getOnlyValueConnection(): Connection | null {
|
||||||
let connection = null;
|
let connection = null;
|
||||||
for (let i = 0; i < this.inputList.length; i++) {
|
for (let i = 0; i < this.inputList.length; i++) {
|
||||||
const thisConnection = this.inputList[i].connection;
|
const thisConnection = this.inputList[i].connection;
|
||||||
@@ -487,7 +495,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @param opt_healStack Disconnect child statement and reconnect stack.
|
* @param opt_healStack Disconnect child statement and reconnect stack.
|
||||||
* Defaults to false.
|
* Defaults to false.
|
||||||
*/
|
*/
|
||||||
private unplugFromStack_(opt_healStack?: boolean) {
|
private unplugFromStack(opt_healStack?: boolean) {
|
||||||
let previousTarget = null;
|
let previousTarget = null;
|
||||||
if (this.previousConnection?.isConnected()) {
|
if (this.previousConnection?.isConnected()) {
|
||||||
// Remember the connection that any next statements need to connect to.
|
// Remember the connection that any next statements need to connect to.
|
||||||
@@ -719,7 +727,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check that block is connected to new parent if new parent is not null and
|
// Check that block is connected to new parent if new parent is not null and
|
||||||
// that block is not connected to superior one if new parent is null.
|
// that block is not connected to superior one if new parent is null.
|
||||||
const targetBlock =
|
const targetBlock =
|
||||||
(this.previousConnection && this.previousConnection.targetBlock()) ||
|
(this.previousConnection && this.previousConnection.targetBlock()) ||
|
||||||
(this.outputConnection && this.outputConnection.targetBlock());
|
(this.outputConnection && this.outputConnection.targetBlock());
|
||||||
@@ -737,14 +745,13 @@ export class Block implements IASTNodeLocation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This block hasn't actually moved on-screen, so there's no need to
|
// This block hasn't actually moved on-screen, so there's no need to
|
||||||
// update
|
// update its connection locations.
|
||||||
// its connection locations.
|
|
||||||
if (this.parentBlock_) {
|
if (this.parentBlock_) {
|
||||||
// Remove this block from the old parent's child list.
|
// Remove this block from the old parent's child list.
|
||||||
arrayUtils.removeElem(this.parentBlock_.childBlocks_, this);
|
arrayUtils.removeElem(this.parentBlock_.childBlocks_, this);
|
||||||
} else {
|
} else {
|
||||||
// New parent must be non-null so remove this block from the workspace's
|
// New parent must be non-null so remove this block from the
|
||||||
// list of top-most blocks.
|
// workspace's list of top-most blocks.
|
||||||
this.workspace.removeTopBlock(this);
|
this.workspace.removeTopBlock(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -785,8 +792,8 @@ export class Block implements IASTNodeLocation {
|
|||||||
*/
|
*/
|
||||||
isDeletable(): boolean {
|
isDeletable(): boolean {
|
||||||
return (
|
return (
|
||||||
this.deletable_ &&
|
this.deletable &&
|
||||||
!this.isShadow_ &&
|
!this.shadow &&
|
||||||
!this.isDeadOrDying() &&
|
!this.isDeadOrDying() &&
|
||||||
!this.workspace.options.readOnly
|
!this.workspace.options.readOnly
|
||||||
);
|
);
|
||||||
@@ -798,7 +805,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @returns True if the block's deletable property is true, false otherwise.
|
* @returns True if the block's deletable property is true, false otherwise.
|
||||||
*/
|
*/
|
||||||
isOwnDeletable(): boolean {
|
isOwnDeletable(): boolean {
|
||||||
return this.deletable_;
|
return this.deletable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -807,7 +814,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @param deletable True if deletable.
|
* @param deletable True if deletable.
|
||||||
*/
|
*/
|
||||||
setDeletable(deletable: boolean) {
|
setDeletable(deletable: boolean) {
|
||||||
this.deletable_ = deletable;
|
this.deletable = deletable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -818,8 +825,8 @@ export class Block implements IASTNodeLocation {
|
|||||||
*/
|
*/
|
||||||
isMovable(): boolean {
|
isMovable(): boolean {
|
||||||
return (
|
return (
|
||||||
this.movable_ &&
|
this.movable &&
|
||||||
!this.isShadow_ &&
|
!this.shadow &&
|
||||||
!this.isDeadOrDying() &&
|
!this.isDeadOrDying() &&
|
||||||
!this.workspace.options.readOnly
|
!this.workspace.options.readOnly
|
||||||
);
|
);
|
||||||
@@ -832,7 +839,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
isOwnMovable(): boolean {
|
isOwnMovable(): boolean {
|
||||||
return this.movable_;
|
return this.movable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -841,7 +848,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @param movable True if movable.
|
* @param movable True if movable.
|
||||||
*/
|
*/
|
||||||
setMovable(movable: boolean) {
|
setMovable(movable: boolean) {
|
||||||
this.movable_ = movable;
|
this.movable = movable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -867,7 +874,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @returns True if a shadow.
|
* @returns True if a shadow.
|
||||||
*/
|
*/
|
||||||
isShadow(): boolean {
|
isShadow(): boolean {
|
||||||
return this.isShadow_;
|
return this.shadow;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -879,7 +886,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
setShadow(shadow: boolean) {
|
setShadow(shadow: boolean) {
|
||||||
this.isShadow_ = shadow;
|
this.shadow = shadow;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -910,9 +917,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
*/
|
*/
|
||||||
isEditable(): boolean {
|
isEditable(): boolean {
|
||||||
return (
|
return (
|
||||||
this.editable_ &&
|
this.editable && !this.isDeadOrDying() && !this.workspace.options.readOnly
|
||||||
!this.isDeadOrDying() &&
|
|
||||||
!this.workspace.options.readOnly
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -922,7 +927,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @returns True if the block's editable property is true, false otherwise.
|
* @returns True if the block's editable property is true, false otherwise.
|
||||||
*/
|
*/
|
||||||
isOwnEditable(): boolean {
|
isOwnEditable(): boolean {
|
||||||
return this.editable_;
|
return this.editable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -931,7 +936,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @param editable True if editable.
|
* @param editable True if editable.
|
||||||
*/
|
*/
|
||||||
setEditable(editable: boolean) {
|
setEditable(editable: boolean) {
|
||||||
this.editable_ = editable;
|
this.editable = editable;
|
||||||
for (let i = 0, input; (input = this.inputList[i]); i++) {
|
for (let i = 0, input; (input = this.inputList[i]); i++) {
|
||||||
for (let j = 0, field; (field = input.fieldRow[j]); j++) {
|
for (let j = 0, field; (field = input.fieldRow[j]); j++) {
|
||||||
field.updateEditable();
|
field.updateEditable();
|
||||||
@@ -994,7 +999,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @param url URL string for block help, or function that returns a URL. Null
|
* @param url URL string for block help, or function that returns a URL. Null
|
||||||
* for no help.
|
* for no help.
|
||||||
*/
|
*/
|
||||||
setHelpUrl(url: string | Function) {
|
setHelpUrl(url: string | (() => string)) {
|
||||||
this.helpUrl = url;
|
this.helpUrl = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1042,7 +1047,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @returns Hue value (0-360).
|
* @returns Hue value (0-360).
|
||||||
*/
|
*/
|
||||||
getHue(): number | null {
|
getHue(): number | null {
|
||||||
return this.hue_;
|
return this.hue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1053,7 +1058,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
*/
|
*/
|
||||||
setColour(colour: number | string) {
|
setColour(colour: number | string) {
|
||||||
const parsed = parsing.parseBlockColour(colour);
|
const parsed = parsing.parseBlockColour(colour);
|
||||||
this.hue_ = parsed.hue;
|
this.hue = parsed.hue;
|
||||||
this.colour_ = parsed.hex;
|
this.colour_ = parsed.hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1079,12 +1084,12 @@ export class Block implements IASTNodeLocation {
|
|||||||
if (onchangeFn && typeof onchangeFn !== 'function') {
|
if (onchangeFn && typeof onchangeFn !== 'function') {
|
||||||
throw Error('onchange must be a function.');
|
throw Error('onchange must be a function.');
|
||||||
}
|
}
|
||||||
if (this.onchangeWrapper_) {
|
if (this.onchangeWrapper) {
|
||||||
this.workspace.removeChangeListener(this.onchangeWrapper_);
|
this.workspace.removeChangeListener(this.onchangeWrapper);
|
||||||
}
|
}
|
||||||
this.onchange = onchangeFn;
|
this.onchange = onchangeFn;
|
||||||
this.onchangeWrapper_ = onchangeFn.bind(this);
|
this.onchangeWrapper = onchangeFn.bind(this);
|
||||||
this.workspace.addChangeListener(this.onchangeWrapper_);
|
this.workspace.addChangeListener(this.onchangeWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1326,7 +1331,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
setInputsInline(newBoolean: boolean) {
|
setInputsInline(newBoolean: boolean) {
|
||||||
if (this.inputsInline !== newBoolean) {
|
if (this.inputsInline !== newBoolean) {
|
||||||
eventUtils.fire(
|
eventUtils.fire(
|
||||||
new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
|
new (eventUtils.get(EventType.BLOCK_CHANGE))(
|
||||||
this,
|
this,
|
||||||
'inline',
|
'inline',
|
||||||
null,
|
null,
|
||||||
@@ -1463,13 +1468,32 @@ export class Block implements IASTNodeLocation {
|
|||||||
* update whether the block is currently disabled for this reason.
|
* update whether the block is currently disabled for this reason.
|
||||||
*/
|
*/
|
||||||
setDisabledReason(disabled: boolean, reason: string): void {
|
setDisabledReason(disabled: boolean, reason: string): void {
|
||||||
|
// Workspaces that were serialized before the reason for being disabled
|
||||||
|
// could be specified may have blocks that are disabled without a known
|
||||||
|
// reason. On being loaded, these blocks will default to having the manually
|
||||||
|
// disabled reason. However, if the user isn't allowed to manually disable
|
||||||
|
// or enable blocks, then this manually disabled reason cannot be removed.
|
||||||
|
// For backward compatibility with these legacy workspaces, when removing
|
||||||
|
// any disabled reason and the workspace does not allow manually disabling
|
||||||
|
// but the block is manually disabled, then remove the manually disabled
|
||||||
|
// reason in addition to the more specific reason. For example, when an
|
||||||
|
// orphaned block is no longer orphaned, the block should be enabled again.
|
||||||
|
if (
|
||||||
|
!disabled &&
|
||||||
|
!this.workspace.options.disable &&
|
||||||
|
this.hasDisabledReason(constants.MANUALLY_DISABLED) &&
|
||||||
|
reason != constants.MANUALLY_DISABLED
|
||||||
|
) {
|
||||||
|
this.setDisabledReason(false, constants.MANUALLY_DISABLED);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.disabledReasons.has(reason) !== disabled) {
|
if (this.disabledReasons.has(reason) !== disabled) {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
this.disabledReasons.add(reason);
|
this.disabledReasons.add(reason);
|
||||||
} else {
|
} else {
|
||||||
this.disabledReasons.delete(reason);
|
this.disabledReasons.delete(reason);
|
||||||
}
|
}
|
||||||
const blockChangeEvent = new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
|
const blockChangeEvent = new (eventUtils.get(EventType.BLOCK_CHANGE))(
|
||||||
this,
|
this,
|
||||||
'disabled',
|
'disabled',
|
||||||
/* name= */ null,
|
/* name= */ null,
|
||||||
@@ -1537,7 +1561,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
setCollapsed(collapsed: boolean) {
|
setCollapsed(collapsed: boolean) {
|
||||||
if (this.collapsed_ !== collapsed) {
|
if (this.collapsed_ !== collapsed) {
|
||||||
eventUtils.fire(
|
eventUtils.fire(
|
||||||
new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
|
new (eventUtils.get(EventType.BLOCK_CHANGE))(
|
||||||
this,
|
this,
|
||||||
'collapsed',
|
'collapsed',
|
||||||
null,
|
null,
|
||||||
@@ -1751,15 +1775,15 @@ export class Block implements IASTNodeLocation {
|
|||||||
if (json['style'] && json['colour']) {
|
if (json['style'] && json['colour']) {
|
||||||
throw Error(warningPrefix + 'Must not have both a colour and a style.');
|
throw Error(warningPrefix + 'Must not have both a colour and a style.');
|
||||||
} else if (json['style']) {
|
} else if (json['style']) {
|
||||||
this.jsonInitStyle_(json, warningPrefix);
|
this.jsonInitStyle(json, warningPrefix);
|
||||||
} else {
|
} else {
|
||||||
this.jsonInitColour_(json, warningPrefix);
|
this.jsonInitColour(json, warningPrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpolate the message blocks.
|
// Interpolate the message blocks.
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while (json['message' + i] !== undefined) {
|
while (json['message' + i] !== undefined) {
|
||||||
this.interpolate_(
|
this.interpolate(
|
||||||
json['message' + i],
|
json['message' + i],
|
||||||
json['args' + i] || [],
|
json['args' + i] || [],
|
||||||
// Backwards compatibility: lastDummyAlign aliases implicitAlign.
|
// Backwards compatibility: lastDummyAlign aliases implicitAlign.
|
||||||
@@ -1834,7 +1858,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @param json Structured data describing the block.
|
* @param json Structured data describing the block.
|
||||||
* @param warningPrefix Warning prefix string identifying block.
|
* @param warningPrefix Warning prefix string identifying block.
|
||||||
*/
|
*/
|
||||||
private jsonInitColour_(json: AnyDuringMigration, warningPrefix: string) {
|
private jsonInitColour(json: AnyDuringMigration, warningPrefix: string) {
|
||||||
if ('colour' in json) {
|
if ('colour' in json) {
|
||||||
if (json['colour'] === undefined) {
|
if (json['colour'] === undefined) {
|
||||||
console.warn(warningPrefix + 'Undefined colour value.');
|
console.warn(warningPrefix + 'Undefined colour value.');
|
||||||
@@ -1842,7 +1866,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
const rawValue = json['colour'];
|
const rawValue = json['colour'];
|
||||||
try {
|
try {
|
||||||
this.setColour(rawValue);
|
this.setColour(rawValue);
|
||||||
} catch (e) {
|
} catch {
|
||||||
console.warn(warningPrefix + 'Illegal colour value: ', rawValue);
|
console.warn(warningPrefix + 'Illegal colour value: ', rawValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1855,11 +1879,11 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @param json Structured data describing the block.
|
* @param json Structured data describing the block.
|
||||||
* @param warningPrefix Warning prefix string identifying block.
|
* @param warningPrefix Warning prefix string identifying block.
|
||||||
*/
|
*/
|
||||||
private jsonInitStyle_(json: AnyDuringMigration, warningPrefix: string) {
|
private jsonInitStyle(json: AnyDuringMigration, warningPrefix: string) {
|
||||||
const blockStyleName = json['style'];
|
const blockStyleName = json['style'];
|
||||||
try {
|
try {
|
||||||
this.setStyle(blockStyleName);
|
this.setStyle(blockStyleName);
|
||||||
} catch (styleError) {
|
} catch {
|
||||||
console.warn(warningPrefix + 'Style does not exist: ', blockStyleName);
|
console.warn(warningPrefix + 'Style does not exist: ', blockStyleName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1907,21 +1931,21 @@ export class Block implements IASTNodeLocation {
|
|||||||
* of newline tokens, how should it be aligned?
|
* of newline tokens, how should it be aligned?
|
||||||
* @param warningPrefix Warning prefix string identifying block.
|
* @param warningPrefix Warning prefix string identifying block.
|
||||||
*/
|
*/
|
||||||
private interpolate_(
|
private interpolate(
|
||||||
message: string,
|
message: string,
|
||||||
args: AnyDuringMigration[],
|
args: AnyDuringMigration[],
|
||||||
implicitAlign: string | undefined,
|
implicitAlign: string | undefined,
|
||||||
warningPrefix: string,
|
warningPrefix: string,
|
||||||
) {
|
) {
|
||||||
const tokens = parsing.tokenizeInterpolation(message);
|
const tokens = parsing.tokenizeInterpolation(message);
|
||||||
this.validateTokens_(tokens, args.length);
|
this.validateTokens(tokens, args.length);
|
||||||
const elements = this.interpolateArguments_(tokens, args, implicitAlign);
|
const elements = this.interpolateArguments(tokens, args, implicitAlign);
|
||||||
|
|
||||||
// An array of [field, fieldName] tuples.
|
// An array of [field, fieldName] tuples.
|
||||||
const fieldStack = [];
|
const fieldStack = [];
|
||||||
for (let i = 0, element; (element = elements[i]); i++) {
|
for (let i = 0, element; (element = elements[i]); i++) {
|
||||||
if (this.isInputKeyword_(element['type'])) {
|
if (this.isInputKeyword(element['type'])) {
|
||||||
const input = this.inputFromJson_(element, warningPrefix);
|
const input = this.inputFromJson(element, warningPrefix);
|
||||||
// Should never be null, but just in case.
|
// Should never be null, but just in case.
|
||||||
if (input) {
|
if (input) {
|
||||||
for (let j = 0, tuple; (tuple = fieldStack[j]); j++) {
|
for (let j = 0, tuple; (tuple = fieldStack[j]); j++) {
|
||||||
@@ -1932,7 +1956,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
} else {
|
} else {
|
||||||
// All other types, including ones starting with 'input_' get routed
|
// All other types, including ones starting with 'input_' get routed
|
||||||
// here.
|
// here.
|
||||||
const field = this.fieldFromJson_(element);
|
const field = this.fieldFromJson(element);
|
||||||
if (field) {
|
if (field) {
|
||||||
fieldStack.push([field, element['name']]);
|
fieldStack.push([field, element['name']]);
|
||||||
}
|
}
|
||||||
@@ -1948,7 +1972,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @param tokens An array of tokens to validate
|
* @param tokens An array of tokens to validate
|
||||||
* @param argsCount The number of args that need to be referred to.
|
* @param argsCount The number of args that need to be referred to.
|
||||||
*/
|
*/
|
||||||
private validateTokens_(tokens: Array<string | number>, argsCount: number) {
|
private validateTokens(tokens: Array<string | number>, argsCount: number) {
|
||||||
const visitedArgsHash = [];
|
const visitedArgsHash = [];
|
||||||
let visitedArgsCount = 0;
|
let visitedArgsCount = 0;
|
||||||
for (let i = 0; i < tokens.length; i++) {
|
for (let i = 0; i < tokens.length; i++) {
|
||||||
@@ -2003,7 +2027,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* or dummy inputs, if necessary.
|
* or dummy inputs, if necessary.
|
||||||
* @returns The JSON definitions of field and inputs to add to the block.
|
* @returns The JSON definitions of field and inputs to add to the block.
|
||||||
*/
|
*/
|
||||||
private interpolateArguments_(
|
private interpolateArguments(
|
||||||
tokens: Array<string | number>,
|
tokens: Array<string | number>,
|
||||||
args: Array<AnyDuringMigration | string>,
|
args: Array<AnyDuringMigration | string>,
|
||||||
implicitAlign: string | undefined,
|
implicitAlign: string | undefined,
|
||||||
@@ -2026,7 +2050,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
} else {
|
} else {
|
||||||
// AnyDuringMigration because: Type '{ text: string; type: string; }
|
// AnyDuringMigration because: Type '{ text: string; type: string; }
|
||||||
// | null' is not assignable to type 'string | number'.
|
// | null' is not assignable to type 'string | number'.
|
||||||
element = this.stringToFieldJson_(element) as AnyDuringMigration;
|
element = this.stringToFieldJson(element) as AnyDuringMigration;
|
||||||
if (!element) {
|
if (!element) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2038,9 +2062,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
const length = elements.length;
|
const length = elements.length;
|
||||||
if (
|
if (
|
||||||
length &&
|
length &&
|
||||||
!this.isInputKeyword_(
|
!this.isInputKeyword((elements as AnyDuringMigration)[length - 1]['type'])
|
||||||
(elements as AnyDuringMigration)[length - 1]['type'],
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
const dummyInput = {'type': 'input_dummy'};
|
const dummyInput = {'type': 'input_dummy'};
|
||||||
if (implicitAlign) {
|
if (implicitAlign) {
|
||||||
@@ -2060,7 +2082,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @param element The element to try to turn into a field.
|
* @param element The element to try to turn into a field.
|
||||||
* @returns The field defined by the JSON, or null if one couldn't be created.
|
* @returns The field defined by the JSON, or null if one couldn't be created.
|
||||||
*/
|
*/
|
||||||
private fieldFromJson_(element: {
|
private fieldFromJson(element: {
|
||||||
alt?: string;
|
alt?: string;
|
||||||
type: string;
|
type: string;
|
||||||
text?: string;
|
text?: string;
|
||||||
@@ -2068,10 +2090,10 @@ export class Block implements IASTNodeLocation {
|
|||||||
const field = fieldRegistry.fromJson(element);
|
const field = fieldRegistry.fromJson(element);
|
||||||
if (!field && element['alt']) {
|
if (!field && element['alt']) {
|
||||||
if (typeof element['alt'] === 'string') {
|
if (typeof element['alt'] === 'string') {
|
||||||
const json = this.stringToFieldJson_(element['alt']);
|
const json = this.stringToFieldJson(element['alt']);
|
||||||
return json ? this.fieldFromJson_(json) : null;
|
return json ? this.fieldFromJson(json) : null;
|
||||||
}
|
}
|
||||||
return this.fieldFromJson_(element['alt']);
|
return this.fieldFromJson(element['alt']);
|
||||||
}
|
}
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
@@ -2086,7 +2108,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @returns The input that has been created, or null if one could not be
|
* @returns The input that has been created, or null if one could not be
|
||||||
* created for some reason (should never happen).
|
* created for some reason (should never happen).
|
||||||
*/
|
*/
|
||||||
private inputFromJson_(
|
private inputFromJson(
|
||||||
element: AnyDuringMigration,
|
element: AnyDuringMigration,
|
||||||
warningPrefix: string,
|
warningPrefix: string,
|
||||||
): Input | null {
|
): Input | null {
|
||||||
@@ -2144,7 +2166,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @returns True if the given string matches one of the input keywords, false
|
* @returns True if the given string matches one of the input keywords, false
|
||||||
* otherwise.
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
private isInputKeyword_(str: string): boolean {
|
private isInputKeyword(str: string): boolean {
|
||||||
return (
|
return (
|
||||||
str === 'input_value' ||
|
str === 'input_value' ||
|
||||||
str === 'input_statement' ||
|
str === 'input_statement' ||
|
||||||
@@ -2161,7 +2183,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @param str String to turn into the JSON definition of a label field.
|
* @param str String to turn into the JSON definition of a label field.
|
||||||
* @returns The JSON definition or null.
|
* @returns The JSON definition or null.
|
||||||
*/
|
*/
|
||||||
private stringToFieldJson_(str: string): {text: string; type: string} | null {
|
private stringToFieldJson(str: string): {text: string; type: string} | null {
|
||||||
str = str.trim();
|
str = str.trim();
|
||||||
if (str) {
|
if (str) {
|
||||||
return {
|
return {
|
||||||
@@ -2336,7 +2358,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
eventUtils.fire(
|
eventUtils.fire(
|
||||||
new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
|
new (eventUtils.get(EventType.BLOCK_CHANGE))(
|
||||||
this,
|
this,
|
||||||
'comment',
|
'comment',
|
||||||
null,
|
null,
|
||||||
@@ -2422,7 +2444,7 @@ export class Block implements IASTNodeLocation {
|
|||||||
* @returns Object with .x and .y properties.
|
* @returns Object with .x and .y properties.
|
||||||
*/
|
*/
|
||||||
getRelativeToSurfaceXY(): Coordinate {
|
getRelativeToSurfaceXY(): Coordinate {
|
||||||
return this.xy_;
|
return this.xy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2436,11 +2458,9 @@ export class Block implements IASTNodeLocation {
|
|||||||
if (this.parentBlock_) {
|
if (this.parentBlock_) {
|
||||||
throw Error('Block has parent');
|
throw Error('Block has parent');
|
||||||
}
|
}
|
||||||
const event = new (eventUtils.get(eventUtils.BLOCK_MOVE))(
|
const event = new (eventUtils.get(EventType.BLOCK_MOVE))(this) as BlockMove;
|
||||||
this,
|
if (reason) event.setReason(reason);
|
||||||
) as BlockMove;
|
this.xy.translate(dx, dy);
|
||||||
reason && event.setReason(reason);
|
|
||||||
this.xy_.translate(dx, dy);
|
|
||||||
event.recordNew();
|
event.recordNew();
|
||||||
eventUtils.fire(event);
|
eventUtils.fire(event);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ import './events/events_selected.js';
|
|||||||
|
|
||||||
import {Block} from './block.js';
|
import {Block} from './block.js';
|
||||||
import * as blockAnimations from './block_animations.js';
|
import * as blockAnimations from './block_animations.js';
|
||||||
|
import {IDeletable} from './blockly.js';
|
||||||
import * as browserEvents from './browser_events.js';
|
import * as browserEvents from './browser_events.js';
|
||||||
|
import {BlockCopyData, BlockPaster} from './clipboard/block_paster.js';
|
||||||
import * as common from './common.js';
|
import * as common from './common.js';
|
||||||
import {config} from './config.js';
|
import {config} from './config.js';
|
||||||
import type {Connection} from './connection.js';
|
import type {Connection} from './connection.js';
|
||||||
@@ -28,11 +30,15 @@ import {
|
|||||||
ContextMenuRegistry,
|
ContextMenuRegistry,
|
||||||
LegacyContextMenuOption,
|
LegacyContextMenuOption,
|
||||||
} from './contextmenu_registry.js';
|
} from './contextmenu_registry.js';
|
||||||
|
import {BlockDragStrategy} from './dragging/block_drag_strategy.js';
|
||||||
import type {BlockMove} from './events/events_block_move.js';
|
import type {BlockMove} from './events/events_block_move.js';
|
||||||
import * as deprecation from './utils/deprecation.js';
|
import {EventType} from './events/type.js';
|
||||||
import * as eventUtils from './events/utils.js';
|
import * as eventUtils from './events/utils.js';
|
||||||
import type {Field} from './field.js';
|
import type {Field} from './field.js';
|
||||||
import {FieldLabel} from './field_label.js';
|
import {FieldLabel} from './field_label.js';
|
||||||
|
import {IconType} from './icons/icon_types.js';
|
||||||
|
import {MutatorIcon} from './icons/mutator_icon.js';
|
||||||
|
import {WarningIcon} from './icons/warning_icon.js';
|
||||||
import type {Input} from './inputs/input.js';
|
import type {Input} from './inputs/input.js';
|
||||||
import type {IASTNodeLocationSvg} from './interfaces/i_ast_node_location_svg.js';
|
import type {IASTNodeLocationSvg} from './interfaces/i_ast_node_location_svg.js';
|
||||||
import type {IBoundedElement} from './interfaces/i_bounded_element.js';
|
import type {IBoundedElement} from './interfaces/i_bounded_element.js';
|
||||||
@@ -44,26 +50,21 @@ import {ASTNode} from './keyboard_nav/ast_node.js';
|
|||||||
import {TabNavigateCursor} from './keyboard_nav/tab_navigate_cursor.js';
|
import {TabNavigateCursor} from './keyboard_nav/tab_navigate_cursor.js';
|
||||||
import {MarkerManager} from './marker_manager.js';
|
import {MarkerManager} from './marker_manager.js';
|
||||||
import {Msg} from './msg.js';
|
import {Msg} from './msg.js';
|
||||||
import {MutatorIcon} from './icons/mutator_icon.js';
|
import * as renderManagement from './render_management.js';
|
||||||
import {RenderedConnection} from './rendered_connection.js';
|
import {RenderedConnection} from './rendered_connection.js';
|
||||||
import type {IPathObject} from './renderers/common/i_path_object.js';
|
import type {IPathObject} from './renderers/common/i_path_object.js';
|
||||||
import * as blocks from './serialization/blocks.js';
|
import * as blocks from './serialization/blocks.js';
|
||||||
import type {BlockStyle} from './theme.js';
|
import type {BlockStyle} from './theme.js';
|
||||||
import * as Tooltip from './tooltip.js';
|
import * as Tooltip from './tooltip.js';
|
||||||
import {Coordinate} from './utils/coordinate.js';
|
import {Coordinate} from './utils/coordinate.js';
|
||||||
|
import * as deprecation from './utils/deprecation.js';
|
||||||
import * as dom from './utils/dom.js';
|
import * as dom from './utils/dom.js';
|
||||||
import {Rect} from './utils/rect.js';
|
import {Rect} from './utils/rect.js';
|
||||||
import {Svg} from './utils/svg.js';
|
import {Svg} from './utils/svg.js';
|
||||||
import * as svgMath from './utils/svg_math.js';
|
import * as svgMath from './utils/svg_math.js';
|
||||||
import {WarningIcon} from './icons/warning_icon.js';
|
import {FlyoutItemInfo} from './utils/toolbox.js';
|
||||||
import type {Workspace} from './workspace.js';
|
import type {Workspace} from './workspace.js';
|
||||||
import type {WorkspaceSvg} from './workspace_svg.js';
|
import type {WorkspaceSvg} from './workspace_svg.js';
|
||||||
import * as renderManagement from './render_management.js';
|
|
||||||
import {IconType} from './icons/icon_types.js';
|
|
||||||
import {BlockCopyData, BlockPaster} from './clipboard/block_paster.js';
|
|
||||||
import {BlockDragStrategy} from './dragging/block_drag_strategy.js';
|
|
||||||
import {IDeletable} from './blockly.js';
|
|
||||||
import {FlyoutItemInfo} from './utils/toolbox.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for a block's SVG representation.
|
* Class for a block's SVG representation.
|
||||||
@@ -92,7 +93,25 @@ export class BlockSvg
|
|||||||
static readonly COLLAPSED_WARNING_ID = 'TEMP_COLLAPSED_WARNING_';
|
static readonly COLLAPSED_WARNING_ID = 'TEMP_COLLAPSED_WARNING_';
|
||||||
override decompose?: (p1: Workspace) => BlockSvg;
|
override decompose?: (p1: Workspace) => BlockSvg;
|
||||||
// override compose?: ((p1: BlockSvg) => void)|null;
|
// override compose?: ((p1: BlockSvg) => void)|null;
|
||||||
saveConnections?: (p1: BlockSvg) => void;
|
|
||||||
|
/**
|
||||||
|
* An optional method which saves a record of blocks connected to
|
||||||
|
* this block so they can be later restored after this block is
|
||||||
|
* recoomposed (reconfigured). Typically records the connected
|
||||||
|
* blocks on properties on blocks in the mutator flyout, so that
|
||||||
|
* rearranging those component blocks will automatically rearrange
|
||||||
|
* the corresponding connected blocks on this block after this block
|
||||||
|
* is recomposed.
|
||||||
|
*
|
||||||
|
* To keep the saved connection information up-to-date, MutatorIcon
|
||||||
|
* arranges for an event listener to call this method any time the
|
||||||
|
* mutator flyout is open and a change occurs on this block's
|
||||||
|
* workspace.
|
||||||
|
*
|
||||||
|
* @param rootBlock The root block in the mutator flyout.
|
||||||
|
*/
|
||||||
|
saveConnections?: (rootBlock: BlockSvg) => void;
|
||||||
|
|
||||||
customContextMenu?: (
|
customContextMenu?: (
|
||||||
p1: Array<ContextMenuOption | LegacyContextMenuOption>,
|
p1: Array<ContextMenuOption | LegacyContextMenuOption>,
|
||||||
) => void;
|
) => void;
|
||||||
@@ -126,7 +145,7 @@ export class BlockSvg
|
|||||||
/** Block's mutator icon (if any). */
|
/** Block's mutator icon (if any). */
|
||||||
mutator: MutatorIcon | null = null;
|
mutator: MutatorIcon | null = null;
|
||||||
|
|
||||||
private svgGroup_: SVGGElement;
|
private svgGroup: SVGGElement;
|
||||||
style: BlockStyle;
|
style: BlockStyle;
|
||||||
/** @internal */
|
/** @internal */
|
||||||
pathObject: IPathObject;
|
pathObject: IPathObject;
|
||||||
@@ -136,15 +155,6 @@ export class BlockSvg
|
|||||||
|
|
||||||
private visuallyDisabled = false;
|
private visuallyDisabled = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Is this block currently rendering? Used to stop recursive render calls
|
|
||||||
* from actually triggering a re-render.
|
|
||||||
*/
|
|
||||||
private renderIsInProgress_ = false;
|
|
||||||
|
|
||||||
/** Whether mousedown events have been bound yet. */
|
|
||||||
private eventsInit_ = false;
|
|
||||||
|
|
||||||
override workspace: WorkspaceSvg;
|
override workspace: WorkspaceSvg;
|
||||||
// TODO(b/109816955): remove '!', see go/strict-prop-init-fix.
|
// TODO(b/109816955): remove '!', see go/strict-prop-init-fix.
|
||||||
override outputConnection!: RenderedConnection;
|
override outputConnection!: RenderedConnection;
|
||||||
@@ -182,10 +192,10 @@ export class BlockSvg
|
|||||||
throw TypeError('Cannot create a rendered block in a headless workspace');
|
throw TypeError('Cannot create a rendered block in a headless workspace');
|
||||||
}
|
}
|
||||||
this.workspace = workspace;
|
this.workspace = workspace;
|
||||||
this.svgGroup_ = dom.createSvgElement(Svg.G, {});
|
this.svgGroup = dom.createSvgElement(Svg.G, {});
|
||||||
|
|
||||||
if (prototypeName) {
|
if (prototypeName) {
|
||||||
dom.addClass(this.svgGroup_, prototypeName);
|
dom.addClass(this.svgGroup, prototypeName);
|
||||||
}
|
}
|
||||||
/** A block style object. */
|
/** A block style object. */
|
||||||
this.style = workspace.getRenderer().getConstants().getBlockStyle(null);
|
this.style = workspace.getRenderer().getConstants().getBlockStyle(null);
|
||||||
@@ -193,14 +203,14 @@ export class BlockSvg
|
|||||||
/** The renderer's path object. */
|
/** The renderer's path object. */
|
||||||
this.pathObject = workspace
|
this.pathObject = workspace
|
||||||
.getRenderer()
|
.getRenderer()
|
||||||
.makePathObject(this.svgGroup_, this.style);
|
.makePathObject(this.svgGroup, this.style);
|
||||||
|
|
||||||
const svgPath = this.pathObject.svgPath;
|
const svgPath = this.pathObject.svgPath;
|
||||||
(svgPath as any).tooltip = this;
|
(svgPath as any).tooltip = this;
|
||||||
Tooltip.bindMouseEvents(svgPath);
|
Tooltip.bindMouseEvents(svgPath);
|
||||||
|
|
||||||
// Expose this block's ID on its top-level SVG group.
|
// Expose this block's ID on its top-level SVG group.
|
||||||
this.svgGroup_.setAttribute('data-id', this.id);
|
this.svgGroup.setAttribute('data-id', this.id);
|
||||||
|
|
||||||
this.doInit_();
|
this.doInit_();
|
||||||
}
|
}
|
||||||
@@ -222,12 +232,7 @@ export class BlockSvg
|
|||||||
this.pathObject.updateMovable(this.isMovable() || this.isInFlyout);
|
this.pathObject.updateMovable(this.isMovable() || this.isInFlyout);
|
||||||
const svg = this.getSvgRoot();
|
const svg = this.getSvgRoot();
|
||||||
if (!this.workspace.options.readOnly && svg) {
|
if (!this.workspace.options.readOnly && svg) {
|
||||||
browserEvents.conditionalBind(
|
browserEvents.conditionalBind(svg, 'pointerdown', this, this.onMouseDown);
|
||||||
svg,
|
|
||||||
'pointerdown',
|
|
||||||
this,
|
|
||||||
this.onMouseDown_,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!svg.parentNode) {
|
if (!svg.parentNode) {
|
||||||
@@ -263,7 +268,7 @@ export class BlockSvg
|
|||||||
this.addSelect();
|
this.addSelect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Unselects this block. Unhighlights the blockv visually. */
|
/** Unselects this block. Unhighlights the block visually. */
|
||||||
unselect() {
|
unselect() {
|
||||||
if (this.isShadow()) {
|
if (this.isShadow()) {
|
||||||
this.getParent()?.unselect();
|
this.getParent()?.unselect();
|
||||||
@@ -362,8 +367,8 @@ export class BlockSvg
|
|||||||
const eventsEnabled = eventUtils.isEnabled();
|
const eventsEnabled = eventUtils.isEnabled();
|
||||||
let event: BlockMove | null = null;
|
let event: BlockMove | null = null;
|
||||||
if (eventsEnabled) {
|
if (eventsEnabled) {
|
||||||
event = new (eventUtils.get(eventUtils.BLOCK_MOVE)!)(this) as BlockMove;
|
event = new (eventUtils.get(EventType.BLOCK_MOVE)!)(this) as BlockMove;
|
||||||
reason && event.setReason(reason);
|
if (reason) event.setReason(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
const delta = new Coordinate(dx, dy);
|
const delta = new Coordinate(dx, dy);
|
||||||
@@ -502,14 +507,14 @@ export class BlockSvg
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
super.setCollapsed(collapsed);
|
super.setCollapsed(collapsed);
|
||||||
this.updateCollapsed_();
|
this.updateCollapsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes sure that when the block is collapsed, it is rendered correctly
|
* Makes sure that when the block is collapsed, it is rendered correctly
|
||||||
* for that state.
|
* for that state.
|
||||||
*/
|
*/
|
||||||
private updateCollapsed_() {
|
private updateCollapsed() {
|
||||||
const collapsed = this.isCollapsed();
|
const collapsed = this.isCollapsed();
|
||||||
const collapsedInputName = constants.COLLAPSED_INPUT_NAME;
|
const collapsedInputName = constants.COLLAPSED_INPUT_NAME;
|
||||||
const collapsedFieldName = constants.COLLAPSED_FIELD_NAME;
|
const collapsedFieldName = constants.COLLAPSED_FIELD_NAME;
|
||||||
@@ -527,11 +532,11 @@ export class BlockSvg
|
|||||||
if (!collapsed) {
|
if (!collapsed) {
|
||||||
this.updateDisabled();
|
this.updateDisabled();
|
||||||
this.removeInput(collapsedInputName);
|
this.removeInput(collapsedInputName);
|
||||||
dom.removeClass(this.svgGroup_, 'blocklyCollapsed');
|
dom.removeClass(this.svgGroup, 'blocklyCollapsed');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dom.addClass(this.svgGroup_, 'blocklyCollapsed');
|
dom.addClass(this.svgGroup, 'blocklyCollapsed');
|
||||||
|
|
||||||
const text = this.toString(internalConstants.COLLAPSE_CHARS);
|
const text = this.toString(internalConstants.COLLAPSE_CHARS);
|
||||||
const field = this.getField(collapsedFieldName);
|
const field = this.getField(collapsedFieldName);
|
||||||
@@ -579,7 +584,7 @@ export class BlockSvg
|
|||||||
*
|
*
|
||||||
* @param e Pointer down event.
|
* @param e Pointer down event.
|
||||||
*/
|
*/
|
||||||
private onMouseDown_(e: PointerEvent) {
|
private onMouseDown(e: PointerEvent) {
|
||||||
const gesture = this.workspace.getGesture(e);
|
const gesture = this.workspace.getGesture(e);
|
||||||
if (gesture) {
|
if (gesture) {
|
||||||
gesture.handleBlockStart(e, this);
|
gesture.handleBlockStart(e, this);
|
||||||
@@ -683,7 +688,7 @@ export class BlockSvg
|
|||||||
* @param className
|
* @param className
|
||||||
*/
|
*/
|
||||||
addClass(className: string) {
|
addClass(className: string) {
|
||||||
dom.addClass(this.svgGroup_, className);
|
dom.addClass(this.svgGroup, className);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -692,7 +697,7 @@ export class BlockSvg
|
|||||||
* @param className
|
* @param className
|
||||||
*/
|
*/
|
||||||
removeClass(className: string) {
|
removeClass(className: string) {
|
||||||
dom.removeClass(this.svgGroup_, className);
|
dom.removeClass(this.svgGroup, className);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -737,9 +742,9 @@ export class BlockSvg
|
|||||||
super.setEditable(editable);
|
super.setEditable(editable);
|
||||||
|
|
||||||
if (editable) {
|
if (editable) {
|
||||||
dom.removeClass(this.svgGroup_, 'blocklyNotEditable');
|
dom.removeClass(this.svgGroup, 'blocklyNotEditable');
|
||||||
} else {
|
} else {
|
||||||
dom.addClass(this.svgGroup_, 'blocklyNotEditable');
|
dom.addClass(this.svgGroup, 'blocklyNotEditable');
|
||||||
}
|
}
|
||||||
|
|
||||||
const icons = this.getIcons();
|
const icons = this.getIcons();
|
||||||
@@ -787,7 +792,7 @@ export class BlockSvg
|
|||||||
* @returns The root SVG node (probably a group).
|
* @returns The root SVG node (probably a group).
|
||||||
*/
|
*/
|
||||||
getSvgRoot(): SVGGElement {
|
getSvgRoot(): SVGGElement {
|
||||||
return this.svgGroup_;
|
return this.svgGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -809,8 +814,27 @@ export class BlockSvg
|
|||||||
blockAnimations.disposeUiEffect(this);
|
blockAnimations.disposeUiEffect(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Selecting a shadow block highlights an ancestor block, but that highlight
|
||||||
|
// should be removed if the shadow block will be deleted. So, before
|
||||||
|
// deleting blocks and severing the connections between them, check whether
|
||||||
|
// doing so would delete a selected block and make sure that any associated
|
||||||
|
// parent is updated.
|
||||||
|
const selection = common.getSelected();
|
||||||
|
if (selection instanceof Block) {
|
||||||
|
let selectionAncestor: Block | null = selection;
|
||||||
|
while (selectionAncestor !== null) {
|
||||||
|
if (selectionAncestor === this) {
|
||||||
|
// The block to be deleted contains the selected block, so remove any
|
||||||
|
// selection highlight associated with the selected block before
|
||||||
|
// deleting them.
|
||||||
|
selection.unselect();
|
||||||
|
}
|
||||||
|
selectionAncestor = selectionAncestor.getParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
super.dispose(!!healStack);
|
super.dispose(!!healStack);
|
||||||
dom.removeNode(this.svgGroup_);
|
dom.removeNode(this.svgGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1090,9 +1114,9 @@ export class BlockSvg
|
|||||||
super.setDeletable(deletable);
|
super.setDeletable(deletable);
|
||||||
|
|
||||||
if (deletable) {
|
if (deletable) {
|
||||||
dom.removeClass(this.svgGroup_, 'blocklyNotDeletable');
|
dom.removeClass(this.svgGroup, 'blocklyNotDeletable');
|
||||||
} else {
|
} else {
|
||||||
dom.addClass(this.svgGroup_, 'blocklyNotDeletable');
|
dom.addClass(this.svgGroup, 'blocklyNotDeletable');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1180,7 +1204,7 @@ export class BlockSvg
|
|||||||
.getBlockStyle(blockStyleName);
|
.getBlockStyle(blockStyleName);
|
||||||
|
|
||||||
if (this.styleName_) {
|
if (this.styleName_) {
|
||||||
dom.removeClass(this.svgGroup_, this.styleName_);
|
dom.removeClass(this.svgGroup, this.styleName_);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blockStyle) {
|
if (blockStyle) {
|
||||||
@@ -1192,7 +1216,7 @@ export class BlockSvg
|
|||||||
|
|
||||||
this.applyColour();
|
this.applyColour();
|
||||||
|
|
||||||
dom.addClass(this.svgGroup_, blockStyleName);
|
dom.addClass(this.svgGroup, blockStyleName);
|
||||||
this.styleName_ = blockStyleName;
|
this.styleName_ = blockStyleName;
|
||||||
} else {
|
} else {
|
||||||
throw Error('Invalid style name: ' + blockStyleName);
|
throw Error('Invalid style name: ' + blockStyleName);
|
||||||
@@ -1204,10 +1228,11 @@ export class BlockSvg
|
|||||||
* <g> tags do not respect z-index so SVG renders them in the
|
* <g> tags do not respect z-index so SVG renders them in the
|
||||||
* order that they are in the DOM. By placing this block first within the
|
* order that they are in the DOM. By placing this block first within the
|
||||||
* block group's <g>, it will render on top of any other blocks.
|
* block group's <g>, it will render on top of any other blocks.
|
||||||
|
* Use sparingly, this method is expensive because it reorders the DOM
|
||||||
|
* nodes.
|
||||||
*
|
*
|
||||||
* @param blockOnly: True to only move this block to the front without
|
* @param blockOnly True to only move this block to the front without
|
||||||
* adjusting its parents.
|
* adjusting its parents.
|
||||||
* @internal
|
|
||||||
*/
|
*/
|
||||||
bringToFront(blockOnly = false) {
|
bringToFront(blockOnly = false) {
|
||||||
/* eslint-disable-next-line @typescript-eslint/no-this-alias */
|
/* eslint-disable-next-line @typescript-eslint/no-this-alias */
|
||||||
@@ -1484,9 +1509,9 @@ export class BlockSvg
|
|||||||
if (conn.isConnected() && neighbour.isConnected()) continue;
|
if (conn.isConnected() && neighbour.isConnected()) continue;
|
||||||
|
|
||||||
if (conn.isSuperior()) {
|
if (conn.isSuperior()) {
|
||||||
neighbour.bumpAwayFrom(conn);
|
neighbour.bumpAwayFrom(conn, /* initiatedByThis = */ false);
|
||||||
} else {
|
} else {
|
||||||
conn.bumpAwayFrom(neighbour);
|
conn.bumpAwayFrom(neighbour, /* initiatedByThis = */ true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1577,7 +1602,7 @@ export class BlockSvg
|
|||||||
dom.startTextWidthCache();
|
dom.startTextWidthCache();
|
||||||
|
|
||||||
if (this.isCollapsed()) {
|
if (this.isCollapsed()) {
|
||||||
this.updateCollapsed_();
|
this.updateCollapsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.isEnabled()) {
|
if (!this.isEnabled()) {
|
||||||
|
|||||||
373
core/blockly.ts
373
core/blockly.ts
@@ -17,13 +17,17 @@ import './events/events_var_create.js';
|
|||||||
|
|
||||||
import {Block} from './block.js';
|
import {Block} from './block.js';
|
||||||
import * as blockAnimations from './block_animations.js';
|
import * as blockAnimations from './block_animations.js';
|
||||||
|
import {BlockFlyoutInflater} from './block_flyout_inflater.js';
|
||||||
import {BlockSvg} from './block_svg.js';
|
import {BlockSvg} from './block_svg.js';
|
||||||
import {BlocklyOptions} from './blockly_options.js';
|
import {BlocklyOptions} from './blockly_options.js';
|
||||||
import {Blocks} from './blocks.js';
|
import {Blocks} from './blocks.js';
|
||||||
import * as browserEvents from './browser_events.js';
|
import * as browserEvents from './browser_events.js';
|
||||||
import * as bubbles from './bubbles.js';
|
import * as bubbles from './bubbles.js';
|
||||||
|
import {MiniWorkspaceBubble} from './bubbles/mini_workspace_bubble.js';
|
||||||
import * as bumpObjects from './bump_objects.js';
|
import * as bumpObjects from './bump_objects.js';
|
||||||
|
import {ButtonFlyoutInflater} from './button_flyout_inflater.js';
|
||||||
import * as clipboard from './clipboard.js';
|
import * as clipboard from './clipboard.js';
|
||||||
|
import * as comments from './comments.js';
|
||||||
import * as common from './common.js';
|
import * as common from './common.js';
|
||||||
import {ComponentManager} from './component_manager.js';
|
import {ComponentManager} from './component_manager.js';
|
||||||
import {config} from './config.js';
|
import {config} from './config.js';
|
||||||
@@ -31,15 +35,15 @@ import {Connection} from './connection.js';
|
|||||||
import {ConnectionChecker} from './connection_checker.js';
|
import {ConnectionChecker} from './connection_checker.js';
|
||||||
import {ConnectionDB} from './connection_db.js';
|
import {ConnectionDB} from './connection_db.js';
|
||||||
import {ConnectionType} from './connection_type.js';
|
import {ConnectionType} from './connection_type.js';
|
||||||
|
import * as constants from './constants.js';
|
||||||
import * as ContextMenu from './contextmenu.js';
|
import * as ContextMenu from './contextmenu.js';
|
||||||
import * as ContextMenuItems from './contextmenu_items.js';
|
import * as ContextMenuItems from './contextmenu_items.js';
|
||||||
import {ContextMenuRegistry} from './contextmenu_registry.js';
|
import {ContextMenuRegistry} from './contextmenu_registry.js';
|
||||||
import * as comments from './comments.js';
|
|
||||||
import * as Css from './css.js';
|
import * as Css from './css.js';
|
||||||
import {DeleteArea} from './delete_area.js';
|
import {DeleteArea} from './delete_area.js';
|
||||||
import * as dialog from './dialog.js';
|
import * as dialog from './dialog.js';
|
||||||
import * as dragging from './dragging.js';
|
|
||||||
import {DragTarget} from './drag_target.js';
|
import {DragTarget} from './drag_target.js';
|
||||||
|
import * as dragging from './dragging.js';
|
||||||
import * as dropDownDiv from './dropdowndiv.js';
|
import * as dropDownDiv from './dropdowndiv.js';
|
||||||
import * as Events from './events/events.js';
|
import * as Events from './events/events.js';
|
||||||
import * as Extensions from './extensions.js';
|
import * as Extensions from './extensions.js';
|
||||||
@@ -97,22 +101,21 @@ import {
|
|||||||
} from './field_variable.js';
|
} from './field_variable.js';
|
||||||
import {Flyout, FlyoutItem} from './flyout_base.js';
|
import {Flyout, FlyoutItem} from './flyout_base.js';
|
||||||
import {FlyoutButton} from './flyout_button.js';
|
import {FlyoutButton} from './flyout_button.js';
|
||||||
import {FlyoutSeparator} from './flyout_separator.js';
|
|
||||||
import {IFlyoutInflater} from './interfaces/i_flyout_inflater.js';
|
|
||||||
import {BlockFlyoutInflater} from './block_flyout_inflater.js';
|
|
||||||
import {ButtonFlyoutInflater} from './button_flyout_inflater.js';
|
|
||||||
import {LabelFlyoutInflater} from './label_flyout_inflater.js';
|
|
||||||
import {SeparatorFlyoutInflater} from './separator_flyout_inflater.js';
|
|
||||||
import {HorizontalFlyout} from './flyout_horizontal.js';
|
import {HorizontalFlyout} from './flyout_horizontal.js';
|
||||||
import {FlyoutMetricsManager} from './flyout_metrics_manager.js';
|
import {FlyoutMetricsManager} from './flyout_metrics_manager.js';
|
||||||
|
import {FlyoutSeparator} from './flyout_separator.js';
|
||||||
import {VerticalFlyout} from './flyout_vertical.js';
|
import {VerticalFlyout} from './flyout_vertical.js';
|
||||||
import {CodeGenerator} from './generator.js';
|
import {CodeGenerator} from './generator.js';
|
||||||
import {Gesture} from './gesture.js';
|
import {Gesture} from './gesture.js';
|
||||||
import {Grid} from './grid.js';
|
import {Grid} from './grid.js';
|
||||||
import * as icons from './icons.js';
|
import * as icons from './icons.js';
|
||||||
import {inject} from './inject.js';
|
import {inject} from './inject.js';
|
||||||
import {Input} from './inputs/input.js';
|
|
||||||
import * as inputs from './inputs.js';
|
import * as inputs from './inputs.js';
|
||||||
|
import {IFlyoutInflater} from './interfaces/i_flyout_inflater.js';
|
||||||
|
import {LabelFlyoutInflater} from './label_flyout_inflater.js';
|
||||||
|
import {SeparatorFlyoutInflater} from './separator_flyout_inflater.js';
|
||||||
|
|
||||||
|
import {Input} from './inputs/input.js';
|
||||||
import {InsertionMarkerPreviewer} from './insertion_marker_previewer.js';
|
import {InsertionMarkerPreviewer} from './insertion_marker_previewer.js';
|
||||||
import {IASTNodeLocation} from './interfaces/i_ast_node_location.js';
|
import {IASTNodeLocation} from './interfaces/i_ast_node_location.js';
|
||||||
import {IASTNodeLocationSvg} from './interfaces/i_ast_node_location_svg.js';
|
import {IASTNodeLocationSvg} from './interfaces/i_ast_node_location_svg.js';
|
||||||
@@ -125,16 +128,16 @@ import {IComponent} from './interfaces/i_component.js';
|
|||||||
import {IConnectionChecker} from './interfaces/i_connection_checker.js';
|
import {IConnectionChecker} from './interfaces/i_connection_checker.js';
|
||||||
import {IConnectionPreviewer} from './interfaces/i_connection_previewer.js';
|
import {IConnectionPreviewer} from './interfaces/i_connection_previewer.js';
|
||||||
import {IContextMenu} from './interfaces/i_contextmenu.js';
|
import {IContextMenu} from './interfaces/i_contextmenu.js';
|
||||||
import {ICopyable, isCopyable, ICopyData} from './interfaces/i_copyable.js';
|
import {ICopyData, ICopyable, isCopyable} from './interfaces/i_copyable.js';
|
||||||
import {IDeletable, isDeletable} from './interfaces/i_deletable.js';
|
import {IDeletable, isDeletable} from './interfaces/i_deletable.js';
|
||||||
import {IDeleteArea} from './interfaces/i_delete_area.js';
|
import {IDeleteArea} from './interfaces/i_delete_area.js';
|
||||||
import {IDragTarget} from './interfaces/i_drag_target.js';
|
import {IDragTarget} from './interfaces/i_drag_target.js';
|
||||||
import {IDragger} from './interfaces/i_dragger.js';
|
|
||||||
import {
|
import {
|
||||||
|
IDragStrategy,
|
||||||
IDraggable,
|
IDraggable,
|
||||||
isDraggable,
|
isDraggable,
|
||||||
IDragStrategy,
|
|
||||||
} from './interfaces/i_draggable.js';
|
} from './interfaces/i_draggable.js';
|
||||||
|
import {IDragger} from './interfaces/i_dragger.js';
|
||||||
import {IFlyout} from './interfaces/i_flyout.js';
|
import {IFlyout} from './interfaces/i_flyout.js';
|
||||||
import {IHasBubble, hasBubble} from './interfaces/i_has_bubble.js';
|
import {IHasBubble, hasBubble} from './interfaces/i_has_bubble.js';
|
||||||
import {IIcon, isIcon} from './interfaces/i_icon.js';
|
import {IIcon, isIcon} from './interfaces/i_icon.js';
|
||||||
@@ -155,35 +158,33 @@ import {ISerializable, isSerializable} from './interfaces/i_serializable.js';
|
|||||||
import {IStyleable} from './interfaces/i_styleable.js';
|
import {IStyleable} from './interfaces/i_styleable.js';
|
||||||
import {IToolbox} from './interfaces/i_toolbox.js';
|
import {IToolbox} from './interfaces/i_toolbox.js';
|
||||||
import {IToolboxItem} from './interfaces/i_toolbox_item.js';
|
import {IToolboxItem} from './interfaces/i_toolbox_item.js';
|
||||||
import {IVariableMap} from './interfaces/i_variable_map.js';
|
|
||||||
import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js';
|
|
||||||
import {
|
import {
|
||||||
IVariableBackedParameterModel,
|
IVariableBackedParameterModel,
|
||||||
isVariableBackedParameterModel,
|
isVariableBackedParameterModel,
|
||||||
} from './interfaces/i_variable_backed_parameter_model.js';
|
} from './interfaces/i_variable_backed_parameter_model.js';
|
||||||
|
import {IVariableMap} from './interfaces/i_variable_map.js';
|
||||||
|
import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js';
|
||||||
import * as internalConstants from './internal_constants.js';
|
import * as internalConstants from './internal_constants.js';
|
||||||
import {ASTNode} from './keyboard_nav/ast_node.js';
|
import {ASTNode} from './keyboard_nav/ast_node.js';
|
||||||
import {BasicCursor} from './keyboard_nav/basic_cursor.js';
|
import {BasicCursor} from './keyboard_nav/basic_cursor.js';
|
||||||
import {Cursor} from './keyboard_nav/cursor.js';
|
import {Cursor} from './keyboard_nav/cursor.js';
|
||||||
import {Marker} from './keyboard_nav/marker.js';
|
import {Marker} from './keyboard_nav/marker.js';
|
||||||
import {TabNavigateCursor} from './keyboard_nav/tab_navigate_cursor.js';
|
import {TabNavigateCursor} from './keyboard_nav/tab_navigate_cursor.js';
|
||||||
import {MarkerManager} from './marker_manager.js';
|
|
||||||
import type {LayerManager} from './layer_manager.js';
|
import type {LayerManager} from './layer_manager.js';
|
||||||
import * as layers from './layers.js';
|
import * as layers from './layers.js';
|
||||||
|
import {MarkerManager} from './marker_manager.js';
|
||||||
import {Menu} from './menu.js';
|
import {Menu} from './menu.js';
|
||||||
import {MenuItem} from './menuitem.js';
|
import {MenuItem} from './menuitem.js';
|
||||||
import {MetricsManager} from './metrics_manager.js';
|
import {MetricsManager} from './metrics_manager.js';
|
||||||
import {Msg, setLocale} from './msg.js';
|
import {Msg, setLocale} from './msg.js';
|
||||||
import {MiniWorkspaceBubble} from './bubbles/mini_workspace_bubble.js';
|
|
||||||
import {Names} from './names.js';
|
import {Names} from './names.js';
|
||||||
import {Options} from './options.js';
|
import {Options} from './options.js';
|
||||||
import * as uiPosition from './positionable_helpers.js';
|
import * as uiPosition from './positionable_helpers.js';
|
||||||
import * as Procedures from './procedures.js';
|
import * as Procedures from './procedures.js';
|
||||||
import * as registry from './registry.js';
|
import * as registry from './registry.js';
|
||||||
import {RenderedConnection} from './rendered_connection.js';
|
|
||||||
import * as renderManagement from './render_management.js';
|
import * as renderManagement from './render_management.js';
|
||||||
|
import {RenderedConnection} from './rendered_connection.js';
|
||||||
import * as blockRendering from './renderers/common/block_rendering.js';
|
import * as blockRendering from './renderers/common/block_rendering.js';
|
||||||
import * as constants from './constants.js';
|
|
||||||
import * as geras from './renderers/geras/geras.js';
|
import * as geras from './renderers/geras/geras.js';
|
||||||
import * as thrasos from './renderers/thrasos/thrasos.js';
|
import * as thrasos from './renderers/thrasos/thrasos.js';
|
||||||
import * as zelos from './renderers/zelos/zelos.js';
|
import * as zelos from './renderers/zelos/zelos.js';
|
||||||
@@ -426,181 +427,205 @@ Names.prototype.populateProcedures = function (
|
|||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
// Re-export submodules that no longer declareLegacyNamespace.
|
// Re-export submodules that no longer declareLegacyNamespace.
|
||||||
export {browserEvents};
|
|
||||||
export {ContextMenu};
|
|
||||||
export {ContextMenuItems};
|
|
||||||
export {Css};
|
|
||||||
export {Events};
|
|
||||||
export {Extensions};
|
|
||||||
export {Procedures};
|
|
||||||
export {Procedures as procedures};
|
|
||||||
export {ShortcutItems};
|
|
||||||
export {Themes};
|
|
||||||
export {Tooltip};
|
|
||||||
export {Touch};
|
|
||||||
export {Variables};
|
|
||||||
export {VariablesDynamic};
|
|
||||||
export {WidgetDiv};
|
|
||||||
export {Xml};
|
|
||||||
export {blockAnimations};
|
|
||||||
export {blockRendering};
|
|
||||||
export {bumpObjects};
|
|
||||||
export {clipboard};
|
|
||||||
export {common};
|
|
||||||
export {constants};
|
|
||||||
export {dialog};
|
|
||||||
export {fieldRegistry};
|
|
||||||
export {geras};
|
|
||||||
export {registry};
|
|
||||||
export {thrasos};
|
|
||||||
export {uiPosition};
|
|
||||||
export {utils};
|
|
||||||
export {zelos};
|
|
||||||
export {ASTNode};
|
|
||||||
export {BasicCursor};
|
|
||||||
export {Block};
|
|
||||||
export {BlocklyOptions};
|
|
||||||
export {BlockSvg};
|
|
||||||
export {Blocks};
|
|
||||||
export {bubbles};
|
|
||||||
export {CollapsibleToolboxCategory};
|
|
||||||
export {ComponentManager};
|
|
||||||
export {Connection};
|
|
||||||
export {ConnectionType};
|
|
||||||
export {ConnectionChecker};
|
|
||||||
export {ConnectionDB};
|
|
||||||
export {ContextMenuRegistry};
|
|
||||||
export {comments};
|
|
||||||
export {Cursor};
|
|
||||||
export {DeleteArea};
|
|
||||||
export {dragging};
|
|
||||||
export {DragTarget};
|
|
||||||
export const DropDownDiv = dropDownDiv;
|
|
||||||
export {Field, FieldConfig, FieldValidator, UnattachedFieldError};
|
|
||||||
export {
|
export {
|
||||||
|
ASTNode,
|
||||||
|
BasicCursor,
|
||||||
|
Block,
|
||||||
|
BlockSvg,
|
||||||
|
BlocklyOptions,
|
||||||
|
Blocks,
|
||||||
|
CollapsibleToolboxCategory,
|
||||||
|
ComponentManager,
|
||||||
|
Connection,
|
||||||
|
ConnectionChecker,
|
||||||
|
ConnectionDB,
|
||||||
|
ConnectionType,
|
||||||
|
ContextMenu,
|
||||||
|
ContextMenuItems,
|
||||||
|
ContextMenuRegistry,
|
||||||
|
Css,
|
||||||
|
Cursor,
|
||||||
|
DeleteArea,
|
||||||
|
DragTarget,
|
||||||
|
Events,
|
||||||
|
Extensions,
|
||||||
|
Procedures,
|
||||||
|
ShortcutItems,
|
||||||
|
Themes,
|
||||||
|
Tooltip,
|
||||||
|
Touch,
|
||||||
|
Variables,
|
||||||
|
VariablesDynamic,
|
||||||
|
WidgetDiv,
|
||||||
|
Xml,
|
||||||
|
blockAnimations,
|
||||||
|
blockRendering,
|
||||||
|
browserEvents,
|
||||||
|
bubbles,
|
||||||
|
bumpObjects,
|
||||||
|
clipboard,
|
||||||
|
comments,
|
||||||
|
common,
|
||||||
|
constants,
|
||||||
|
dialog,
|
||||||
|
dragging,
|
||||||
|
fieldRegistry,
|
||||||
|
geras,
|
||||||
|
Procedures as procedures,
|
||||||
|
registry,
|
||||||
|
thrasos,
|
||||||
|
uiPosition,
|
||||||
|
utils,
|
||||||
|
zelos,
|
||||||
|
};
|
||||||
|
export const DropDownDiv = dropDownDiv;
|
||||||
|
export {
|
||||||
|
BlockFlyoutInflater,
|
||||||
|
ButtonFlyoutInflater,
|
||||||
|
CodeGenerator,
|
||||||
|
CodeGenerator,
|
||||||
|
Field,
|
||||||
FieldCheckbox,
|
FieldCheckbox,
|
||||||
FieldCheckboxConfig,
|
FieldCheckboxConfig,
|
||||||
FieldCheckboxFromJsonConfig,
|
FieldCheckboxFromJsonConfig,
|
||||||
FieldCheckboxValidator,
|
FieldCheckboxValidator,
|
||||||
};
|
FieldConfig,
|
||||||
export {
|
|
||||||
FieldDropdown,
|
FieldDropdown,
|
||||||
FieldDropdownConfig,
|
FieldDropdownConfig,
|
||||||
FieldDropdownFromJsonConfig,
|
FieldDropdownFromJsonConfig,
|
||||||
FieldDropdownValidator,
|
FieldDropdownValidator,
|
||||||
ImageProperties,
|
FieldImage,
|
||||||
MenuGenerator,
|
FieldImage,
|
||||||
MenuGeneratorFunction,
|
FieldImageConfig,
|
||||||
MenuOption,
|
FieldImageConfig,
|
||||||
};
|
FieldImageFromJsonConfig,
|
||||||
export {FieldImage, FieldImageConfig, FieldImageFromJsonConfig};
|
FieldImageFromJsonConfig,
|
||||||
export {FieldLabel, FieldLabelConfig, FieldLabelFromJsonConfig};
|
FieldLabel,
|
||||||
export {FieldLabelSerializable};
|
FieldLabel,
|
||||||
export {
|
FieldLabelConfig,
|
||||||
|
FieldLabelConfig,
|
||||||
|
FieldLabelFromJsonConfig,
|
||||||
|
FieldLabelFromJsonConfig,
|
||||||
|
FieldLabelSerializable,
|
||||||
|
FieldLabelSerializable,
|
||||||
FieldNumber,
|
FieldNumber,
|
||||||
FieldNumberConfig,
|
FieldNumberConfig,
|
||||||
FieldNumberFromJsonConfig,
|
FieldNumberFromJsonConfig,
|
||||||
FieldNumberValidator,
|
FieldNumberValidator,
|
||||||
};
|
|
||||||
export {
|
|
||||||
FieldTextInput,
|
FieldTextInput,
|
||||||
FieldTextInputConfig,
|
FieldTextInputConfig,
|
||||||
FieldTextInputFromJsonConfig,
|
FieldTextInputFromJsonConfig,
|
||||||
FieldTextInputValidator,
|
FieldTextInputValidator,
|
||||||
};
|
FieldValidator,
|
||||||
export {
|
|
||||||
FieldVariable,
|
FieldVariable,
|
||||||
FieldVariableConfig,
|
FieldVariableConfig,
|
||||||
FieldVariableFromJsonConfig,
|
FieldVariableFromJsonConfig,
|
||||||
FieldVariableValidator,
|
FieldVariableValidator,
|
||||||
|
Flyout,
|
||||||
|
FlyoutButton,
|
||||||
|
FlyoutItem,
|
||||||
|
FlyoutMetricsManager,
|
||||||
|
FlyoutSeparator,
|
||||||
|
CodeGenerator as Generator,
|
||||||
|
Gesture,
|
||||||
|
Grid,
|
||||||
|
HorizontalFlyout,
|
||||||
|
IASTNodeLocation,
|
||||||
|
IASTNodeLocationSvg,
|
||||||
|
IASTNodeLocationWithBlock,
|
||||||
|
IAutoHideable,
|
||||||
|
IBoundedElement,
|
||||||
|
IBubble,
|
||||||
|
ICollapsibleToolboxItem,
|
||||||
|
IComponent,
|
||||||
|
IConnectionChecker,
|
||||||
|
IConnectionPreviewer,
|
||||||
|
IContextMenu,
|
||||||
|
ICopyData,
|
||||||
|
ICopyable,
|
||||||
|
IDeletable,
|
||||||
|
IDeleteArea,
|
||||||
|
IDragStrategy,
|
||||||
|
IDragTarget,
|
||||||
|
IDraggable,
|
||||||
|
IDragger,
|
||||||
|
IFlyout,
|
||||||
|
IFlyoutInflater,
|
||||||
|
IHasBubble,
|
||||||
|
IIcon,
|
||||||
|
IKeyboardAccessible,
|
||||||
|
IMetricsManager,
|
||||||
|
IMovable,
|
||||||
|
IObservable,
|
||||||
|
IPaster,
|
||||||
|
IPositionable,
|
||||||
|
IRegistrable,
|
||||||
|
IRenderedElement,
|
||||||
|
ISelectable,
|
||||||
|
ISelectableToolboxItem,
|
||||||
|
ISerializable,
|
||||||
|
IStyleable,
|
||||||
|
IToolbox,
|
||||||
|
IToolboxItem,
|
||||||
|
IVariableBackedParameterModel,
|
||||||
|
IVariableMap,
|
||||||
|
IVariableModel,
|
||||||
|
IVariableState,
|
||||||
|
ImageProperties,
|
||||||
|
Input,
|
||||||
|
InsertionMarkerPreviewer,
|
||||||
|
LabelFlyoutInflater,
|
||||||
|
LayerManager,
|
||||||
|
Marker,
|
||||||
|
MarkerManager,
|
||||||
|
Menu,
|
||||||
|
MenuGenerator,
|
||||||
|
MenuGeneratorFunction,
|
||||||
|
MenuItem,
|
||||||
|
MenuOption,
|
||||||
|
MetricsManager,
|
||||||
|
Msg,
|
||||||
|
Names,
|
||||||
|
Options,
|
||||||
|
RenderedConnection,
|
||||||
|
Scrollbar,
|
||||||
|
ScrollbarPair,
|
||||||
|
SeparatorFlyoutInflater,
|
||||||
|
ShortcutRegistry,
|
||||||
|
TabNavigateCursor,
|
||||||
|
Theme,
|
||||||
|
ThemeManager,
|
||||||
|
Toolbox,
|
||||||
|
ToolboxCategory,
|
||||||
|
ToolboxItem,
|
||||||
|
ToolboxSeparator,
|
||||||
|
Trashcan,
|
||||||
|
UnattachedFieldError,
|
||||||
|
VariableMap,
|
||||||
|
VariableModel,
|
||||||
|
VerticalFlyout,
|
||||||
|
Workspace,
|
||||||
|
WorkspaceAudio,
|
||||||
|
WorkspaceDragger,
|
||||||
|
WorkspaceSvg,
|
||||||
|
ZoomControls,
|
||||||
|
config,
|
||||||
|
hasBubble,
|
||||||
|
icons,
|
||||||
|
inject,
|
||||||
|
inputs,
|
||||||
|
isCopyable,
|
||||||
|
isDeletable,
|
||||||
|
isDraggable,
|
||||||
|
isIcon,
|
||||||
|
isObservable,
|
||||||
|
isPaster,
|
||||||
|
isRenderedElement,
|
||||||
|
isSelectable,
|
||||||
|
isSerializable,
|
||||||
|
isVariableBackedParameterModel,
|
||||||
|
layers,
|
||||||
|
renderManagement,
|
||||||
|
serialization,
|
||||||
|
setLocale,
|
||||||
};
|
};
|
||||||
export {Flyout, FlyoutItem};
|
|
||||||
export {FlyoutButton};
|
|
||||||
export {FlyoutMetricsManager};
|
|
||||||
export {FlyoutSeparator};
|
|
||||||
export {IFlyoutInflater};
|
|
||||||
export {BlockFlyoutInflater};
|
|
||||||
export {ButtonFlyoutInflater};
|
|
||||||
export {LabelFlyoutInflater};
|
|
||||||
export {SeparatorFlyoutInflater};
|
|
||||||
export {CodeGenerator};
|
|
||||||
export {CodeGenerator as Generator}; // Deprecated name, October 2022.
|
|
||||||
export {Gesture};
|
|
||||||
export {Grid};
|
|
||||||
export {HorizontalFlyout};
|
|
||||||
export {IASTNodeLocation};
|
|
||||||
export {IASTNodeLocationSvg};
|
|
||||||
export {IASTNodeLocationWithBlock};
|
|
||||||
export {IAutoHideable};
|
|
||||||
export {IBoundedElement};
|
|
||||||
export {IBubble};
|
|
||||||
export {ICollapsibleToolboxItem};
|
|
||||||
export {IComponent};
|
|
||||||
export {IConnectionChecker};
|
|
||||||
export {IConnectionPreviewer};
|
|
||||||
export {IContextMenu};
|
|
||||||
export {icons};
|
|
||||||
export {ICopyable, isCopyable, ICopyData};
|
|
||||||
export {IDeletable, isDeletable};
|
|
||||||
export {IDeleteArea};
|
|
||||||
export {IDragTarget};
|
|
||||||
export {IDragger};
|
|
||||||
export {IDraggable, isDraggable, IDragStrategy};
|
|
||||||
export {IFlyout};
|
|
||||||
export {IHasBubble, hasBubble};
|
|
||||||
export {IIcon, isIcon};
|
|
||||||
export {IKeyboardAccessible};
|
|
||||||
export {IMetricsManager};
|
|
||||||
export {IMovable};
|
|
||||||
export {Input};
|
|
||||||
export {inputs};
|
|
||||||
export {InsertionMarkerPreviewer};
|
|
||||||
export {IObservable, isObservable};
|
|
||||||
export {IPaster, isPaster};
|
|
||||||
export {IPositionable};
|
|
||||||
export {IRegistrable};
|
|
||||||
export {IRenderedElement, isRenderedElement};
|
|
||||||
export {ISelectable, isSelectable};
|
|
||||||
export {ISelectableToolboxItem};
|
|
||||||
export {ISerializable, isSerializable};
|
|
||||||
export {IStyleable};
|
|
||||||
export {IToolbox};
|
|
||||||
export {IToolboxItem};
|
|
||||||
export {IVariableMap};
|
|
||||||
export {IVariableModel};
|
|
||||||
export {IVariableState};
|
|
||||||
export {IVariableBackedParameterModel, isVariableBackedParameterModel};
|
|
||||||
export {Marker};
|
|
||||||
export {MarkerManager};
|
|
||||||
export {LayerManager};
|
|
||||||
export {Menu};
|
|
||||||
export {MenuItem};
|
|
||||||
export {MetricsManager};
|
|
||||||
export {Msg, setLocale};
|
|
||||||
export {Names};
|
|
||||||
export {Options};
|
|
||||||
export {RenderedConnection};
|
|
||||||
export {renderManagement};
|
|
||||||
export {Scrollbar};
|
|
||||||
export {ScrollbarPair};
|
|
||||||
export {ShortcutRegistry};
|
|
||||||
export {TabNavigateCursor};
|
|
||||||
export {Theme};
|
|
||||||
export {ThemeManager};
|
|
||||||
export {Toolbox};
|
|
||||||
export {ToolboxCategory};
|
|
||||||
export {ToolboxItem};
|
|
||||||
export {ToolboxSeparator};
|
|
||||||
export {Trashcan};
|
|
||||||
export {VariableMap};
|
|
||||||
export {VariableModel};
|
|
||||||
export {VerticalFlyout};
|
|
||||||
export {Workspace};
|
|
||||||
export {WorkspaceAudio};
|
|
||||||
export {WorkspaceDragger};
|
|
||||||
export {WorkspaceSvg};
|
|
||||||
export {ZoomControls};
|
|
||||||
export {config};
|
|
||||||
export {inject};
|
|
||||||
export {serialization};
|
|
||||||
export {layers};
|
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
|
|
||||||
// Former goog.module ID: Blockly.BlocklyOptions
|
// Former goog.module ID: Blockly.BlocklyOptions
|
||||||
|
|
||||||
import type {Theme, ITheme} from './theme.js';
|
import type {ITheme, Theme} from './theme.js';
|
||||||
import type {WorkspaceSvg} from './workspace_svg.js';
|
|
||||||
import type {ToolboxDefinition} from './utils/toolbox.js';
|
import type {ToolboxDefinition} from './utils/toolbox.js';
|
||||||
|
import type {WorkspaceSvg} from './workspace_svg.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blockly options.
|
* Blockly options.
|
||||||
|
|||||||
@@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
// Former goog.module ID: Blockly.browserEvents
|
// Former goog.module ID: Blockly.browserEvents
|
||||||
|
|
||||||
|
// Theoretically we could figure out a way to type the event params correctly,
|
||||||
|
// but it's not high priority.
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-function-type */
|
||||||
|
|
||||||
import * as Touch from './touch.js';
|
import * as Touch from './touch.js';
|
||||||
import * as userAgent from './utils/useragent.js';
|
import * as userAgent from './utils/useragent.js';
|
||||||
|
|
||||||
@@ -47,7 +51,7 @@ const PAGE_MODE_MULTIPLIER = 125;
|
|||||||
export function conditionalBind(
|
export function conditionalBind(
|
||||||
node: EventTarget,
|
node: EventTarget,
|
||||||
name: string,
|
name: string,
|
||||||
thisObject: Object | null,
|
thisObject: object | null,
|
||||||
func: Function,
|
func: Function,
|
||||||
opt_noCaptureIdentifier?: boolean,
|
opt_noCaptureIdentifier?: boolean,
|
||||||
): Data {
|
): Data {
|
||||||
@@ -96,7 +100,7 @@ export function conditionalBind(
|
|||||||
export function bind(
|
export function bind(
|
||||||
node: EventTarget,
|
node: EventTarget,
|
||||||
name: string,
|
name: string,
|
||||||
thisObject: Object | null,
|
thisObject: object | null,
|
||||||
func: Function,
|
func: Function,
|
||||||
): Data {
|
): Data {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Bubble} from './bubbles/bubble.js';
|
import {Bubble} from './bubbles/bubble.js';
|
||||||
|
import {MiniWorkspaceBubble} from './bubbles/mini_workspace_bubble.js';
|
||||||
import {TextBubble} from './bubbles/text_bubble.js';
|
import {TextBubble} from './bubbles/text_bubble.js';
|
||||||
import {TextInputBubble} from './bubbles/textinput_bubble.js';
|
import {TextInputBubble} from './bubbles/textinput_bubble.js';
|
||||||
import {MiniWorkspaceBubble} from './bubbles/mini_workspace_bubble.js';
|
|
||||||
|
|
||||||
export {Bubble, TextBubble, TextInputBubble, MiniWorkspaceBubble};
|
export {Bubble, MiniWorkspaceBubble, TextBubble, TextInputBubble};
|
||||||
|
|||||||
@@ -4,21 +4,21 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {ISelectable} from '../blockly.js';
|
||||||
import * as browserEvents from '../browser_events.js';
|
import * as browserEvents from '../browser_events.js';
|
||||||
|
import * as common from '../common.js';
|
||||||
import {BubbleDragStrategy} from '../dragging/bubble_drag_strategy.js';
|
import {BubbleDragStrategy} from '../dragging/bubble_drag_strategy.js';
|
||||||
import {IBubble} from '../interfaces/i_bubble.js';
|
import {IBubble} from '../interfaces/i_bubble.js';
|
||||||
import {ContainerRegion} from '../metrics_manager.js';
|
import {ContainerRegion} from '../metrics_manager.js';
|
||||||
import {Scrollbar} from '../scrollbar.js';
|
import {Scrollbar} from '../scrollbar.js';
|
||||||
import {Coordinate} from '../utils/coordinate.js';
|
import {Coordinate} from '../utils/coordinate.js';
|
||||||
import * as dom from '../utils/dom.js';
|
import * as dom from '../utils/dom.js';
|
||||||
|
import * as idGenerator from '../utils/idgenerator.js';
|
||||||
import * as math from '../utils/math.js';
|
import * as math from '../utils/math.js';
|
||||||
import {Rect} from '../utils/rect.js';
|
import {Rect} from '../utils/rect.js';
|
||||||
import {Size} from '../utils/size.js';
|
import {Size} from '../utils/size.js';
|
||||||
import {Svg} from '../utils/svg.js';
|
import {Svg} from '../utils/svg.js';
|
||||||
import {WorkspaceSvg} from '../workspace_svg.js';
|
import {WorkspaceSvg} from '../workspace_svg.js';
|
||||||
import * as common from '../common.js';
|
|
||||||
import {ISelectable} from '../blockly.js';
|
|
||||||
import * as idGenerator from '../utils/idgenerator.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The abstract pop-up bubble class. This creates a UI that looks like a speech
|
* The abstract pop-up bubble class. This creates a UI that looks like a speech
|
||||||
@@ -208,9 +208,10 @@ export abstract class Bubble implements IBubble, ISelectable {
|
|||||||
this.background.setAttribute('fill', colour);
|
this.background.setAttribute('fill', colour);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Passes the pointer event off to the gesture system. */
|
/** Brings the bubble to the front and passes the pointer event off to the gesture system. */
|
||||||
private onMouseDown(e: PointerEvent) {
|
private onMouseDown(e: PointerEvent) {
|
||||||
this.workspace.getGesture(e)?.handleBubbleStart(e, this);
|
this.workspace.getGesture(e)?.handleBubbleStart(e, this);
|
||||||
|
this.bringToFront();
|
||||||
common.setSelected(this);
|
common.setSelected(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,16 +4,16 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Abstract as AbstractEvent} from '../events/events_abstract.js';
|
|
||||||
import type {BlocklyOptions} from '../blockly_options.js';
|
import type {BlocklyOptions} from '../blockly_options.js';
|
||||||
import {Bubble} from './bubble.js';
|
import {Abstract as AbstractEvent} from '../events/events_abstract.js';
|
||||||
|
import {Options} from '../options.js';
|
||||||
import {Coordinate} from '../utils/coordinate.js';
|
import {Coordinate} from '../utils/coordinate.js';
|
||||||
import * as dom from '../utils/dom.js';
|
import * as dom from '../utils/dom.js';
|
||||||
import {Options} from '../options.js';
|
|
||||||
import {Svg} from '../utils/svg.js';
|
|
||||||
import type {Rect} from '../utils/rect.js';
|
import type {Rect} from '../utils/rect.js';
|
||||||
import {Size} from '../utils/size.js';
|
import {Size} from '../utils/size.js';
|
||||||
|
import {Svg} from '../utils/svg.js';
|
||||||
import type {WorkspaceSvg} from '../workspace_svg.js';
|
import type {WorkspaceSvg} from '../workspace_svg.js';
|
||||||
|
import {Bubble} from './bubble.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A bubble that contains a mini-workspace which can hold arbitrary blocks.
|
* A bubble that contains a mini-workspace which can hold arbitrary blocks.
|
||||||
|
|||||||
@@ -4,13 +4,13 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Bubble} from './bubble.js';
|
|
||||||
import {Coordinate} from '../utils/coordinate.js';
|
import {Coordinate} from '../utils/coordinate.js';
|
||||||
import * as dom from '../utils/dom.js';
|
import * as dom from '../utils/dom.js';
|
||||||
import {Rect} from '../utils/rect.js';
|
import {Rect} from '../utils/rect.js';
|
||||||
import {Size} from '../utils/size.js';
|
import {Size} from '../utils/size.js';
|
||||||
import {Svg} from '../utils/svg.js';
|
import {Svg} from '../utils/svg.js';
|
||||||
import {WorkspaceSvg} from '../workspace_svg.js';
|
import {WorkspaceSvg} from '../workspace_svg.js';
|
||||||
|
import {Bubble} from './bubble.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A bubble that displays non-editable text. Used by the warning icon.
|
* A bubble that displays non-editable text. Used by the warning icon.
|
||||||
|
|||||||
@@ -4,16 +4,17 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Bubble} from './bubble.js';
|
|
||||||
import {Coordinate} from '../utils/coordinate.js';
|
|
||||||
import * as Css from '../css.js';
|
import * as Css from '../css.js';
|
||||||
|
import * as touch from '../touch.js';
|
||||||
|
import {browserEvents} from '../utils.js';
|
||||||
|
import {Coordinate} from '../utils/coordinate.js';
|
||||||
import * as dom from '../utils/dom.js';
|
import * as dom from '../utils/dom.js';
|
||||||
|
import * as drag from '../utils/drag.js';
|
||||||
import {Rect} from '../utils/rect.js';
|
import {Rect} from '../utils/rect.js';
|
||||||
import {Size} from '../utils/size.js';
|
import {Size} from '../utils/size.js';
|
||||||
import {Svg} from '../utils/svg.js';
|
import {Svg} from '../utils/svg.js';
|
||||||
import * as touch from '../touch.js';
|
|
||||||
import {WorkspaceSvg} from '../workspace_svg.js';
|
import {WorkspaceSvg} from '../workspace_svg.js';
|
||||||
import {browserEvents} from '../utils.js';
|
import {Bubble} from './bubble.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A bubble that displays editable text. It can also be resized by the user.
|
* A bubble that displays editable text. It can also be resized by the user.
|
||||||
@@ -65,6 +66,8 @@ export class TextInputBubble extends Bubble {
|
|||||||
20 + Bubble.DOUBLE_BORDER,
|
20 + Bubble.DOUBLE_BORDER,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private editable = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param workspace The workspace this bubble belongs to.
|
* @param workspace The workspace this bubble belongs to.
|
||||||
* @param anchor The anchor location of the thing this bubble is attached to.
|
* @param anchor The anchor location of the thing this bubble is attached to.
|
||||||
@@ -98,6 +101,21 @@ export class TextInputBubble extends Bubble {
|
|||||||
this.onTextChange();
|
this.onTextChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Sets whether or not the text in the bubble is editable. */
|
||||||
|
setEditable(editable: boolean) {
|
||||||
|
this.editable = editable;
|
||||||
|
if (this.editable) {
|
||||||
|
this.textArea.removeAttribute('readonly');
|
||||||
|
} else {
|
||||||
|
this.textArea.setAttribute('readonly', '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns whether or not the text in the bubble is editable. */
|
||||||
|
isEditable(): boolean {
|
||||||
|
return this.editable;
|
||||||
|
}
|
||||||
|
|
||||||
/** Adds a change listener to be notified when this bubble's text changes. */
|
/** Adds a change listener to be notified when this bubble's text changes. */
|
||||||
addTextChangeListener(listener: () => void) {
|
addTextChangeListener(listener: () => void) {
|
||||||
this.textChangeListeners.push(listener);
|
this.textChangeListeners.push(listener);
|
||||||
@@ -247,7 +265,8 @@ export class TextInputBubble extends Bubble {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.workspace.startDrag(
|
drag.start(
|
||||||
|
this.workspace,
|
||||||
e,
|
e,
|
||||||
new Coordinate(
|
new Coordinate(
|
||||||
this.workspace.RTL ? -this.getSize().width : this.getSize().width,
|
this.workspace.RTL ? -this.getSize().width : this.getSize().width,
|
||||||
@@ -287,7 +306,7 @@ export class TextInputBubble extends Bubble {
|
|||||||
|
|
||||||
/** Handles pointer move events on the resize target. */
|
/** Handles pointer move events on the resize target. */
|
||||||
private onResizePointerMove(e: PointerEvent) {
|
private onResizePointerMove(e: PointerEvent) {
|
||||||
const delta = this.workspace.moveDrag(e);
|
const delta = drag.move(this.workspace, e);
|
||||||
this.setSize(
|
this.setSize(
|
||||||
new Size(this.workspace.RTL ? -delta.x : delta.x, delta.y),
|
new Size(this.workspace.RTL ? -delta.x : delta.x, delta.y),
|
||||||
false,
|
false,
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ import type {BlockMove} from './events/events_block_move.js';
|
|||||||
import type {CommentCreate} from './events/events_comment_create.js';
|
import type {CommentCreate} from './events/events_comment_create.js';
|
||||||
import type {CommentMove} from './events/events_comment_move.js';
|
import type {CommentMove} from './events/events_comment_move.js';
|
||||||
import type {CommentResize} from './events/events_comment_resize.js';
|
import type {CommentResize} from './events/events_comment_resize.js';
|
||||||
import type {ViewportChange} from './events/events_viewport.js';
|
import {isViewportChange} from './events/predicates.js';
|
||||||
|
import {BUMP_EVENTS, EventType} from './events/type.js';
|
||||||
import * as eventUtils from './events/utils.js';
|
import * as eventUtils from './events/utils.js';
|
||||||
import type {IBoundedElement} from './interfaces/i_bounded_element.js';
|
import type {IBoundedElement} from './interfaces/i_bounded_element.js';
|
||||||
import type {ContainerRegion} from './metrics_manager.js';
|
import type {ContainerRegion} from './metrics_manager.js';
|
||||||
@@ -99,7 +100,7 @@ export function bumpIntoBoundsHandler(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventUtils.BUMP_EVENTS.includes(e.type ?? '')) {
|
if (BUMP_EVENTS.includes(e.type ?? '')) {
|
||||||
const scrollMetricsInWsCoords = metricsManager.getScrollMetrics(true);
|
const scrollMetricsInWsCoords = metricsManager.getScrollMetrics(true);
|
||||||
|
|
||||||
// Triggered by move/create event
|
// Triggered by move/create event
|
||||||
@@ -127,13 +128,8 @@ export function bumpIntoBoundsHandler(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
eventUtils.setGroup(existingGroup);
|
eventUtils.setGroup(existingGroup);
|
||||||
} else if (e.type === eventUtils.VIEWPORT_CHANGE) {
|
} else if (isViewportChange(e)) {
|
||||||
const viewportEvent = e as ViewportChange;
|
if (e.scale && e.oldScale && e.scale > e.oldScale) {
|
||||||
if (
|
|
||||||
viewportEvent.scale &&
|
|
||||||
viewportEvent.oldScale &&
|
|
||||||
viewportEvent.scale > viewportEvent.oldScale
|
|
||||||
) {
|
|
||||||
bumpTopObjectsIntoBounds(workspace);
|
bumpTopObjectsIntoBounds(workspace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,16 +151,16 @@ function extractObjectFromEvent(
|
|||||||
): IBoundedElement | null {
|
): IBoundedElement | null {
|
||||||
let object = null;
|
let object = null;
|
||||||
switch (e.type) {
|
switch (e.type) {
|
||||||
case eventUtils.BLOCK_CREATE:
|
case EventType.BLOCK_CREATE:
|
||||||
case eventUtils.BLOCK_MOVE:
|
case EventType.BLOCK_MOVE:
|
||||||
object = workspace.getBlockById((e as BlockCreate | BlockMove).blockId!);
|
object = workspace.getBlockById((e as BlockCreate | BlockMove).blockId!);
|
||||||
if (object) {
|
if (object) {
|
||||||
object = object.getRootBlock();
|
object = object.getRootBlock();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case eventUtils.COMMENT_CREATE:
|
case EventType.COMMENT_CREATE:
|
||||||
case eventUtils.COMMENT_MOVE:
|
case EventType.COMMENT_MOVE:
|
||||||
case eventUtils.COMMENT_RESIZE:
|
case EventType.COMMENT_RESIZE:
|
||||||
object = workspace.getCommentById(
|
object = workspace.getCommentById(
|
||||||
(e as CommentCreate | CommentMove | CommentResize).commentId!,
|
(e as CommentCreate | CommentMove | CommentResize).commentId!,
|
||||||
) as RenderedWorkspaceComment;
|
) as RenderedWorkspaceComment;
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
|
|
||||||
// Former goog.module ID: Blockly.clipboard
|
// Former goog.module ID: Blockly.clipboard
|
||||||
|
|
||||||
import type {ICopyData, ICopyable} from './interfaces/i_copyable.js';
|
import {BlockCopyData, BlockPaster} from './clipboard/block_paster.js';
|
||||||
import {BlockPaster, BlockCopyData} from './clipboard/block_paster.js';
|
|
||||||
import * as globalRegistry from './registry.js';
|
|
||||||
import {WorkspaceSvg} from './workspace_svg.js';
|
|
||||||
import * as registry from './clipboard/registry.js';
|
import * as registry from './clipboard/registry.js';
|
||||||
|
import type {ICopyData, ICopyable} from './interfaces/i_copyable.js';
|
||||||
|
import * as globalRegistry from './registry.js';
|
||||||
import {Coordinate} from './utils/coordinate.js';
|
import {Coordinate} from './utils/coordinate.js';
|
||||||
|
import {WorkspaceSvg} from './workspace_svg.js';
|
||||||
|
|
||||||
/** Metadata about the object that is currently on the clipboard. */
|
/** Metadata about the object that is currently on the clipboard. */
|
||||||
let stashedCopyData: ICopyData | null = null;
|
let stashedCopyData: ICopyData | null = null;
|
||||||
@@ -110,4 +110,4 @@ export const TEST_ONLY = {
|
|||||||
copyInternal,
|
copyInternal,
|
||||||
};
|
};
|
||||||
|
|
||||||
export {BlockPaster, BlockCopyData, registry};
|
export {BlockCopyData, BlockPaster, registry};
|
||||||
|
|||||||
@@ -5,15 +5,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {BlockSvg} from '../block_svg.js';
|
import {BlockSvg} from '../block_svg.js';
|
||||||
import * as registry from './registry.js';
|
import * as common from '../common.js';
|
||||||
|
import {config} from '../config.js';
|
||||||
|
import {EventType} from '../events/type.js';
|
||||||
|
import * as eventUtils from '../events/utils.js';
|
||||||
import {ICopyData} from '../interfaces/i_copyable.js';
|
import {ICopyData} from '../interfaces/i_copyable.js';
|
||||||
import {IPaster} from '../interfaces/i_paster.js';
|
import {IPaster} from '../interfaces/i_paster.js';
|
||||||
import {State, append} from '../serialization/blocks.js';
|
import {State, append} from '../serialization/blocks.js';
|
||||||
import {Coordinate} from '../utils/coordinate.js';
|
import {Coordinate} from '../utils/coordinate.js';
|
||||||
import {WorkspaceSvg} from '../workspace_svg.js';
|
import {WorkspaceSvg} from '../workspace_svg.js';
|
||||||
import * as eventUtils from '../events/utils.js';
|
import * as registry from './registry.js';
|
||||||
import {config} from '../config.js';
|
|
||||||
import * as common from '../common.js';
|
|
||||||
|
|
||||||
export class BlockPaster implements IPaster<BlockCopyData, BlockSvg> {
|
export class BlockPaster implements IPaster<BlockCopyData, BlockSvg> {
|
||||||
static TYPE = 'block';
|
static TYPE = 'block';
|
||||||
@@ -52,7 +53,7 @@ export class BlockPaster implements IPaster<BlockCopyData, BlockSvg> {
|
|||||||
if (!block) return block;
|
if (!block) return block;
|
||||||
|
|
||||||
if (eventUtils.isEnabled() && !block.isShadow()) {
|
if (eventUtils.isEnabled() && !block.isShadow()) {
|
||||||
eventUtils.fire(new (eventUtils.get(eventUtils.BLOCK_CREATE))(block));
|
eventUtils.fire(new (eventUtils.get(EventType.BLOCK_CREATE))(block));
|
||||||
}
|
}
|
||||||
common.setSelected(block);
|
common.setSelected(block);
|
||||||
return block;
|
return block;
|
||||||
|
|||||||
@@ -4,15 +4,16 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {IPaster} from '../interfaces/i_paster.js';
|
import {RenderedWorkspaceComment} from '../comments/rendered_workspace_comment.js';
|
||||||
|
import * as common from '../common.js';
|
||||||
|
import {EventType} from '../events/type.js';
|
||||||
|
import * as eventUtils from '../events/utils.js';
|
||||||
import {ICopyData} from '../interfaces/i_copyable.js';
|
import {ICopyData} from '../interfaces/i_copyable.js';
|
||||||
|
import {IPaster} from '../interfaces/i_paster.js';
|
||||||
|
import * as commentSerialiation from '../serialization/workspace_comments.js';
|
||||||
import {Coordinate} from '../utils/coordinate.js';
|
import {Coordinate} from '../utils/coordinate.js';
|
||||||
import {WorkspaceSvg} from '../workspace_svg.js';
|
import {WorkspaceSvg} from '../workspace_svg.js';
|
||||||
import * as registry from './registry.js';
|
import * as registry from './registry.js';
|
||||||
import * as commentSerialiation from '../serialization/workspace_comments.js';
|
|
||||||
import * as eventUtils from '../events/utils.js';
|
|
||||||
import * as common from '../common.js';
|
|
||||||
import {RenderedWorkspaceComment} from '../comments/rendered_workspace_comment.js';
|
|
||||||
|
|
||||||
export class WorkspaceCommentPaster
|
export class WorkspaceCommentPaster
|
||||||
implements IPaster<WorkspaceCommentCopyData, RenderedWorkspaceComment>
|
implements IPaster<WorkspaceCommentCopyData, RenderedWorkspaceComment>
|
||||||
@@ -46,7 +47,7 @@ export class WorkspaceCommentPaster
|
|||||||
if (!comment) return null;
|
if (!comment) return null;
|
||||||
|
|
||||||
if (eventUtils.isEnabled()) {
|
if (eventUtils.isEnabled()) {
|
||||||
eventUtils.fire(new (eventUtils.get(eventUtils.COMMENT_CREATE))(comment));
|
eventUtils.fire(new (eventUtils.get(EventType.COMMENT_CREATE))(comment));
|
||||||
}
|
}
|
||||||
common.setSelected(comment);
|
common.setSelected(comment);
|
||||||
return comment;
|
return comment;
|
||||||
|
|||||||
@@ -5,5 +5,5 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export {CommentView} from './comments/comment_view.js';
|
export {CommentView} from './comments/comment_view.js';
|
||||||
export {WorkspaceComment} from './comments/workspace_comment.js';
|
|
||||||
export {RenderedWorkspaceComment} from './comments/rendered_workspace_comment.js';
|
export {RenderedWorkspaceComment} from './comments/rendered_workspace_comment.js';
|
||||||
|
export {WorkspaceComment} from './comments/workspace_comment.js';
|
||||||
|
|||||||
@@ -4,16 +4,17 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {IRenderedElement} from '../interfaces/i_rendered_element.js';
|
|
||||||
import {WorkspaceSvg} from '../workspace_svg.js';
|
|
||||||
import * as dom from '../utils/dom.js';
|
|
||||||
import {Svg} from '../utils/svg.js';
|
|
||||||
import * as layers from '../layers.js';
|
|
||||||
import * as css from '../css.js';
|
|
||||||
import {Coordinate} from '../utils/coordinate.js';
|
|
||||||
import {Size} from '../utils/size.js';
|
|
||||||
import * as browserEvents from '../browser_events.js';
|
import * as browserEvents from '../browser_events.js';
|
||||||
|
import * as css from '../css.js';
|
||||||
|
import {IRenderedElement} from '../interfaces/i_rendered_element.js';
|
||||||
|
import * as layers from '../layers.js';
|
||||||
import * as touch from '../touch.js';
|
import * as touch from '../touch.js';
|
||||||
|
import {Coordinate} from '../utils/coordinate.js';
|
||||||
|
import * as dom from '../utils/dom.js';
|
||||||
|
import * as drag from '../utils/drag.js';
|
||||||
|
import {Size} from '../utils/size.js';
|
||||||
|
import {Svg} from '../utils/svg.js';
|
||||||
|
import {WorkspaceSvg} from '../workspace_svg.js';
|
||||||
|
|
||||||
export class CommentView implements IRenderedElement {
|
export class CommentView implements IRenderedElement {
|
||||||
/** The root group element of the comment view. */
|
/** The root group element of the comment view. */
|
||||||
@@ -528,8 +529,8 @@ export class CommentView implements IRenderedElement {
|
|||||||
|
|
||||||
this.preResizeSize = this.getSize();
|
this.preResizeSize = this.getSize();
|
||||||
|
|
||||||
// TODO(#7926): Move this into a utils file.
|
drag.start(
|
||||||
this.workspace.startDrag(
|
this.workspace,
|
||||||
e,
|
e,
|
||||||
new Coordinate(
|
new Coordinate(
|
||||||
this.workspace.RTL ? -this.getSize().width : this.getSize().width,
|
this.workspace.RTL ? -this.getSize().width : this.getSize().width,
|
||||||
@@ -573,8 +574,7 @@ export class CommentView implements IRenderedElement {
|
|||||||
|
|
||||||
/** Resizes the comment in response to a drag on the resize handle. */
|
/** Resizes the comment in response to a drag on the resize handle. */
|
||||||
private onResizePointerMove(e: PointerEvent) {
|
private onResizePointerMove(e: PointerEvent) {
|
||||||
// TODO(#7926): Move this into a utils file.
|
const size = drag.move(this.workspace, e);
|
||||||
const size = this.workspace.moveDrag(e);
|
|
||||||
this.setSizeWithoutFiringEvents(
|
this.setSizeWithoutFiringEvents(
|
||||||
new Size(this.workspace.RTL ? -size.x : size.x, size.y),
|
new Size(this.workspace.RTL ? -size.x : size.x, size.y),
|
||||||
);
|
);
|
||||||
@@ -627,6 +627,7 @@ export class CommentView implements IRenderedElement {
|
|||||||
* event on the foldout icon.
|
* event on the foldout icon.
|
||||||
*/
|
*/
|
||||||
private onFoldoutDown(e: PointerEvent) {
|
private onFoldoutDown(e: PointerEvent) {
|
||||||
|
touch.clearTouchIdentifier();
|
||||||
this.bringToFront();
|
this.bringToFront();
|
||||||
if (browserEvents.isRightButton(e)) {
|
if (browserEvents.isRightButton(e)) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -747,6 +748,7 @@ export class CommentView implements IRenderedElement {
|
|||||||
* delete icon.
|
* delete icon.
|
||||||
*/
|
*/
|
||||||
private onDeleteDown(e: PointerEvent) {
|
private onDeleteDown(e: PointerEvent) {
|
||||||
|
touch.clearTouchIdentifier();
|
||||||
if (browserEvents.isRightButton(e)) {
|
if (browserEvents.isRightButton(e)) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
return;
|
return;
|
||||||
@@ -836,7 +838,6 @@ css.register(`
|
|||||||
}
|
}
|
||||||
|
|
||||||
.blocklyCommentTopbarBackground {
|
.blocklyCommentTopbarBackground {
|
||||||
cursor: grab;
|
|
||||||
fill: var(--commentBorderColour);
|
fill: var(--commentBorderColour);
|
||||||
height: 24px;
|
height: 24px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,30 +4,31 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {WorkspaceComment} from './workspace_comment.js';
|
|
||||||
import {WorkspaceSvg} from '../workspace_svg.js';
|
|
||||||
import {CommentView} from './comment_view.js';
|
|
||||||
import {Coordinate} from '../utils/coordinate.js';
|
|
||||||
import {Rect} from '../utils/rect.js';
|
|
||||||
import {Size} from '../utils/size.js';
|
|
||||||
import {IBoundedElement} from '../interfaces/i_bounded_element.js';
|
|
||||||
import {IRenderedElement} from '../interfaces/i_rendered_element.js';
|
|
||||||
import * as dom from '../utils/dom.js';
|
|
||||||
import {IDraggable} from '../interfaces/i_draggable.js';
|
|
||||||
import {CommentDragStrategy} from '../dragging/comment_drag_strategy.js';
|
|
||||||
import * as browserEvents from '../browser_events.js';
|
import * as browserEvents from '../browser_events.js';
|
||||||
import * as common from '../common.js';
|
|
||||||
import {ISelectable} from '../interfaces/i_selectable.js';
|
|
||||||
import {IDeletable} from '../interfaces/i_deletable.js';
|
|
||||||
import {ICopyable} from '../interfaces/i_copyable.js';
|
|
||||||
import * as commentSerialization from '../serialization/workspace_comments.js';
|
|
||||||
import {
|
import {
|
||||||
WorkspaceCommentPaster,
|
|
||||||
WorkspaceCommentCopyData,
|
WorkspaceCommentCopyData,
|
||||||
|
WorkspaceCommentPaster,
|
||||||
} from '../clipboard/workspace_comment_paster.js';
|
} from '../clipboard/workspace_comment_paster.js';
|
||||||
import {IContextMenu} from '../interfaces/i_contextmenu.js';
|
import * as common from '../common.js';
|
||||||
import * as contextMenu from '../contextmenu.js';
|
import * as contextMenu from '../contextmenu.js';
|
||||||
import {ContextMenuRegistry} from '../contextmenu_registry.js';
|
import {ContextMenuRegistry} from '../contextmenu_registry.js';
|
||||||
|
import {CommentDragStrategy} from '../dragging/comment_drag_strategy.js';
|
||||||
|
import {IBoundedElement} from '../interfaces/i_bounded_element.js';
|
||||||
|
import {IContextMenu} from '../interfaces/i_contextmenu.js';
|
||||||
|
import {ICopyable} from '../interfaces/i_copyable.js';
|
||||||
|
import {IDeletable} from '../interfaces/i_deletable.js';
|
||||||
|
import {IDraggable} from '../interfaces/i_draggable.js';
|
||||||
|
import {IRenderedElement} from '../interfaces/i_rendered_element.js';
|
||||||
|
import {ISelectable} from '../interfaces/i_selectable.js';
|
||||||
|
import * as layers from '../layers.js';
|
||||||
|
import * as commentSerialization from '../serialization/workspace_comments.js';
|
||||||
|
import {Coordinate} from '../utils/coordinate.js';
|
||||||
|
import * as dom from '../utils/dom.js';
|
||||||
|
import {Rect} from '../utils/rect.js';
|
||||||
|
import {Size} from '../utils/size.js';
|
||||||
|
import {WorkspaceSvg} from '../workspace_svg.js';
|
||||||
|
import {CommentView} from './comment_view.js';
|
||||||
|
import {WorkspaceComment} from './workspace_comment.js';
|
||||||
|
|
||||||
export class RenderedWorkspaceComment
|
export class RenderedWorkspaceComment
|
||||||
extends WorkspaceComment
|
extends WorkspaceComment
|
||||||
@@ -213,6 +214,7 @@ export class RenderedWorkspaceComment
|
|||||||
const gesture = this.workspace.getGesture(e);
|
const gesture = this.workspace.getGesture(e);
|
||||||
if (gesture) {
|
if (gesture) {
|
||||||
gesture.handleCommentStart(e, this);
|
gesture.handleCommentStart(e, this);
|
||||||
|
this.workspace.getLayerManager()?.append(this, layers.BLOCK);
|
||||||
common.setSelected(this);
|
common.setSelected(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,14 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Workspace} from '../workspace.js';
|
|
||||||
import {Size} from '../utils/size.js';
|
|
||||||
import {Coordinate} from '../utils/coordinate.js';
|
|
||||||
import * as idGenerator from '../utils/idgenerator.js';
|
|
||||||
import * as eventUtils from '../events/utils.js';
|
|
||||||
import {CommentMove} from '../events/events_comment_move.js';
|
import {CommentMove} from '../events/events_comment_move.js';
|
||||||
import {CommentResize} from '../events/events_comment_resize.js';
|
import {CommentResize} from '../events/events_comment_resize.js';
|
||||||
|
import {EventType} from '../events/type.js';
|
||||||
|
import * as eventUtils from '../events/utils.js';
|
||||||
|
import {Coordinate} from '../utils/coordinate.js';
|
||||||
|
import * as idGenerator from '../utils/idgenerator.js';
|
||||||
|
import {Size} from '../utils/size.js';
|
||||||
|
import {Workspace} from '../workspace.js';
|
||||||
import {CommentView} from './comment_view.js';
|
import {CommentView} from './comment_view.js';
|
||||||
|
|
||||||
export class WorkspaceComment {
|
export class WorkspaceComment {
|
||||||
@@ -65,13 +66,13 @@ export class WorkspaceComment {
|
|||||||
|
|
||||||
private fireCreateEvent() {
|
private fireCreateEvent() {
|
||||||
if (eventUtils.isEnabled()) {
|
if (eventUtils.isEnabled()) {
|
||||||
eventUtils.fire(new (eventUtils.get(eventUtils.COMMENT_CREATE))(this));
|
eventUtils.fire(new (eventUtils.get(EventType.COMMENT_CREATE))(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fireDeleteEvent() {
|
private fireDeleteEvent() {
|
||||||
if (eventUtils.isEnabled()) {
|
if (eventUtils.isEnabled()) {
|
||||||
eventUtils.fire(new (eventUtils.get(eventUtils.COMMENT_DELETE))(this));
|
eventUtils.fire(new (eventUtils.get(EventType.COMMENT_DELETE))(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +80,7 @@ export class WorkspaceComment {
|
|||||||
private fireChangeEvent(oldText: string, newText: string) {
|
private fireChangeEvent(oldText: string, newText: string) {
|
||||||
if (eventUtils.isEnabled()) {
|
if (eventUtils.isEnabled()) {
|
||||||
eventUtils.fire(
|
eventUtils.fire(
|
||||||
new (eventUtils.get(eventUtils.COMMENT_CHANGE))(this, oldText, newText),
|
new (eventUtils.get(EventType.COMMENT_CHANGE))(this, oldText, newText),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,7 +89,7 @@ export class WorkspaceComment {
|
|||||||
private fireCollapseEvent(newCollapsed: boolean) {
|
private fireCollapseEvent(newCollapsed: boolean) {
|
||||||
if (eventUtils.isEnabled()) {
|
if (eventUtils.isEnabled()) {
|
||||||
eventUtils.fire(
|
eventUtils.fire(
|
||||||
new (eventUtils.get(eventUtils.COMMENT_COLLAPSE))(this, newCollapsed),
|
new (eventUtils.get(EventType.COMMENT_COLLAPSE))(this, newCollapsed),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,7 +108,7 @@ export class WorkspaceComment {
|
|||||||
|
|
||||||
/** Sets the comment's size in workspace units. */
|
/** Sets the comment's size in workspace units. */
|
||||||
setSize(size: Size) {
|
setSize(size: Size) {
|
||||||
const event = new (eventUtils.get(eventUtils.COMMENT_RESIZE))(
|
const event = new (eventUtils.get(EventType.COMMENT_RESIZE))(
|
||||||
this,
|
this,
|
||||||
) as CommentResize;
|
) as CommentResize;
|
||||||
|
|
||||||
@@ -185,7 +186,11 @@ export class WorkspaceComment {
|
|||||||
* workspace is read-only.
|
* workspace is read-only.
|
||||||
*/
|
*/
|
||||||
isDeletable(): boolean {
|
isDeletable(): boolean {
|
||||||
return this.isOwnDeletable() && !this.workspace.options.readOnly;
|
return (
|
||||||
|
this.isOwnDeletable() &&
|
||||||
|
!this.isDeadOrDying() &&
|
||||||
|
!this.workspace.options.readOnly
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -198,7 +203,7 @@ export class WorkspaceComment {
|
|||||||
|
|
||||||
/** Moves the comment to the given location in workspace coordinates. */
|
/** Moves the comment to the given location in workspace coordinates. */
|
||||||
moveTo(location: Coordinate, reason?: string[] | undefined) {
|
moveTo(location: Coordinate, reason?: string[] | undefined) {
|
||||||
const event = new (eventUtils.get(eventUtils.COMMENT_MOVE))(
|
const event = new (eventUtils.get(EventType.COMMENT_MOVE))(
|
||||||
this,
|
this,
|
||||||
) as CommentMove;
|
) as CommentMove;
|
||||||
if (reason) event.setReason(reason);
|
if (reason) event.setReason(reason);
|
||||||
|
|||||||
@@ -6,14 +6,14 @@
|
|||||||
|
|
||||||
// Former goog.module ID: Blockly.common
|
// Former goog.module ID: Blockly.common
|
||||||
|
|
||||||
/* eslint-disable-next-line no-unused-vars */
|
|
||||||
import type {Block} from './block.js';
|
import type {Block} from './block.js';
|
||||||
import {ISelectable} from './blockly.js';
|
import {ISelectable} from './blockly.js';
|
||||||
import {BlockDefinition, Blocks} from './blocks.js';
|
import {BlockDefinition, Blocks} from './blocks.js';
|
||||||
import type {Connection} from './connection.js';
|
import type {Connection} from './connection.js';
|
||||||
|
import {EventType} from './events/type.js';
|
||||||
|
import * as eventUtils from './events/utils.js';
|
||||||
import type {Workspace} from './workspace.js';
|
import type {Workspace} from './workspace.js';
|
||||||
import type {WorkspaceSvg} from './workspace_svg.js';
|
import type {WorkspaceSvg} from './workspace_svg.js';
|
||||||
import * as eventUtils from './events/utils.js';
|
|
||||||
|
|
||||||
/** Database of all workspaces. */
|
/** Database of all workspaces. */
|
||||||
const WorkspaceDB_ = Object.create(null);
|
const WorkspaceDB_ = Object.create(null);
|
||||||
@@ -108,7 +108,7 @@ export function getSelected(): ISelectable | null {
|
|||||||
export function setSelected(newSelection: ISelectable | null) {
|
export function setSelected(newSelection: ISelectable | null) {
|
||||||
if (selected === newSelection) return;
|
if (selected === newSelection) return;
|
||||||
|
|
||||||
const event = new (eventUtils.get(eventUtils.SELECTED))(
|
const event = new (eventUtils.get(EventType.SELECTED))(
|
||||||
selected?.id ?? null,
|
selected?.id ?? null,
|
||||||
newSelection?.id ?? null,
|
newSelection?.id ?? null,
|
||||||
newSelection?.workspace.id ?? selected?.workspace.id ?? '',
|
newSelection?.workspace.id ?? selected?.workspace.id ?? '',
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ class Capability<_T> {
|
|||||||
static DRAG_TARGET = new Capability<IDragTarget>('drag_target');
|
static DRAG_TARGET = new Capability<IDragTarget>('drag_target');
|
||||||
static DELETE_AREA = new Capability<IDeleteArea>('delete_area');
|
static DELETE_AREA = new Capability<IDeleteArea>('delete_area');
|
||||||
static AUTOHIDEABLE = new Capability<IAutoHideable>('autohideable');
|
static AUTOHIDEABLE = new Capability<IAutoHideable>('autohideable');
|
||||||
private readonly name_: string;
|
private readonly name: string;
|
||||||
/** @param name The name of the component capability. */
|
/** @param name The name of the component capability. */
|
||||||
constructor(name: string) {
|
constructor(name: string) {
|
||||||
this.name_ = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,7 +35,7 @@ class Capability<_T> {
|
|||||||
* @returns The name.
|
* @returns The name.
|
||||||
*/
|
*/
|
||||||
toString(): string {
|
toString(): string {
|
||||||
return this.name_;
|
return this.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,6 +224,16 @@ export class ComponentManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export namespace ComponentManager {
|
export namespace ComponentManager {
|
||||||
|
export enum ComponentWeight {
|
||||||
|
// The toolbox weight is lower (higher precedence) than the flyout, so that
|
||||||
|
// if both are under the pointer, the toolbox takes precedence even though
|
||||||
|
// the flyout's drag target area is large enough to include the toolbox.
|
||||||
|
TOOLBOX_WEIGHT = 0,
|
||||||
|
FLYOUT_WEIGHT = 1,
|
||||||
|
TRASHCAN_WEIGHT = 2,
|
||||||
|
ZOOM_CONTROLS_WEIGHT = 3,
|
||||||
|
}
|
||||||
|
|
||||||
/** An object storing component information. */
|
/** An object storing component information. */
|
||||||
export interface ComponentDatum {
|
export interface ComponentDatum {
|
||||||
component: IComponent;
|
component: IComponent;
|
||||||
@@ -232,4 +242,6 @@ export namespace ComponentManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ComponentWeight = ComponentManager.ComponentWeight;
|
||||||
|
export const ComponentWeight = ComponentManager.ComponentWeight;
|
||||||
export type ComponentDatum = ComponentManager.ComponentDatum;
|
export type ComponentDatum = ComponentManager.ComponentDatum;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
import type {Block} from './block.js';
|
import type {Block} from './block.js';
|
||||||
import {ConnectionType} from './connection_type.js';
|
import {ConnectionType} from './connection_type.js';
|
||||||
import type {BlockMove} from './events/events_block_move.js';
|
import type {BlockMove} from './events/events_block_move.js';
|
||||||
|
import {EventType} from './events/type.js';
|
||||||
import * as eventUtils from './events/utils.js';
|
import * as eventUtils from './events/utils.js';
|
||||||
import type {Input} from './inputs/input.js';
|
import type {Input} from './inputs/input.js';
|
||||||
import type {IASTNodeLocationWithBlock} from './interfaces/i_ast_node_location_with_block.js';
|
import type {IASTNodeLocationWithBlock} from './interfaces/i_ast_node_location_with_block.js';
|
||||||
@@ -114,7 +115,7 @@ export class Connection implements IASTNodeLocationWithBlock {
|
|||||||
// Connect the new connection to the parent.
|
// Connect the new connection to the parent.
|
||||||
let event;
|
let event;
|
||||||
if (eventUtils.isEnabled()) {
|
if (eventUtils.isEnabled()) {
|
||||||
event = new (eventUtils.get(eventUtils.BLOCK_MOVE))(
|
event = new (eventUtils.get(EventType.BLOCK_MOVE))(
|
||||||
childBlock,
|
childBlock,
|
||||||
) as BlockMove;
|
) as BlockMove;
|
||||||
event.setReason(['connect']);
|
event.setReason(['connect']);
|
||||||
@@ -213,11 +214,11 @@ export class Connection implements IASTNodeLocationWithBlock {
|
|||||||
* Called when an attempted connection fails. NOP by default (i.e. for
|
* Called when an attempted connection fails. NOP by default (i.e. for
|
||||||
* headless workspaces).
|
* headless workspaces).
|
||||||
*
|
*
|
||||||
* @param _otherConnection Connection that this connection failed to connect
|
* @param _superiorConnection Connection that this connection failed to connect
|
||||||
* to.
|
* to. The provided connection should be the superior connection.
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
onFailedConnect(_otherConnection: Connection) {}
|
onFailedConnect(_superiorConnection: Connection) {}
|
||||||
// NOP
|
// NOP
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -281,7 +282,7 @@ export class Connection implements IASTNodeLocationWithBlock {
|
|||||||
|
|
||||||
let event;
|
let event;
|
||||||
if (eventUtils.isEnabled()) {
|
if (eventUtils.isEnabled()) {
|
||||||
event = new (eventUtils.get(eventUtils.BLOCK_MOVE))(
|
event = new (eventUtils.get(EventType.BLOCK_MOVE))(
|
||||||
childConnection.getSourceBlock(),
|
childConnection.getSourceBlock(),
|
||||||
) as BlockMove;
|
) as BlockMove;
|
||||||
event.setReason(['disconnect']);
|
event.setReason(['disconnect']);
|
||||||
|
|||||||
@@ -9,23 +9,24 @@
|
|||||||
import type {Block} from './block.js';
|
import type {Block} from './block.js';
|
||||||
import type {BlockSvg} from './block_svg.js';
|
import type {BlockSvg} from './block_svg.js';
|
||||||
import * as browserEvents from './browser_events.js';
|
import * as browserEvents from './browser_events.js';
|
||||||
|
import * as common from './common.js';
|
||||||
import {config} from './config.js';
|
import {config} from './config.js';
|
||||||
import * as dom from './utils/dom.js';
|
|
||||||
import type {
|
import type {
|
||||||
ContextMenuOption,
|
ContextMenuOption,
|
||||||
LegacyContextMenuOption,
|
LegacyContextMenuOption,
|
||||||
} from './contextmenu_registry.js';
|
} from './contextmenu_registry.js';
|
||||||
|
import {EventType} from './events/type.js';
|
||||||
import * as eventUtils from './events/utils.js';
|
import * as eventUtils from './events/utils.js';
|
||||||
import {Menu} from './menu.js';
|
import {Menu} from './menu.js';
|
||||||
import {MenuItem} from './menuitem.js';
|
import {MenuItem} from './menuitem.js';
|
||||||
import * as aria from './utils/aria.js';
|
|
||||||
import {Rect} from './utils/rect.js';
|
|
||||||
import * as serializationBlocks from './serialization/blocks.js';
|
import * as serializationBlocks from './serialization/blocks.js';
|
||||||
|
import * as aria from './utils/aria.js';
|
||||||
|
import * as dom from './utils/dom.js';
|
||||||
|
import {Rect} from './utils/rect.js';
|
||||||
import * as svgMath from './utils/svg_math.js';
|
import * as svgMath from './utils/svg_math.js';
|
||||||
import * as WidgetDiv from './widgetdiv.js';
|
import * as WidgetDiv from './widgetdiv.js';
|
||||||
import type {WorkspaceSvg} from './workspace_svg.js';
|
import type {WorkspaceSvg} from './workspace_svg.js';
|
||||||
import * as Xml from './xml.js';
|
import * as Xml from './xml.js';
|
||||||
import * as common from './common.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Which block is the context menu attached to?
|
* Which block is the context menu attached to?
|
||||||
@@ -260,7 +261,7 @@ export function callbackFactory(
|
|||||||
eventUtils.enable();
|
eventUtils.enable();
|
||||||
}
|
}
|
||||||
if (eventUtils.isEnabled() && !newBlock.isShadow()) {
|
if (eventUtils.isEnabled() && !newBlock.isShadow()) {
|
||||||
eventUtils.fire(new (eventUtils.get(eventUtils.BLOCK_CREATE))(newBlock));
|
eventUtils.fire(new (eventUtils.get(EventType.BLOCK_CREATE))(newBlock));
|
||||||
}
|
}
|
||||||
common.setSelected(newBlock);
|
common.setSelected(newBlock);
|
||||||
return newBlock;
|
return newBlock;
|
||||||
|
|||||||
@@ -9,12 +9,13 @@
|
|||||||
import type {BlockSvg} from './block_svg.js';
|
import type {BlockSvg} from './block_svg.js';
|
||||||
import * as clipboard from './clipboard.js';
|
import * as clipboard from './clipboard.js';
|
||||||
import {RenderedWorkspaceComment} from './comments/rendered_workspace_comment.js';
|
import {RenderedWorkspaceComment} from './comments/rendered_workspace_comment.js';
|
||||||
|
import * as common from './common.js';
|
||||||
|
import {MANUALLY_DISABLED} from './constants.js';
|
||||||
import {
|
import {
|
||||||
ContextMenuRegistry,
|
ContextMenuRegistry,
|
||||||
RegistryItem,
|
RegistryItem,
|
||||||
Scope,
|
Scope,
|
||||||
} from './contextmenu_registry.js';
|
} from './contextmenu_registry.js';
|
||||||
import {MANUALLY_DISABLED} from './constants.js';
|
|
||||||
import * as dialog from './dialog.js';
|
import * as dialog from './dialog.js';
|
||||||
import * as Events from './events/events.js';
|
import * as Events from './events/events.js';
|
||||||
import * as eventUtils from './events/utils.js';
|
import * as eventUtils from './events/utils.js';
|
||||||
@@ -23,7 +24,6 @@ import {Msg} from './msg.js';
|
|||||||
import {StatementInput} from './renderers/zelos/zelos.js';
|
import {StatementInput} from './renderers/zelos/zelos.js';
|
||||||
import {Coordinate} from './utils/coordinate.js';
|
import {Coordinate} from './utils/coordinate.js';
|
||||||
import type {WorkspaceSvg} from './workspace_svg.js';
|
import type {WorkspaceSvg} from './workspace_svg.js';
|
||||||
import * as common from './common.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Option to undo previous action.
|
* Option to undo previous action.
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import type {WorkspaceSvg} from './workspace_svg.js';
|
|||||||
export class ContextMenuRegistry {
|
export class ContextMenuRegistry {
|
||||||
static registry: ContextMenuRegistry;
|
static registry: ContextMenuRegistry;
|
||||||
/** Registry of all registered RegistryItems, keyed by ID. */
|
/** Registry of all registered RegistryItems, keyed by ID. */
|
||||||
private registry_ = new Map<string, RegistryItem>();
|
private registeredItems = new Map<string, RegistryItem>();
|
||||||
|
|
||||||
/** Resets the existing singleton instance of ContextMenuRegistry. */
|
/** Resets the existing singleton instance of ContextMenuRegistry. */
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -32,7 +32,7 @@ export class ContextMenuRegistry {
|
|||||||
|
|
||||||
/** Clear and recreate the registry. */
|
/** Clear and recreate the registry. */
|
||||||
reset() {
|
reset() {
|
||||||
this.registry_.clear();
|
this.registeredItems.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,10 +42,10 @@ export class ContextMenuRegistry {
|
|||||||
* @throws {Error} if an item with the given ID already exists.
|
* @throws {Error} if an item with the given ID already exists.
|
||||||
*/
|
*/
|
||||||
register(item: RegistryItem) {
|
register(item: RegistryItem) {
|
||||||
if (this.registry_.has(item.id)) {
|
if (this.registeredItems.has(item.id)) {
|
||||||
throw Error('Menu item with ID "' + item.id + '" is already registered.');
|
throw Error('Menu item with ID "' + item.id + '" is already registered.');
|
||||||
}
|
}
|
||||||
this.registry_.set(item.id, item);
|
this.registeredItems.set(item.id, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,10 +55,10 @@ export class ContextMenuRegistry {
|
|||||||
* @throws {Error} if an item with the given ID does not exist.
|
* @throws {Error} if an item with the given ID does not exist.
|
||||||
*/
|
*/
|
||||||
unregister(id: string) {
|
unregister(id: string) {
|
||||||
if (!this.registry_.has(id)) {
|
if (!this.registeredItems.has(id)) {
|
||||||
throw new Error('Menu item with ID "' + id + '" not found.');
|
throw new Error('Menu item with ID "' + id + '" not found.');
|
||||||
}
|
}
|
||||||
this.registry_.delete(id);
|
this.registeredItems.delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,7 +66,7 @@ export class ContextMenuRegistry {
|
|||||||
* @returns RegistryItem or null if not found
|
* @returns RegistryItem or null if not found
|
||||||
*/
|
*/
|
||||||
getItem(id: string): RegistryItem | null {
|
getItem(id: string): RegistryItem | null {
|
||||||
return this.registry_.get(id) ?? null;
|
return this.registeredItems.get(id) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,7 +85,7 @@ export class ContextMenuRegistry {
|
|||||||
scope: Scope,
|
scope: Scope,
|
||||||
): ContextMenuOption[] {
|
): ContextMenuOption[] {
|
||||||
const menuOptions: ContextMenuOption[] = [];
|
const menuOptions: ContextMenuOption[] = [];
|
||||||
for (const item of this.registry_.values()) {
|
for (const item of this.registeredItems.values()) {
|
||||||
if (scopeType === item.scopeType) {
|
if (scopeType === item.scopeType) {
|
||||||
const precondition = item.preconditionFn(scope);
|
const precondition = item.preconditionFn(scope);
|
||||||
if (precondition !== 'hidden') {
|
if (precondition !== 'hidden') {
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ let content = `
|
|||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden; /* So blocks in drag surface disappear at edges */
|
overflow: hidden; /* So blocks in drag surface disappear at edges */
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.blocklyBlockCanvas.blocklyCanvasTransitioning,
|
.blocklyBlockCanvas.blocklyCanvasTransitioning,
|
||||||
@@ -214,10 +216,6 @@ let content = `
|
|||||||
stroke: none;
|
stroke: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.blocklyMultilineText {
|
|
||||||
font-family: monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.blocklyNonEditableField>text {
|
.blocklyNonEditableField>text {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,9 @@
|
|||||||
|
|
||||||
import {BlockSvg} from './block_svg.js';
|
import {BlockSvg} from './block_svg.js';
|
||||||
import {DragTarget} from './drag_target.js';
|
import {DragTarget} from './drag_target.js';
|
||||||
|
import {isDeletable} from './interfaces/i_deletable.js';
|
||||||
import type {IDeleteArea} from './interfaces/i_delete_area.js';
|
import type {IDeleteArea} from './interfaces/i_delete_area.js';
|
||||||
import type {IDraggable} from './interfaces/i_draggable.js';
|
import type {IDraggable} from './interfaces/i_draggable.js';
|
||||||
import {isDeletable} from './interfaces/i_deletable.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class for a component that can delete a block or bubble that is
|
* Abstract class for a component that can delete a block or bubble that is
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Dragger} from './dragging/dragger.js';
|
|
||||||
import {BlockDragStrategy} from './dragging/block_drag_strategy.js';
|
import {BlockDragStrategy} from './dragging/block_drag_strategy.js';
|
||||||
import {BubbleDragStrategy} from './dragging/bubble_drag_strategy.js';
|
import {BubbleDragStrategy} from './dragging/bubble_drag_strategy.js';
|
||||||
import {CommentDragStrategy} from './dragging/comment_drag_strategy.js';
|
import {CommentDragStrategy} from './dragging/comment_drag_strategy.js';
|
||||||
|
import {Dragger} from './dragging/dragger.js';
|
||||||
|
|
||||||
export {Dragger, BlockDragStrategy, BubbleDragStrategy, CommentDragStrategy};
|
export {BlockDragStrategy, BubbleDragStrategy, CommentDragStrategy, Dragger};
|
||||||
|
|||||||
@@ -4,24 +4,25 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {WorkspaceSvg} from '../workspace_svg.js';
|
|
||||||
import {IDragStrategy} from '../interfaces/i_draggable.js';
|
|
||||||
import {Coordinate} from '../utils.js';
|
|
||||||
import * as eventUtils from '../events/utils.js';
|
|
||||||
import {BlockSvg} from '../block_svg.js';
|
|
||||||
import {RenderedConnection} from '../rendered_connection.js';
|
|
||||||
import * as dom from '../utils/dom.js';
|
|
||||||
import * as blockAnimation from '../block_animations.js';
|
|
||||||
import {ConnectionType} from '../connection_type.js';
|
|
||||||
import * as bumpObjects from '../bump_objects.js';
|
|
||||||
import * as registry from '../registry.js';
|
|
||||||
import {IConnectionPreviewer} from '../interfaces/i_connection_previewer.js';
|
|
||||||
import {Connection} from '../connection.js';
|
|
||||||
import type {Block} from '../block.js';
|
import type {Block} from '../block.js';
|
||||||
|
import * as blockAnimation from '../block_animations.js';
|
||||||
|
import {BlockSvg} from '../block_svg.js';
|
||||||
|
import * as bumpObjects from '../bump_objects.js';
|
||||||
import {config} from '../config.js';
|
import {config} from '../config.js';
|
||||||
|
import {Connection} from '../connection.js';
|
||||||
|
import {ConnectionType} from '../connection_type.js';
|
||||||
import type {BlockMove} from '../events/events_block_move.js';
|
import type {BlockMove} from '../events/events_block_move.js';
|
||||||
import {finishQueuedRenders} from '../render_management.js';
|
import {EventType} from '../events/type.js';
|
||||||
|
import * as eventUtils from '../events/utils.js';
|
||||||
|
import {IConnectionPreviewer} from '../interfaces/i_connection_previewer.js';
|
||||||
|
import {IDragStrategy} from '../interfaces/i_draggable.js';
|
||||||
import * as layers from '../layers.js';
|
import * as layers from '../layers.js';
|
||||||
|
import * as registry from '../registry.js';
|
||||||
|
import {finishQueuedRenders} from '../render_management.js';
|
||||||
|
import {RenderedConnection} from '../rendered_connection.js';
|
||||||
|
import {Coordinate} from '../utils.js';
|
||||||
|
import * as dom from '../utils/dom.js';
|
||||||
|
import {WorkspaceSvg} from '../workspace_svg.js';
|
||||||
|
|
||||||
/** Represents a nearby valid connection. */
|
/** Represents a nearby valid connection. */
|
||||||
interface ConnectionCandidate {
|
interface ConnectionCandidate {
|
||||||
@@ -61,6 +62,9 @@ export class BlockDragStrategy implements IDragStrategy {
|
|||||||
*/
|
*/
|
||||||
private dragOffset = new Coordinate(0, 0);
|
private dragOffset = new Coordinate(0, 0);
|
||||||
|
|
||||||
|
/** Was there already an event group in progress when the drag started? */
|
||||||
|
private inGroup: boolean = false;
|
||||||
|
|
||||||
constructor(private block: BlockSvg) {
|
constructor(private block: BlockSvg) {
|
||||||
this.workspace = block.workspace;
|
this.workspace = block.workspace;
|
||||||
}
|
}
|
||||||
@@ -92,7 +96,8 @@ export class BlockDragStrategy implements IDragStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.dragging = true;
|
this.dragging = true;
|
||||||
if (!eventUtils.getGroup()) {
|
this.inGroup = !!eventUtils.getGroup();
|
||||||
|
if (!this.inGroup) {
|
||||||
eventUtils.setGroup(true);
|
eventUtils.setGroup(true);
|
||||||
}
|
}
|
||||||
this.fireDragStartEvent();
|
this.fireDragStartEvent();
|
||||||
@@ -173,7 +178,7 @@ export class BlockDragStrategy implements IDragStrategy {
|
|||||||
|
|
||||||
/** Fire a UI event at the start of a block drag. */
|
/** Fire a UI event at the start of a block drag. */
|
||||||
private fireDragStartEvent() {
|
private fireDragStartEvent() {
|
||||||
const event = new (eventUtils.get(eventUtils.BLOCK_DRAG))(
|
const event = new (eventUtils.get(EventType.BLOCK_DRAG))(
|
||||||
this.block,
|
this.block,
|
||||||
true,
|
true,
|
||||||
this.block.getDescendants(false),
|
this.block.getDescendants(false),
|
||||||
@@ -183,7 +188,7 @@ export class BlockDragStrategy implements IDragStrategy {
|
|||||||
|
|
||||||
/** Fire a UI event at the end of a block drag. */
|
/** Fire a UI event at the end of a block drag. */
|
||||||
private fireDragEndEvent() {
|
private fireDragEndEvent() {
|
||||||
const event = new (eventUtils.get(eventUtils.BLOCK_DRAG))(
|
const event = new (eventUtils.get(EventType.BLOCK_DRAG))(
|
||||||
this.block,
|
this.block,
|
||||||
false,
|
false,
|
||||||
this.block.getDescendants(false),
|
this.block.getDescendants(false),
|
||||||
@@ -194,7 +199,7 @@ export class BlockDragStrategy implements IDragStrategy {
|
|||||||
/** Fire a move event at the end of a block drag. */
|
/** Fire a move event at the end of a block drag. */
|
||||||
private fireMoveEvent() {
|
private fireMoveEvent() {
|
||||||
if (this.block.isDeadOrDying()) return;
|
if (this.block.isDeadOrDying()) return;
|
||||||
const event = new (eventUtils.get(eventUtils.BLOCK_MOVE))(
|
const event = new (eventUtils.get(EventType.BLOCK_MOVE))(
|
||||||
this.block,
|
this.block,
|
||||||
) as BlockMove;
|
) as BlockMove;
|
||||||
event.setReason(['drag']);
|
event.setReason(['drag']);
|
||||||
@@ -379,17 +384,24 @@ export class BlockDragStrategy implements IDragStrategy {
|
|||||||
if (this.connectionCandidate) {
|
if (this.connectionCandidate) {
|
||||||
// Applying connections also rerenders the relevant blocks.
|
// Applying connections also rerenders the relevant blocks.
|
||||||
this.applyConnections(this.connectionCandidate);
|
this.applyConnections(this.connectionCandidate);
|
||||||
|
this.disposeStep();
|
||||||
} else {
|
} else {
|
||||||
this.block.queueRender();
|
this.block.queueRender().then(() => this.disposeStep());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.inGroup) {
|
||||||
|
eventUtils.setGroup(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Disposes of any state at the end of the drag. */
|
||||||
|
private disposeStep() {
|
||||||
this.block.snapToGrid();
|
this.block.snapToGrid();
|
||||||
|
|
||||||
// Must dispose after connections are applied to not break the dynamic
|
// Must dispose after connections are applied to not break the dynamic
|
||||||
// connections plugin. See #7859
|
// connections plugin. See #7859
|
||||||
this.connectionPreviewer!.dispose();
|
this.connectionPreviewer!.dispose();
|
||||||
this.workspace.setResizesEnabled(true);
|
this.workspace.setResizesEnabled(true);
|
||||||
|
|
||||||
eventUtils.setGroup(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Connects the given candidate connections. */
|
/** Connects the given candidate connections. */
|
||||||
|
|||||||
@@ -4,15 +4,18 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {IDragStrategy} from '../interfaces/i_draggable.js';
|
|
||||||
import {Coordinate} from '../utils.js';
|
|
||||||
import * as eventUtils from '../events/utils.js';
|
|
||||||
import {IBubble, WorkspaceSvg} from '../blockly.js';
|
import {IBubble, WorkspaceSvg} from '../blockly.js';
|
||||||
|
import * as eventUtils from '../events/utils.js';
|
||||||
|
import {IDragStrategy} from '../interfaces/i_draggable.js';
|
||||||
import * as layers from '../layers.js';
|
import * as layers from '../layers.js';
|
||||||
|
import {Coordinate} from '../utils.js';
|
||||||
|
|
||||||
export class BubbleDragStrategy implements IDragStrategy {
|
export class BubbleDragStrategy implements IDragStrategy {
|
||||||
private startLoc: Coordinate | null = null;
|
private startLoc: Coordinate | null = null;
|
||||||
|
|
||||||
|
/** Was there already an event group in progress when the drag started? */
|
||||||
|
private inGroup: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private bubble: IBubble,
|
private bubble: IBubble,
|
||||||
private workspace: WorkspaceSvg,
|
private workspace: WorkspaceSvg,
|
||||||
@@ -23,13 +26,16 @@ export class BubbleDragStrategy implements IDragStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
startDrag(): void {
|
startDrag(): void {
|
||||||
if (!eventUtils.getGroup()) {
|
this.inGroup = !!eventUtils.getGroup();
|
||||||
|
if (!this.inGroup) {
|
||||||
eventUtils.setGroup(true);
|
eventUtils.setGroup(true);
|
||||||
}
|
}
|
||||||
this.startLoc = this.bubble.getRelativeToSurfaceXY();
|
this.startLoc = this.bubble.getRelativeToSurfaceXY();
|
||||||
this.workspace.setResizesEnabled(false);
|
this.workspace.setResizesEnabled(false);
|
||||||
this.workspace.getLayerManager()?.moveToDragLayer(this.bubble);
|
this.workspace.getLayerManager()?.moveToDragLayer(this.bubble);
|
||||||
this.bubble.setDragging && this.bubble.setDragging(true);
|
if (this.bubble.setDragging) {
|
||||||
|
this.bubble.setDragging(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drag(newLoc: Coordinate): void {
|
drag(newLoc: Coordinate): void {
|
||||||
@@ -38,7 +44,9 @@ export class BubbleDragStrategy implements IDragStrategy {
|
|||||||
|
|
||||||
endDrag(): void {
|
endDrag(): void {
|
||||||
this.workspace.setResizesEnabled(true);
|
this.workspace.setResizesEnabled(true);
|
||||||
eventUtils.setGroup(false);
|
if (!this.inGroup) {
|
||||||
|
eventUtils.setGroup(false);
|
||||||
|
}
|
||||||
|
|
||||||
this.workspace
|
this.workspace
|
||||||
.getLayerManager()
|
.getLayerManager()
|
||||||
|
|||||||
@@ -4,29 +4,38 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {IDragStrategy} from '../interfaces/i_draggable.js';
|
|
||||||
import {Coordinate} from '../utils.js';
|
|
||||||
import * as eventUtils from '../events/utils.js';
|
|
||||||
import * as layers from '../layers.js';
|
|
||||||
import {RenderedWorkspaceComment} from '../comments.js';
|
import {RenderedWorkspaceComment} from '../comments.js';
|
||||||
import {WorkspaceSvg} from '../workspace_svg.js';
|
|
||||||
import {CommentMove} from '../events/events_comment_move.js';
|
import {CommentMove} from '../events/events_comment_move.js';
|
||||||
|
import {EventType} from '../events/type.js';
|
||||||
|
import * as eventUtils from '../events/utils.js';
|
||||||
|
import {IDragStrategy} from '../interfaces/i_draggable.js';
|
||||||
|
import * as layers from '../layers.js';
|
||||||
|
import {Coordinate} from '../utils.js';
|
||||||
|
import {WorkspaceSvg} from '../workspace_svg.js';
|
||||||
|
|
||||||
export class CommentDragStrategy implements IDragStrategy {
|
export class CommentDragStrategy implements IDragStrategy {
|
||||||
private startLoc: Coordinate | null = null;
|
private startLoc: Coordinate | null = null;
|
||||||
|
|
||||||
private workspace: WorkspaceSvg;
|
private workspace: WorkspaceSvg;
|
||||||
|
|
||||||
|
/** Was there already an event group in progress when the drag started? */
|
||||||
|
private inGroup: boolean = false;
|
||||||
|
|
||||||
constructor(private comment: RenderedWorkspaceComment) {
|
constructor(private comment: RenderedWorkspaceComment) {
|
||||||
this.workspace = comment.workspace;
|
this.workspace = comment.workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
isMovable(): boolean {
|
isMovable(): boolean {
|
||||||
return this.comment.isOwnMovable() && !this.workspace.options.readOnly;
|
return (
|
||||||
|
this.comment.isOwnMovable() &&
|
||||||
|
!this.comment.isDeadOrDying() &&
|
||||||
|
!this.workspace.options.readOnly
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
startDrag(): void {
|
startDrag(): void {
|
||||||
if (!eventUtils.getGroup()) {
|
this.inGroup = !!eventUtils.getGroup();
|
||||||
|
if (!this.inGroup) {
|
||||||
eventUtils.setGroup(true);
|
eventUtils.setGroup(true);
|
||||||
}
|
}
|
||||||
this.fireDragStartEvent();
|
this.fireDragStartEvent();
|
||||||
@@ -52,12 +61,14 @@ export class CommentDragStrategy implements IDragStrategy {
|
|||||||
this.comment.snapToGrid();
|
this.comment.snapToGrid();
|
||||||
|
|
||||||
this.workspace.setResizesEnabled(true);
|
this.workspace.setResizesEnabled(true);
|
||||||
eventUtils.setGroup(false);
|
if (!this.inGroup) {
|
||||||
|
eventUtils.setGroup(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Fire a UI event at the start of a comment drag. */
|
/** Fire a UI event at the start of a comment drag. */
|
||||||
private fireDragStartEvent() {
|
private fireDragStartEvent() {
|
||||||
const event = new (eventUtils.get(eventUtils.COMMENT_DRAG))(
|
const event = new (eventUtils.get(EventType.COMMENT_DRAG))(
|
||||||
this.comment,
|
this.comment,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
@@ -66,7 +77,7 @@ export class CommentDragStrategy implements IDragStrategy {
|
|||||||
|
|
||||||
/** Fire a UI event at the end of a comment drag. */
|
/** Fire a UI event at the end of a comment drag. */
|
||||||
private fireDragEndEvent() {
|
private fireDragEndEvent() {
|
||||||
const event = new (eventUtils.get(eventUtils.COMMENT_DRAG))(
|
const event = new (eventUtils.get(EventType.COMMENT_DRAG))(
|
||||||
this.comment,
|
this.comment,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
@@ -76,7 +87,7 @@ export class CommentDragStrategy implements IDragStrategy {
|
|||||||
/** Fire a move event at the end of a comment drag. */
|
/** Fire a move event at the end of a comment drag. */
|
||||||
private fireMoveEvent() {
|
private fireMoveEvent() {
|
||||||
if (this.comment.isDeadOrDying()) return;
|
if (this.comment.isDeadOrDying()) return;
|
||||||
const event = new (eventUtils.get(eventUtils.COMMENT_MOVE))(
|
const event = new (eventUtils.get(EventType.COMMENT_MOVE))(
|
||||||
this.comment,
|
this.comment,
|
||||||
) as CommentMove;
|
) as CommentMove;
|
||||||
event.setReason(['drag']);
|
event.setReason(['drag']);
|
||||||
|
|||||||
@@ -4,18 +4,18 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {IDragTarget} from '../interfaces/i_drag_target.js';
|
|
||||||
import {IDeletable, isDeletable} from '../interfaces/i_deletable.js';
|
|
||||||
import {IDragger} from '../interfaces/i_dragger.js';
|
|
||||||
import {IDraggable} from '../interfaces/i_draggable.js';
|
|
||||||
import {Coordinate} from '../utils/coordinate.js';
|
|
||||||
import {WorkspaceSvg} from '../workspace_svg.js';
|
|
||||||
import {ComponentManager} from '../component_manager.js';
|
|
||||||
import {IDeleteArea} from '../interfaces/i_delete_area.js';
|
|
||||||
import * as registry from '../registry.js';
|
|
||||||
import * as eventUtils from '../events/utils.js';
|
|
||||||
import * as blockAnimations from '../block_animations.js';
|
import * as blockAnimations from '../block_animations.js';
|
||||||
import {BlockSvg} from '../block_svg.js';
|
import {BlockSvg} from '../block_svg.js';
|
||||||
|
import {ComponentManager} from '../component_manager.js';
|
||||||
|
import * as eventUtils from '../events/utils.js';
|
||||||
|
import {IDeletable, isDeletable} from '../interfaces/i_deletable.js';
|
||||||
|
import {IDeleteArea} from '../interfaces/i_delete_area.js';
|
||||||
|
import {IDragTarget} from '../interfaces/i_drag_target.js';
|
||||||
|
import {IDraggable} from '../interfaces/i_draggable.js';
|
||||||
|
import {IDragger} from '../interfaces/i_dragger.js';
|
||||||
|
import * as registry from '../registry.js';
|
||||||
|
import {Coordinate} from '../utils/coordinate.js';
|
||||||
|
import {WorkspaceSvg} from '../workspace_svg.js';
|
||||||
|
|
||||||
export class Dragger implements IDragger {
|
export class Dragger implements IDragger {
|
||||||
protected startLoc: Coordinate;
|
protected startLoc: Coordinate;
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
|
|
||||||
import type {BlockSvg} from './block_svg.js';
|
import type {BlockSvg} from './block_svg.js';
|
||||||
import * as common from './common.js';
|
import * as common from './common.js';
|
||||||
import * as dom from './utils/dom.js';
|
|
||||||
import type {Field} from './field.js';
|
import type {Field} from './field.js';
|
||||||
|
import * as dom from './utils/dom.js';
|
||||||
import * as math from './utils/math.js';
|
import * as math from './utils/math.js';
|
||||||
import {Rect} from './utils/rect.js';
|
import {Rect} from './utils/rect.js';
|
||||||
import type {Size} from './utils/size.js';
|
import type {Size} from './utils/size.js';
|
||||||
@@ -53,7 +53,7 @@ export const ANIMATION_TIME = 0.25;
|
|||||||
let animateOutTimer: ReturnType<typeof setTimeout> | null = null;
|
let animateOutTimer: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|
||||||
/** Callback for when the drop-down is hidden. */
|
/** Callback for when the drop-down is hidden. */
|
||||||
let onHide: Function | null = null;
|
let onHide: (() => void) | null = null;
|
||||||
|
|
||||||
/** A class name representing the current owner's workspace renderer. */
|
/** A class name representing the current owner's workspace renderer. */
|
||||||
let renderedClassName = '';
|
let renderedClassName = '';
|
||||||
@@ -196,7 +196,7 @@ export function setColour(backgroundColour: string, borderColour: string) {
|
|||||||
export function showPositionedByBlock<T>(
|
export function showPositionedByBlock<T>(
|
||||||
field: Field<T>,
|
field: Field<T>,
|
||||||
block: BlockSvg,
|
block: BlockSvg,
|
||||||
opt_onHide?: Function,
|
opt_onHide?: () => void,
|
||||||
opt_secondaryYOffset?: number,
|
opt_secondaryYOffset?: number,
|
||||||
): boolean {
|
): boolean {
|
||||||
return showPositionedByRect(
|
return showPositionedByRect(
|
||||||
@@ -220,7 +220,7 @@ export function showPositionedByBlock<T>(
|
|||||||
*/
|
*/
|
||||||
export function showPositionedByField<T>(
|
export function showPositionedByField<T>(
|
||||||
field: Field<T>,
|
field: Field<T>,
|
||||||
opt_onHide?: Function,
|
opt_onHide?: () => void,
|
||||||
opt_secondaryYOffset?: number,
|
opt_secondaryYOffset?: number,
|
||||||
): boolean {
|
): boolean {
|
||||||
positionToField = true;
|
positionToField = true;
|
||||||
@@ -272,7 +272,7 @@ function getScaledBboxOfField(field: Field): Rect {
|
|||||||
function showPositionedByRect(
|
function showPositionedByRect(
|
||||||
bBox: Rect,
|
bBox: Rect,
|
||||||
field: Field,
|
field: Field,
|
||||||
opt_onHide?: Function,
|
opt_onHide?: () => void,
|
||||||
opt_secondaryYOffset?: number,
|
opt_secondaryYOffset?: number,
|
||||||
): boolean {
|
): boolean {
|
||||||
// If we can fit it, render below the block.
|
// If we can fit it, render below the block.
|
||||||
@@ -328,7 +328,7 @@ export function show<T>(
|
|||||||
primaryY: number,
|
primaryY: number,
|
||||||
secondaryX: number,
|
secondaryX: number,
|
||||||
secondaryY: number,
|
secondaryY: number,
|
||||||
opt_onHide?: Function,
|
opt_onHide?: () => void,
|
||||||
): boolean {
|
): boolean {
|
||||||
owner = newOwner as Field;
|
owner = newOwner as Field;
|
||||||
onHide = opt_onHide || null;
|
onHide = opt_onHide || null;
|
||||||
|
|||||||
@@ -6,158 +6,105 @@
|
|||||||
|
|
||||||
// Former goog.module ID: Blockly.Events
|
// Former goog.module ID: Blockly.Events
|
||||||
|
|
||||||
import {Abstract, AbstractEventJson} from './events_abstract.js';
|
import {EventType} from './type.js';
|
||||||
import {BlockBase, BlockBaseJson} from './events_block_base.js';
|
|
||||||
import {BlockChange, BlockChangeJson} from './events_block_change.js';
|
// Events.
|
||||||
import {BlockCreate, BlockCreateJson} from './events_block_create.js';
|
export {Abstract, AbstractEventJson} from './events_abstract.js';
|
||||||
import {BlockDelete, BlockDeleteJson} from './events_block_delete.js';
|
export {BlockBase, BlockBaseJson} from './events_block_base.js';
|
||||||
import {BlockDrag, BlockDragJson} from './events_block_drag.js';
|
export {BlockChange, BlockChangeJson} from './events_block_change.js';
|
||||||
import {
|
export {BlockCreate, BlockCreateJson} from './events_block_create.js';
|
||||||
|
export {BlockDelete, BlockDeleteJson} from './events_block_delete.js';
|
||||||
|
export {BlockDrag, BlockDragJson} from './events_block_drag.js';
|
||||||
|
export {
|
||||||
BlockFieldIntermediateChange,
|
BlockFieldIntermediateChange,
|
||||||
BlockFieldIntermediateChangeJson,
|
BlockFieldIntermediateChangeJson,
|
||||||
} from './events_block_field_intermediate_change.js';
|
} from './events_block_field_intermediate_change.js';
|
||||||
import {BlockMove, BlockMoveJson} from './events_block_move.js';
|
export {BlockMove, BlockMoveJson} from './events_block_move.js';
|
||||||
import {BubbleOpen, BubbleOpenJson, BubbleType} from './events_bubble_open.js';
|
export {BubbleOpen, BubbleOpenJson, BubbleType} from './events_bubble_open.js';
|
||||||
import {Click, ClickJson, ClickTarget} from './events_click.js';
|
export {Click, ClickJson, ClickTarget} from './events_click.js';
|
||||||
import {CommentBase, CommentBaseJson} from './events_comment_base.js';
|
export {CommentBase, CommentBaseJson} from './events_comment_base.js';
|
||||||
import {CommentChange, CommentChangeJson} from './events_comment_change.js';
|
export {CommentChange, CommentChangeJson} from './events_comment_change.js';
|
||||||
import {CommentCreate, CommentCreateJson} from './events_comment_create.js';
|
export {
|
||||||
import {CommentDelete} from './events_comment_delete.js';
|
|
||||||
import {CommentMove, CommentMoveJson} from './events_comment_move.js';
|
|
||||||
import {CommentResize, CommentResizeJson} from './events_comment_resize.js';
|
|
||||||
import {CommentDrag, CommentDragJson} from './events_comment_drag.js';
|
|
||||||
import {
|
|
||||||
CommentCollapse,
|
CommentCollapse,
|
||||||
CommentCollapseJson,
|
CommentCollapseJson,
|
||||||
} from './events_comment_collapse.js';
|
} from './events_comment_collapse.js';
|
||||||
import {MarkerMove, MarkerMoveJson} from './events_marker_move.js';
|
export {CommentCreate, CommentCreateJson} from './events_comment_create.js';
|
||||||
import {Selected, SelectedJson} from './events_selected.js';
|
export {CommentDelete} from './events_comment_delete.js';
|
||||||
import {ThemeChange, ThemeChangeJson} from './events_theme_change.js';
|
export {CommentDrag, CommentDragJson} from './events_comment_drag.js';
|
||||||
import {
|
export {CommentMove, CommentMoveJson} from './events_comment_move.js';
|
||||||
|
export {CommentResize, CommentResizeJson} from './events_comment_resize.js';
|
||||||
|
export {MarkerMove, MarkerMoveJson} from './events_marker_move.js';
|
||||||
|
export {Selected, SelectedJson} from './events_selected.js';
|
||||||
|
export {ThemeChange, ThemeChangeJson} from './events_theme_change.js';
|
||||||
|
export {
|
||||||
ToolboxItemSelect,
|
ToolboxItemSelect,
|
||||||
ToolboxItemSelectJson,
|
ToolboxItemSelectJson,
|
||||||
} from './events_toolbox_item_select.js';
|
} from './events_toolbox_item_select.js';
|
||||||
import {TrashcanOpen, TrashcanOpenJson} from './events_trashcan_open.js';
|
|
||||||
import {UiBase} from './events_ui_base.js';
|
|
||||||
import {VarBase, VarBaseJson} from './events_var_base.js';
|
|
||||||
import {VarCreate, VarCreateJson} from './events_var_create.js';
|
|
||||||
import {VarDelete, VarDeleteJson} from './events_var_delete.js';
|
|
||||||
import {VarRename, VarRenameJson} from './events_var_rename.js';
|
|
||||||
import {VarTypeChange, VarTypeChangeJson} from './events_var_type_change.js';
|
|
||||||
import {ViewportChange, ViewportChangeJson} from './events_viewport.js';
|
|
||||||
import * as eventUtils from './utils.js';
|
|
||||||
import {FinishedLoading} from './workspace_events.js';
|
|
||||||
|
|
||||||
// Events.
|
// Events.
|
||||||
export {Abstract};
|
export {TrashcanOpen, TrashcanOpenJson} from './events_trashcan_open.js';
|
||||||
export {AbstractEventJson};
|
export {UiBase} from './events_ui_base.js';
|
||||||
export {BubbleOpen};
|
export {VarBase, VarBaseJson} from './events_var_base.js';
|
||||||
export {BubbleOpenJson};
|
export {VarCreate, VarCreateJson} from './events_var_create.js';
|
||||||
export {BubbleType};
|
export {VarDelete, VarDeleteJson} from './events_var_delete.js';
|
||||||
export {BlockBase};
|
export {VarRename, VarRenameJson} from './events_var_rename.js';
|
||||||
export {BlockBaseJson};
|
export {ViewportChange, ViewportChangeJson} from './events_viewport.js';
|
||||||
export {BlockChange};
|
export {FinishedLoading} from './workspace_events.js';
|
||||||
export {BlockChangeJson};
|
|
||||||
export {BlockCreate};
|
export type {BumpEvent} from './utils.js';
|
||||||
export {BlockCreateJson};
|
|
||||||
export {BlockDelete};
|
|
||||||
export {BlockDeleteJson};
|
|
||||||
export {BlockDrag};
|
|
||||||
export {BlockDragJson};
|
|
||||||
export {BlockFieldIntermediateChange};
|
|
||||||
export {BlockFieldIntermediateChangeJson};
|
|
||||||
export {BlockMove};
|
|
||||||
export {BlockMoveJson};
|
|
||||||
export {Click};
|
|
||||||
export {ClickJson};
|
|
||||||
export {ClickTarget};
|
|
||||||
export {CommentBase};
|
|
||||||
export {CommentBaseJson};
|
|
||||||
export {CommentChange};
|
|
||||||
export {CommentChangeJson};
|
|
||||||
export {CommentCreate};
|
|
||||||
export {CommentCreateJson};
|
|
||||||
export {CommentDelete};
|
|
||||||
export {CommentMove};
|
|
||||||
export {CommentMoveJson};
|
|
||||||
export {CommentResize};
|
|
||||||
export {CommentResizeJson};
|
|
||||||
export {CommentDrag};
|
|
||||||
export {CommentDragJson};
|
|
||||||
export {CommentCollapse};
|
|
||||||
export {CommentCollapseJson};
|
|
||||||
export {FinishedLoading};
|
|
||||||
export {MarkerMove};
|
|
||||||
export {MarkerMoveJson};
|
|
||||||
export {Selected};
|
|
||||||
export {SelectedJson};
|
|
||||||
export {ThemeChange};
|
|
||||||
export {ThemeChangeJson};
|
|
||||||
export {ToolboxItemSelect};
|
|
||||||
export {ToolboxItemSelectJson};
|
|
||||||
export {TrashcanOpen};
|
|
||||||
export {TrashcanOpenJson};
|
|
||||||
export {UiBase};
|
|
||||||
export {VarBase};
|
|
||||||
export {VarBaseJson};
|
|
||||||
export {VarCreate};
|
|
||||||
export {VarCreateJson};
|
|
||||||
export {VarDelete};
|
|
||||||
export {VarDeleteJson};
|
|
||||||
export {VarRename};
|
|
||||||
export {VarRenameJson};
|
|
||||||
export {VarTypeChange};
|
|
||||||
export {VarTypeChangeJson};
|
|
||||||
export {ViewportChange};
|
|
||||||
export {ViewportChangeJson};
|
|
||||||
|
|
||||||
// Event types.
|
// Event types.
|
||||||
export const BLOCK_CHANGE = eventUtils.BLOCK_CHANGE;
|
export const BLOCK_CHANGE = EventType.BLOCK_CHANGE;
|
||||||
export const BLOCK_CREATE = eventUtils.BLOCK_CREATE;
|
export const BLOCK_CREATE = EventType.BLOCK_CREATE;
|
||||||
export const BLOCK_DELETE = eventUtils.BLOCK_DELETE;
|
export const BLOCK_DELETE = EventType.BLOCK_DELETE;
|
||||||
export const BLOCK_DRAG = eventUtils.BLOCK_DRAG;
|
export const BLOCK_DRAG = EventType.BLOCK_DRAG;
|
||||||
export const BLOCK_MOVE = eventUtils.BLOCK_MOVE;
|
export const BLOCK_MOVE = EventType.BLOCK_MOVE;
|
||||||
export const BLOCK_FIELD_INTERMEDIATE_CHANGE =
|
export const BLOCK_FIELD_INTERMEDIATE_CHANGE =
|
||||||
eventUtils.BLOCK_FIELD_INTERMEDIATE_CHANGE;
|
EventType.BLOCK_FIELD_INTERMEDIATE_CHANGE;
|
||||||
export const BUBBLE_OPEN = eventUtils.BUBBLE_OPEN;
|
export const BUBBLE_OPEN = EventType.BUBBLE_OPEN;
|
||||||
export type BumpEvent = eventUtils.BumpEvent;
|
/** @deprecated Use BLOCK_CHANGE instead */
|
||||||
export const BUMP_EVENTS = eventUtils.BUMP_EVENTS;
|
export const CHANGE = EventType.BLOCK_CHANGE;
|
||||||
export const CHANGE = eventUtils.CHANGE;
|
export const CLICK = EventType.CLICK;
|
||||||
export const CLICK = eventUtils.CLICK;
|
export const COMMENT_CHANGE = EventType.COMMENT_CHANGE;
|
||||||
export const COMMENT_CHANGE = eventUtils.COMMENT_CHANGE;
|
export const COMMENT_CREATE = EventType.COMMENT_CREATE;
|
||||||
export const COMMENT_CREATE = eventUtils.COMMENT_CREATE;
|
export const COMMENT_DELETE = EventType.COMMENT_DELETE;
|
||||||
export const COMMENT_DELETE = eventUtils.COMMENT_DELETE;
|
export const COMMENT_MOVE = EventType.COMMENT_MOVE;
|
||||||
export const COMMENT_MOVE = eventUtils.COMMENT_MOVE;
|
export const COMMENT_RESIZE = EventType.COMMENT_RESIZE;
|
||||||
export const COMMENT_RESIZE = eventUtils.COMMENT_RESIZE;
|
export const COMMENT_DRAG = EventType.COMMENT_DRAG;
|
||||||
export const COMMENT_DRAG = eventUtils.COMMENT_DRAG;
|
/** @deprecated Use BLOCK_CREATE instead */
|
||||||
export const CREATE = eventUtils.CREATE;
|
export const CREATE = EventType.BLOCK_CREATE;
|
||||||
export const DELETE = eventUtils.DELETE;
|
/** @deprecated Use BLOCK_DELETE instead */
|
||||||
export const FINISHED_LOADING = eventUtils.FINISHED_LOADING;
|
export const DELETE = EventType.BLOCK_DELETE;
|
||||||
export const MARKER_MOVE = eventUtils.MARKER_MOVE;
|
export const FINISHED_LOADING = EventType.FINISHED_LOADING;
|
||||||
export const MOVE = eventUtils.MOVE;
|
export const MARKER_MOVE = EventType.MARKER_MOVE;
|
||||||
export const SELECTED = eventUtils.SELECTED;
|
/** @deprecated Use BLOCK_MOVE instead */
|
||||||
export const THEME_CHANGE = eventUtils.THEME_CHANGE;
|
export const MOVE = EventType.BLOCK_MOVE;
|
||||||
export const TOOLBOX_ITEM_SELECT = eventUtils.TOOLBOX_ITEM_SELECT;
|
export const SELECTED = EventType.SELECTED;
|
||||||
export const TRASHCAN_OPEN = eventUtils.TRASHCAN_OPEN;
|
export const THEME_CHANGE = EventType.THEME_CHANGE;
|
||||||
export const UI = eventUtils.UI;
|
export const TOOLBOX_ITEM_SELECT = EventType.TOOLBOX_ITEM_SELECT;
|
||||||
export const VAR_CREATE = eventUtils.VAR_CREATE;
|
export const TRASHCAN_OPEN = EventType.TRASHCAN_OPEN;
|
||||||
export const VAR_DELETE = eventUtils.VAR_DELETE;
|
export const UI = EventType.UI;
|
||||||
export const VAR_RENAME = eventUtils.VAR_RENAME;
|
export const VAR_CREATE = EventType.VAR_CREATE;
|
||||||
export const VAR_TYPE_CHAGE = eventUtils.VAR_TYPE_CHANGE;
|
export const VAR_DELETE = EventType.VAR_DELETE;
|
||||||
export const VIEWPORT_CHANGE = eventUtils.VIEWPORT_CHANGE;
|
export const VAR_RENAME = EventType.VAR_RENAME;
|
||||||
|
export const VIEWPORT_CHANGE = EventType.VIEWPORT_CHANGE;
|
||||||
|
|
||||||
|
export {BUMP_EVENTS} from './type.js';
|
||||||
|
|
||||||
// Event utils.
|
// Event utils.
|
||||||
export const clearPendingUndo = eventUtils.clearPendingUndo;
|
export {
|
||||||
export const disable = eventUtils.disable;
|
clearPendingUndo,
|
||||||
export const enable = eventUtils.enable;
|
disable,
|
||||||
export const filter = eventUtils.filter;
|
disableOrphans,
|
||||||
export const fire = eventUtils.fire;
|
enable,
|
||||||
export const fromJson = eventUtils.fromJson;
|
filter,
|
||||||
export const getDescendantIds = eventUtils.getDescendantIds;
|
fire,
|
||||||
export const get = eventUtils.get;
|
fromJson,
|
||||||
export const getGroup = eventUtils.getGroup;
|
get,
|
||||||
export const getRecordUndo = eventUtils.getRecordUndo;
|
getDescendantIds,
|
||||||
export const isEnabled = eventUtils.isEnabled;
|
getGroup,
|
||||||
export const setGroup = eventUtils.setGroup;
|
getRecordUndo,
|
||||||
export const setRecordUndo = eventUtils.setRecordUndo;
|
isEnabled,
|
||||||
export const disableOrphans = eventUtils.disableOrphans;
|
setGroup,
|
||||||
|
setRecordUndo,
|
||||||
|
} from './utils.js';
|
||||||
|
|||||||
@@ -14,8 +14,7 @@
|
|||||||
|
|
||||||
import * as common from '../common.js';
|
import * as common from '../common.js';
|
||||||
import type {Workspace} from '../workspace.js';
|
import type {Workspace} from '../workspace.js';
|
||||||
|
import {getGroup, getRecordUndo} from './utils.js';
|
||||||
import * as eventUtils from './utils.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class for an event.
|
* Abstract class for an event.
|
||||||
@@ -48,8 +47,8 @@ export abstract class Abstract {
|
|||||||
type = '';
|
type = '';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.group = eventUtils.getGroup();
|
this.group = getGroup();
|
||||||
this.recordUndo = eventUtils.getRecordUndo();
|
this.recordUndo = getRecordUndo();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
|
|
||||||
import type {Block} from '../block.js';
|
import type {Block} from '../block.js';
|
||||||
import type {Workspace} from '../workspace.js';
|
import type {Workspace} from '../workspace.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Abstract as AbstractEvent,
|
Abstract as AbstractEvent,
|
||||||
AbstractEventJson,
|
AbstractEventJson,
|
||||||
|
|||||||
@@ -13,15 +13,15 @@
|
|||||||
|
|
||||||
import type {Block} from '../block.js';
|
import type {Block} from '../block.js';
|
||||||
import type {BlockSvg} from '../block_svg.js';
|
import type {BlockSvg} from '../block_svg.js';
|
||||||
|
import {MANUALLY_DISABLED} from '../constants.js';
|
||||||
import {IconType} from '../icons/icon_types.js';
|
import {IconType} from '../icons/icon_types.js';
|
||||||
import {hasBubble} from '../interfaces/i_has_bubble.js';
|
import {hasBubble} from '../interfaces/i_has_bubble.js';
|
||||||
import {MANUALLY_DISABLED} from '../constants.js';
|
|
||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
import * as utilsXml from '../utils/xml.js';
|
import * as utilsXml from '../utils/xml.js';
|
||||||
import {Workspace} from '../workspace.js';
|
import {Workspace} from '../workspace.js';
|
||||||
import * as Xml from '../xml.js';
|
import * as Xml from '../xml.js';
|
||||||
|
|
||||||
import {BlockBase, BlockBaseJson} from './events_block_base.js';
|
import {BlockBase, BlockBaseJson} from './events_block_base.js';
|
||||||
|
import {EventType} from './type.js';
|
||||||
import * as eventUtils from './utils.js';
|
import * as eventUtils from './utils.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,7 +29,7 @@ import * as eventUtils from './utils.js';
|
|||||||
* field values, comments, etc).
|
* field values, comments, etc).
|
||||||
*/
|
*/
|
||||||
export class BlockChange extends BlockBase {
|
export class BlockChange extends BlockBase {
|
||||||
override type = eventUtils.BLOCK_CHANGE;
|
override type = EventType.BLOCK_CHANGE;
|
||||||
/**
|
/**
|
||||||
* The element that changed; one of 'field', 'comment', 'collapsed',
|
* The element that changed; one of 'field', 'comment', 'collapsed',
|
||||||
* 'disabled', 'inline', or 'mutation'
|
* 'disabled', 'inline', or 'mutation'
|
||||||
@@ -256,4 +256,4 @@ export interface BlockChangeJson extends BlockBaseJson {
|
|||||||
disabledReason?: string;
|
disabledReason?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(registry.Type.EVENT, eventUtils.CHANGE, BlockChange);
|
registry.register(registry.Type.EVENT, EventType.BLOCK_CHANGE, BlockChange);
|
||||||
|
|||||||
@@ -15,18 +15,18 @@ import type {Block} from '../block.js';
|
|||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
import * as blocks from '../serialization/blocks.js';
|
import * as blocks from '../serialization/blocks.js';
|
||||||
import * as utilsXml from '../utils/xml.js';
|
import * as utilsXml from '../utils/xml.js';
|
||||||
import * as Xml from '../xml.js';
|
|
||||||
|
|
||||||
import {BlockBase, BlockBaseJson} from './events_block_base.js';
|
|
||||||
import * as eventUtils from './utils.js';
|
|
||||||
import {Workspace} from '../workspace.js';
|
import {Workspace} from '../workspace.js';
|
||||||
|
import * as Xml from '../xml.js';
|
||||||
|
import {BlockBase, BlockBaseJson} from './events_block_base.js';
|
||||||
|
import {EventType} from './type.js';
|
||||||
|
import * as eventUtils from './utils.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners when a block (or connected stack of blocks) is
|
* Notifies listeners when a block (or connected stack of blocks) is
|
||||||
* created.
|
* created.
|
||||||
*/
|
*/
|
||||||
export class BlockCreate extends BlockBase {
|
export class BlockCreate extends BlockBase {
|
||||||
override type = eventUtils.BLOCK_CREATE;
|
override type = EventType.BLOCK_CREATE;
|
||||||
|
|
||||||
/** The XML representation of the created block(s). */
|
/** The XML representation of the created block(s). */
|
||||||
xml?: Element | DocumentFragment;
|
xml?: Element | DocumentFragment;
|
||||||
@@ -182,4 +182,4 @@ export interface BlockCreateJson extends BlockBaseJson {
|
|||||||
recordUndo?: boolean;
|
recordUndo?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(registry.Type.EVENT, eventUtils.CREATE, BlockCreate);
|
registry.register(registry.Type.EVENT, EventType.BLOCK_CREATE, BlockCreate);
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ import type {Block} from '../block.js';
|
|||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
import * as blocks from '../serialization/blocks.js';
|
import * as blocks from '../serialization/blocks.js';
|
||||||
import * as utilsXml from '../utils/xml.js';
|
import * as utilsXml from '../utils/xml.js';
|
||||||
import * as Xml from '../xml.js';
|
|
||||||
|
|
||||||
import {BlockBase, BlockBaseJson} from './events_block_base.js';
|
|
||||||
import * as eventUtils from './utils.js';
|
|
||||||
import {Workspace} from '../workspace.js';
|
import {Workspace} from '../workspace.js';
|
||||||
|
import * as Xml from '../xml.js';
|
||||||
|
import {BlockBase, BlockBaseJson} from './events_block_base.js';
|
||||||
|
import {EventType} from './type.js';
|
||||||
|
import * as eventUtils from './utils.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners when a block (or connected stack of blocks) is
|
* Notifies listeners when a block (or connected stack of blocks) is
|
||||||
@@ -38,7 +38,7 @@ export class BlockDelete extends BlockBase {
|
|||||||
/** True if the deleted block was a shadow block, false otherwise. */
|
/** True if the deleted block was a shadow block, false otherwise. */
|
||||||
wasShadow?: boolean;
|
wasShadow?: boolean;
|
||||||
|
|
||||||
override type = eventUtils.BLOCK_DELETE;
|
override type = EventType.BLOCK_DELETE;
|
||||||
|
|
||||||
/** @param opt_block The deleted block. Undefined for a blank event. */
|
/** @param opt_block The deleted block. Undefined for a blank event. */
|
||||||
constructor(opt_block?: Block) {
|
constructor(opt_block?: Block) {
|
||||||
@@ -179,4 +179,4 @@ export interface BlockDeleteJson extends BlockBaseJson {
|
|||||||
recordUndo?: boolean;
|
recordUndo?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(registry.Type.EVENT, eventUtils.DELETE, BlockDelete);
|
registry.register(registry.Type.EVENT, EventType.BLOCK_DELETE, BlockDelete);
|
||||||
|
|||||||
@@ -13,10 +13,10 @@
|
|||||||
|
|
||||||
import type {Block} from '../block.js';
|
import type {Block} from '../block.js';
|
||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
|
import {Workspace} from '../workspace.js';
|
||||||
import {AbstractEventJson} from './events_abstract.js';
|
import {AbstractEventJson} from './events_abstract.js';
|
||||||
import {UiBase} from './events_ui_base.js';
|
import {UiBase} from './events_ui_base.js';
|
||||||
import * as eventUtils from './utils.js';
|
import {EventType} from './type.js';
|
||||||
import {Workspace} from '../workspace.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners when a block is being manually dragged/dropped.
|
* Notifies listeners when a block is being manually dragged/dropped.
|
||||||
@@ -34,7 +34,7 @@ export class BlockDrag extends UiBase {
|
|||||||
*/
|
*/
|
||||||
blocks?: Block[];
|
blocks?: Block[];
|
||||||
|
|
||||||
override type = eventUtils.BLOCK_DRAG;
|
override type = EventType.BLOCK_DRAG;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param opt_block The top block in the stack that is being dragged.
|
* @param opt_block The top block in the stack that is being dragged.
|
||||||
@@ -113,4 +113,4 @@ export interface BlockDragJson extends AbstractEventJson {
|
|||||||
blocks?: Block[];
|
blocks?: Block[];
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(registry.Type.EVENT, eventUtils.BLOCK_DRAG, BlockDrag);
|
registry.register(registry.Type.EVENT, EventType.BLOCK_DRAG, BlockDrag);
|
||||||
|
|||||||
@@ -15,9 +15,8 @@
|
|||||||
import type {Block} from '../block.js';
|
import type {Block} from '../block.js';
|
||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
import {Workspace} from '../workspace.js';
|
import {Workspace} from '../workspace.js';
|
||||||
|
|
||||||
import {BlockBase, BlockBaseJson} from './events_block_base.js';
|
import {BlockBase, BlockBaseJson} from './events_block_base.js';
|
||||||
import * as eventUtils from './utils.js';
|
import {EventType} from './type.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners when the value of a block's field has changed but the
|
* Notifies listeners when the value of a block's field has changed but the
|
||||||
@@ -25,7 +24,7 @@ import * as eventUtils from './utils.js';
|
|||||||
* event.
|
* event.
|
||||||
*/
|
*/
|
||||||
export class BlockFieldIntermediateChange extends BlockBase {
|
export class BlockFieldIntermediateChange extends BlockBase {
|
||||||
override type = eventUtils.BLOCK_FIELD_INTERMEDIATE_CHANGE;
|
override type = EventType.BLOCK_FIELD_INTERMEDIATE_CHANGE;
|
||||||
|
|
||||||
// Intermediate events do not undo or redo. They may be fired frequently while
|
// Intermediate events do not undo or redo. They may be fired frequently while
|
||||||
// the field editor widget is open. A separate BLOCK_CHANGE event is fired
|
// the field editor widget is open. A separate BLOCK_CHANGE event is fired
|
||||||
@@ -162,6 +161,6 @@ export interface BlockFieldIntermediateChangeJson extends BlockBaseJson {
|
|||||||
|
|
||||||
registry.register(
|
registry.register(
|
||||||
registry.Type.EVENT,
|
registry.Type.EVENT,
|
||||||
eventUtils.BLOCK_FIELD_INTERMEDIATE_CHANGE,
|
EventType.BLOCK_FIELD_INTERMEDIATE_CHANGE,
|
||||||
BlockFieldIntermediateChange,
|
BlockFieldIntermediateChange,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -15,10 +15,9 @@ import type {Block} from '../block.js';
|
|||||||
import {ConnectionType} from '../connection_type.js';
|
import {ConnectionType} from '../connection_type.js';
|
||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
import {Coordinate} from '../utils/coordinate.js';
|
import {Coordinate} from '../utils/coordinate.js';
|
||||||
|
|
||||||
import {BlockBase, BlockBaseJson} from './events_block_base.js';
|
|
||||||
import * as eventUtils from './utils.js';
|
|
||||||
import type {Workspace} from '../workspace.js';
|
import type {Workspace} from '../workspace.js';
|
||||||
|
import {BlockBase, BlockBaseJson} from './events_block_base.js';
|
||||||
|
import {EventType} from './type.js';
|
||||||
|
|
||||||
interface BlockLocation {
|
interface BlockLocation {
|
||||||
parentId?: string;
|
parentId?: string;
|
||||||
@@ -31,7 +30,7 @@ interface BlockLocation {
|
|||||||
* connection to another, or from one location on the workspace to another.
|
* connection to another, or from one location on the workspace to another.
|
||||||
*/
|
*/
|
||||||
export class BlockMove extends BlockBase {
|
export class BlockMove extends BlockBase {
|
||||||
override type = eventUtils.BLOCK_MOVE;
|
override type = EventType.BLOCK_MOVE;
|
||||||
|
|
||||||
/** The ID of the old parent block. Undefined if it was a top-level block. */
|
/** The ID of the old parent block. Undefined if it was a top-level block. */
|
||||||
oldParentId?: string;
|
oldParentId?: string;
|
||||||
@@ -90,7 +89,7 @@ export class BlockMove extends BlockBase {
|
|||||||
this.recordUndo = false;
|
this.recordUndo = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const location = this.currentLocation_();
|
const location = this.currentLocation();
|
||||||
this.oldParentId = location.parentId;
|
this.oldParentId = location.parentId;
|
||||||
this.oldInputName = location.inputName;
|
this.oldInputName = location.inputName;
|
||||||
this.oldCoordinate = location.coordinate;
|
this.oldCoordinate = location.coordinate;
|
||||||
@@ -168,7 +167,7 @@ export class BlockMove extends BlockBase {
|
|||||||
|
|
||||||
/** Record the block's new location. Called after the move. */
|
/** Record the block's new location. Called after the move. */
|
||||||
recordNew() {
|
recordNew() {
|
||||||
const location = this.currentLocation_();
|
const location = this.currentLocation();
|
||||||
this.newParentId = location.parentId;
|
this.newParentId = location.parentId;
|
||||||
this.newInputName = location.inputName;
|
this.newInputName = location.inputName;
|
||||||
this.newCoordinate = location.coordinate;
|
this.newCoordinate = location.coordinate;
|
||||||
@@ -189,7 +188,7 @@ export class BlockMove extends BlockBase {
|
|||||||
*
|
*
|
||||||
* @returns Collection of location info.
|
* @returns Collection of location info.
|
||||||
*/
|
*/
|
||||||
private currentLocation_(): BlockLocation {
|
private currentLocation(): BlockLocation {
|
||||||
const workspace = this.getEventWorkspace_();
|
const workspace = this.getEventWorkspace_();
|
||||||
if (!this.blockId) {
|
if (!this.blockId) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -304,4 +303,4 @@ export interface BlockMoveJson extends BlockBaseJson {
|
|||||||
recordUndo?: boolean;
|
recordUndo?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(registry.Type.EVENT, eventUtils.MOVE, BlockMove);
|
registry.register(registry.Type.EVENT, EventType.BLOCK_MOVE, BlockMove);
|
||||||
|
|||||||
@@ -9,14 +9,15 @@
|
|||||||
*
|
*
|
||||||
* @class
|
* @class
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Former goog.module ID: Blockly.Events.BubbleOpen
|
// Former goog.module ID: Blockly.Events.BubbleOpen
|
||||||
|
|
||||||
import type {AbstractEventJson} from './events_abstract.js';
|
|
||||||
import type {BlockSvg} from '../block_svg.js';
|
import type {BlockSvg} from '../block_svg.js';
|
||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
import {UiBase} from './events_ui_base.js';
|
|
||||||
import * as eventUtils from './utils.js';
|
|
||||||
import type {Workspace} from '../workspace.js';
|
import type {Workspace} from '../workspace.js';
|
||||||
|
import type {AbstractEventJson} from './events_abstract.js';
|
||||||
|
import {UiBase} from './events_ui_base.js';
|
||||||
|
import {EventType} from './type.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for a bubble open event.
|
* Class for a bubble open event.
|
||||||
@@ -31,7 +32,7 @@ export class BubbleOpen extends UiBase {
|
|||||||
/** The type of bubble; one of 'mutator', 'comment', or 'warning'. */
|
/** The type of bubble; one of 'mutator', 'comment', or 'warning'. */
|
||||||
bubbleType?: BubbleType;
|
bubbleType?: BubbleType;
|
||||||
|
|
||||||
override type = eventUtils.BUBBLE_OPEN;
|
override type = EventType.BUBBLE_OPEN;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param opt_block The associated block. Undefined for a blank event.
|
* @param opt_block The associated block. Undefined for a blank event.
|
||||||
@@ -117,4 +118,4 @@ export interface BubbleOpenJson extends AbstractEventJson {
|
|||||||
blockId: string;
|
blockId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(registry.Type.EVENT, eventUtils.BUBBLE_OPEN, BubbleOpen);
|
registry.register(registry.Type.EVENT, EventType.BUBBLE_OPEN, BubbleOpen);
|
||||||
|
|||||||
@@ -9,15 +9,15 @@
|
|||||||
*
|
*
|
||||||
* @class
|
* @class
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Former goog.module ID: Blockly.Events.Click
|
// Former goog.module ID: Blockly.Events.Click
|
||||||
|
|
||||||
import type {Block} from '../block.js';
|
import type {Block} from '../block.js';
|
||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
import {AbstractEventJson} from './events_abstract.js';
|
|
||||||
|
|
||||||
import {UiBase} from './events_ui_base.js';
|
|
||||||
import * as eventUtils from './utils.js';
|
|
||||||
import {Workspace} from '../workspace.js';
|
import {Workspace} from '../workspace.js';
|
||||||
|
import {AbstractEventJson} from './events_abstract.js';
|
||||||
|
import {UiBase} from './events_ui_base.js';
|
||||||
|
import {EventType} from './type.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners that some blockly element was clicked.
|
* Notifies listeners that some blockly element was clicked.
|
||||||
@@ -31,7 +31,7 @@ export class Click extends UiBase {
|
|||||||
* or 'zoom_controls'.
|
* or 'zoom_controls'.
|
||||||
*/
|
*/
|
||||||
targetType?: ClickTarget;
|
targetType?: ClickTarget;
|
||||||
override type = eventUtils.CLICK;
|
override type = EventType.CLICK;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param opt_block The affected block. Null for click events that do not have
|
* @param opt_block The affected block. Null for click events that do not have
|
||||||
@@ -107,4 +107,4 @@ export interface ClickJson extends AbstractEventJson {
|
|||||||
blockId?: string;
|
blockId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(registry.Type.EVENT, eventUtils.CLICK, Click);
|
registry.register(registry.Type.EVENT, EventType.CLICK, Click);
|
||||||
|
|||||||
@@ -13,14 +13,14 @@
|
|||||||
|
|
||||||
import type {WorkspaceComment} from '../comments/workspace_comment.js';
|
import type {WorkspaceComment} from '../comments/workspace_comment.js';
|
||||||
import * as comments from '../serialization/workspace_comments.js';
|
import * as comments from '../serialization/workspace_comments.js';
|
||||||
|
import type {Workspace} from '../workspace.js';
|
||||||
import {
|
import {
|
||||||
Abstract as AbstractEvent,
|
Abstract as AbstractEvent,
|
||||||
AbstractEventJson,
|
AbstractEventJson,
|
||||||
} from './events_abstract.js';
|
} from './events_abstract.js';
|
||||||
import type {CommentCreate} from './events_comment_create.js';
|
import type {CommentCreate} from './events_comment_create.js';
|
||||||
import type {CommentDelete} from './events_comment_delete.js';
|
import type {CommentDelete} from './events_comment_delete.js';
|
||||||
import * as eventUtils from './utils.js';
|
import {getGroup, getRecordUndo} from './utils.js';
|
||||||
import type {Workspace} from '../workspace.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class for a comment event.
|
* Abstract class for a comment event.
|
||||||
@@ -44,8 +44,8 @@ export class CommentBase extends AbstractEvent {
|
|||||||
|
|
||||||
this.commentId = opt_comment.id;
|
this.commentId = opt_comment.id;
|
||||||
this.workspaceId = opt_comment.workspace.id;
|
this.workspaceId = opt_comment.workspace.id;
|
||||||
this.group = eventUtils.getGroup();
|
this.group = getGroup();
|
||||||
this.recordUndo = eventUtils.getRecordUndo();
|
this.recordUndo = getRecordUndo();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,18 +11,17 @@
|
|||||||
*/
|
*/
|
||||||
// Former goog.module ID: Blockly.Events.CommentChange
|
// Former goog.module ID: Blockly.Events.CommentChange
|
||||||
|
|
||||||
import * as registry from '../registry.js';
|
|
||||||
import type {WorkspaceComment} from '../comments/workspace_comment.js';
|
import type {WorkspaceComment} from '../comments/workspace_comment.js';
|
||||||
|
import * as registry from '../registry.js';
|
||||||
import {CommentBase, CommentBaseJson} from './events_comment_base.js';
|
|
||||||
import * as eventUtils from './utils.js';
|
|
||||||
import type {Workspace} from '../workspace.js';
|
import type {Workspace} from '../workspace.js';
|
||||||
|
import {CommentBase, CommentBaseJson} from './events_comment_base.js';
|
||||||
|
import {EventType} from './type.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners that the contents of a workspace comment has changed.
|
* Notifies listeners that the contents of a workspace comment has changed.
|
||||||
*/
|
*/
|
||||||
export class CommentChange extends CommentBase {
|
export class CommentChange extends CommentBase {
|
||||||
override type = eventUtils.COMMENT_CHANGE;
|
override type = EventType.COMMENT_CHANGE;
|
||||||
|
|
||||||
// TODO(#6774): We should remove underscores.
|
// TODO(#6774): We should remove underscores.
|
||||||
/** The previous contents of the comment. */
|
/** The previous contents of the comment. */
|
||||||
@@ -154,8 +153,4 @@ export interface CommentChangeJson extends CommentBaseJson {
|
|||||||
newContents: string;
|
newContents: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(
|
registry.register(registry.Type.EVENT, EventType.COMMENT_CHANGE, CommentChange);
|
||||||
registry.Type.EVENT,
|
|
||||||
eventUtils.COMMENT_CHANGE,
|
|
||||||
CommentChange,
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -4,14 +4,14 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as registry from '../registry.js';
|
|
||||||
import {WorkspaceComment} from '../comments/workspace_comment.js';
|
import {WorkspaceComment} from '../comments/workspace_comment.js';
|
||||||
import {CommentBase, CommentBaseJson} from './events_comment_base.js';
|
import * as registry from '../registry.js';
|
||||||
import * as eventUtils from './utils.js';
|
|
||||||
import type {Workspace} from '../workspace.js';
|
import type {Workspace} from '../workspace.js';
|
||||||
|
import {CommentBase, CommentBaseJson} from './events_comment_base.js';
|
||||||
|
import {EventType} from './type.js';
|
||||||
|
|
||||||
export class CommentCollapse extends CommentBase {
|
export class CommentCollapse extends CommentBase {
|
||||||
override type = eventUtils.COMMENT_COLLAPSE;
|
override type = EventType.COMMENT_COLLAPSE;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
comment?: WorkspaceComment,
|
comment?: WorkspaceComment,
|
||||||
@@ -98,6 +98,6 @@ export interface CommentCollapseJson extends CommentBaseJson {
|
|||||||
|
|
||||||
registry.register(
|
registry.register(
|
||||||
registry.Type.EVENT,
|
registry.Type.EVENT,
|
||||||
eventUtils.COMMENT_COLLAPSE,
|
EventType.COMMENT_COLLAPSE,
|
||||||
CommentCollapse,
|
CommentCollapse,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,20 +11,20 @@
|
|||||||
*/
|
*/
|
||||||
// Former goog.module ID: Blockly.Events.CommentCreate
|
// Former goog.module ID: Blockly.Events.CommentCreate
|
||||||
|
|
||||||
import * as registry from '../registry.js';
|
|
||||||
import type {WorkspaceComment} from '../comments/workspace_comment.js';
|
import type {WorkspaceComment} from '../comments/workspace_comment.js';
|
||||||
|
import * as registry from '../registry.js';
|
||||||
import * as comments from '../serialization/workspace_comments.js';
|
import * as comments from '../serialization/workspace_comments.js';
|
||||||
import * as utilsXml from '../utils/xml.js';
|
import * as utilsXml from '../utils/xml.js';
|
||||||
|
import type {Workspace} from '../workspace.js';
|
||||||
import * as Xml from '../xml.js';
|
import * as Xml from '../xml.js';
|
||||||
import {CommentBase, CommentBaseJson} from './events_comment_base.js';
|
import {CommentBase, CommentBaseJson} from './events_comment_base.js';
|
||||||
import * as eventUtils from './utils.js';
|
import {EventType} from './type.js';
|
||||||
import type {Workspace} from '../workspace.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners that a workspace comment was created.
|
* Notifies listeners that a workspace comment was created.
|
||||||
*/
|
*/
|
||||||
export class CommentCreate extends CommentBase {
|
export class CommentCreate extends CommentBase {
|
||||||
override type = eventUtils.COMMENT_CREATE;
|
override type = EventType.COMMENT_CREATE;
|
||||||
|
|
||||||
/** The XML representation of the created workspace comment. */
|
/** The XML representation of the created workspace comment. */
|
||||||
xml?: Element | DocumentFragment;
|
xml?: Element | DocumentFragment;
|
||||||
@@ -111,8 +111,4 @@ export interface CommentCreateJson extends CommentBaseJson {
|
|||||||
json: object;
|
json: object;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(
|
registry.register(registry.Type.EVENT, EventType.COMMENT_CREATE, CommentCreate);
|
||||||
registry.Type.EVENT,
|
|
||||||
eventUtils.COMMENT_CREATE,
|
|
||||||
CommentCreate,
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -11,20 +11,20 @@
|
|||||||
*/
|
*/
|
||||||
// Former goog.module ID: Blockly.Events.CommentDelete
|
// Former goog.module ID: Blockly.Events.CommentDelete
|
||||||
|
|
||||||
import * as registry from '../registry.js';
|
|
||||||
import type {WorkspaceComment} from '../comments/workspace_comment.js';
|
import type {WorkspaceComment} from '../comments/workspace_comment.js';
|
||||||
|
import * as registry from '../registry.js';
|
||||||
import * as comments from '../serialization/workspace_comments.js';
|
import * as comments from '../serialization/workspace_comments.js';
|
||||||
import {CommentBase, CommentBaseJson} from './events_comment_base.js';
|
|
||||||
import * as eventUtils from './utils.js';
|
|
||||||
import * as utilsXml from '../utils/xml.js';
|
import * as utilsXml from '../utils/xml.js';
|
||||||
import * as Xml from '../xml.js';
|
|
||||||
import type {Workspace} from '../workspace.js';
|
import type {Workspace} from '../workspace.js';
|
||||||
|
import * as Xml from '../xml.js';
|
||||||
|
import {CommentBase, CommentBaseJson} from './events_comment_base.js';
|
||||||
|
import {EventType} from './type.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners that a workspace comment has been deleted.
|
* Notifies listeners that a workspace comment has been deleted.
|
||||||
*/
|
*/
|
||||||
export class CommentDelete extends CommentBase {
|
export class CommentDelete extends CommentBase {
|
||||||
override type = eventUtils.COMMENT_DELETE;
|
override type = EventType.COMMENT_DELETE;
|
||||||
|
|
||||||
/** The XML representation of the deleted workspace comment. */
|
/** The XML representation of the deleted workspace comment. */
|
||||||
xml?: Element;
|
xml?: Element;
|
||||||
@@ -110,8 +110,4 @@ export interface CommentDeleteJson extends CommentBaseJson {
|
|||||||
json: object;
|
json: object;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(
|
registry.register(registry.Type.EVENT, EventType.COMMENT_DELETE, CommentDelete);
|
||||||
registry.Type.EVENT,
|
|
||||||
eventUtils.COMMENT_DELETE,
|
|
||||||
CommentDelete,
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -10,10 +10,10 @@
|
|||||||
|
|
||||||
import type {WorkspaceComment} from '../comments/workspace_comment.js';
|
import type {WorkspaceComment} from '../comments/workspace_comment.js';
|
||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
|
import {Workspace} from '../workspace.js';
|
||||||
import {AbstractEventJson} from './events_abstract.js';
|
import {AbstractEventJson} from './events_abstract.js';
|
||||||
import {UiBase} from './events_ui_base.js';
|
import {UiBase} from './events_ui_base.js';
|
||||||
import * as eventUtils from './utils.js';
|
import {EventType} from './type.js';
|
||||||
import {Workspace} from '../workspace.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners when a comment is being manually dragged/dropped.
|
* Notifies listeners when a comment is being manually dragged/dropped.
|
||||||
@@ -25,7 +25,7 @@ export class CommentDrag extends UiBase {
|
|||||||
/** True if this is the start of a drag, false if this is the end of one. */
|
/** True if this is the start of a drag, false if this is the end of one. */
|
||||||
isStart?: boolean;
|
isStart?: boolean;
|
||||||
|
|
||||||
override type = eventUtils.COMMENT_DRAG;
|
override type = EventType.COMMENT_DRAG;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param opt_comment The comment that is being dragged.
|
* @param opt_comment The comment that is being dragged.
|
||||||
@@ -96,4 +96,4 @@ export interface CommentDragJson extends AbstractEventJson {
|
|||||||
commentId: string;
|
commentId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(registry.Type.EVENT, eventUtils.COMMENT_DRAG, CommentDrag);
|
registry.register(registry.Type.EVENT, EventType.COMMENT_DRAG, CommentDrag);
|
||||||
|
|||||||
@@ -11,19 +11,18 @@
|
|||||||
*/
|
*/
|
||||||
// Former goog.module ID: Blockly.Events.CommentMove
|
// Former goog.module ID: Blockly.Events.CommentMove
|
||||||
|
|
||||||
|
import type {WorkspaceComment} from '../comments/workspace_comment.js';
|
||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
import {Coordinate} from '../utils/coordinate.js';
|
import {Coordinate} from '../utils/coordinate.js';
|
||||||
import type {WorkspaceComment} from '../comments/workspace_comment.js';
|
|
||||||
|
|
||||||
import {CommentBase, CommentBaseJson} from './events_comment_base.js';
|
|
||||||
import * as eventUtils from './utils.js';
|
|
||||||
import type {Workspace} from '../workspace.js';
|
import type {Workspace} from '../workspace.js';
|
||||||
|
import {CommentBase, CommentBaseJson} from './events_comment_base.js';
|
||||||
|
import {EventType} from './type.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners that a workspace comment has moved.
|
* Notifies listeners that a workspace comment has moved.
|
||||||
*/
|
*/
|
||||||
export class CommentMove extends CommentBase {
|
export class CommentMove extends CommentBase {
|
||||||
override type = eventUtils.COMMENT_MOVE;
|
override type = EventType.COMMENT_MOVE;
|
||||||
|
|
||||||
/** The comment that is being moved. */
|
/** The comment that is being moved. */
|
||||||
comment_?: WorkspaceComment;
|
comment_?: WorkspaceComment;
|
||||||
@@ -204,4 +203,4 @@ export interface CommentMoveJson extends CommentBaseJson {
|
|||||||
newCoordinate: string;
|
newCoordinate: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(registry.Type.EVENT, eventUtils.COMMENT_MOVE, CommentMove);
|
registry.register(registry.Type.EVENT, EventType.COMMENT_MOVE, CommentMove);
|
||||||
|
|||||||
@@ -8,19 +8,18 @@
|
|||||||
* Class for comment resize event.
|
* Class for comment resize event.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type {WorkspaceComment} from '../comments/workspace_comment.js';
|
||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
import {Size} from '../utils/size.js';
|
import {Size} from '../utils/size.js';
|
||||||
import type {WorkspaceComment} from '../comments/workspace_comment.js';
|
|
||||||
|
|
||||||
import {CommentBase, CommentBaseJson} from './events_comment_base.js';
|
|
||||||
import * as eventUtils from './utils.js';
|
|
||||||
import type {Workspace} from '../workspace.js';
|
import type {Workspace} from '../workspace.js';
|
||||||
|
import {CommentBase, CommentBaseJson} from './events_comment_base.js';
|
||||||
|
import {EventType} from './type.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners that a workspace comment has resized.
|
* Notifies listeners that a workspace comment has resized.
|
||||||
*/
|
*/
|
||||||
export class CommentResize extends CommentBase {
|
export class CommentResize extends CommentBase {
|
||||||
override type = eventUtils.COMMENT_RESIZE;
|
override type = EventType.COMMENT_RESIZE;
|
||||||
|
|
||||||
/** The size of the comment before the resize. */
|
/** The size of the comment before the resize. */
|
||||||
oldSize?: Size;
|
oldSize?: Size;
|
||||||
@@ -167,8 +166,4 @@ export interface CommentResizeJson extends CommentBaseJson {
|
|||||||
newHeight: number;
|
newHeight: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(
|
registry.register(registry.Type.EVENT, EventType.COMMENT_RESIZE, CommentResize);
|
||||||
registry.Type.EVENT,
|
|
||||||
eventUtils.COMMENT_RESIZE,
|
|
||||||
CommentResize,
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -16,9 +16,8 @@ import {ASTNode} from '../keyboard_nav/ast_node.js';
|
|||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
import type {Workspace} from '../workspace.js';
|
import type {Workspace} from '../workspace.js';
|
||||||
import {AbstractEventJson} from './events_abstract.js';
|
import {AbstractEventJson} from './events_abstract.js';
|
||||||
|
|
||||||
import {UiBase} from './events_ui_base.js';
|
import {UiBase} from './events_ui_base.js';
|
||||||
import * as eventUtils from './utils.js';
|
import {EventType} from './type.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners that a marker (used for keyboard navigation) has
|
* Notifies listeners that a marker (used for keyboard navigation) has
|
||||||
@@ -41,7 +40,7 @@ export class MarkerMove extends UiBase {
|
|||||||
*/
|
*/
|
||||||
isCursor?: boolean;
|
isCursor?: boolean;
|
||||||
|
|
||||||
override type = eventUtils.MARKER_MOVE;
|
override type = EventType.MARKER_MOVE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param opt_block The affected block. Null if current node is of type
|
* @param opt_block The affected block. Null if current node is of type
|
||||||
@@ -131,4 +130,4 @@ export interface MarkerMoveJson extends AbstractEventJson {
|
|||||||
newNode: ASTNode;
|
newNode: ASTNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(registry.Type.EVENT, eventUtils.MARKER_MOVE, MarkerMove);
|
registry.register(registry.Type.EVENT, EventType.MARKER_MOVE, MarkerMove);
|
||||||
|
|||||||
@@ -12,11 +12,10 @@
|
|||||||
// Former goog.module ID: Blockly.Events.Selected
|
// Former goog.module ID: Blockly.Events.Selected
|
||||||
|
|
||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
import {AbstractEventJson} from './events_abstract.js';
|
|
||||||
|
|
||||||
import {UiBase} from './events_ui_base.js';
|
|
||||||
import * as eventUtils from './utils.js';
|
|
||||||
import type {Workspace} from '../workspace.js';
|
import type {Workspace} from '../workspace.js';
|
||||||
|
import {AbstractEventJson} from './events_abstract.js';
|
||||||
|
import {UiBase} from './events_ui_base.js';
|
||||||
|
import {EventType} from './type.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for a selected event.
|
* Class for a selected event.
|
||||||
@@ -32,7 +31,7 @@ export class Selected extends UiBase {
|
|||||||
*/
|
*/
|
||||||
newElementId?: string;
|
newElementId?: string;
|
||||||
|
|
||||||
override type = eventUtils.SELECTED;
|
override type = EventType.SELECTED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param opt_oldElementId The ID of the previously selected element. Null if
|
* @param opt_oldElementId The ID of the previously selected element. Null if
|
||||||
@@ -95,4 +94,4 @@ export interface SelectedJson extends AbstractEventJson {
|
|||||||
newElementId?: string;
|
newElementId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(registry.Type.EVENT, eventUtils.SELECTED, Selected);
|
registry.register(registry.Type.EVENT, EventType.SELECTED, Selected);
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
// Former goog.module ID: Blockly.Events.ThemeChange
|
// Former goog.module ID: Blockly.Events.ThemeChange
|
||||||
|
|
||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
|
import type {Workspace} from '../workspace.js';
|
||||||
import {AbstractEventJson} from './events_abstract.js';
|
import {AbstractEventJson} from './events_abstract.js';
|
||||||
import {UiBase} from './events_ui_base.js';
|
import {UiBase} from './events_ui_base.js';
|
||||||
import * as eventUtils from './utils.js';
|
import {EventType} from './type.js';
|
||||||
import type {Workspace} from '../workspace.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners that the workspace theme has changed.
|
* Notifies listeners that the workspace theme has changed.
|
||||||
@@ -24,7 +24,7 @@ export class ThemeChange extends UiBase {
|
|||||||
/** The name of the new theme that has been set. */
|
/** The name of the new theme that has been set. */
|
||||||
themeName?: string;
|
themeName?: string;
|
||||||
|
|
||||||
override type = eventUtils.THEME_CHANGE;
|
override type = EventType.THEME_CHANGE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param opt_themeName The theme name. Undefined for a blank event.
|
* @param opt_themeName The theme name. Undefined for a blank event.
|
||||||
@@ -81,4 +81,4 @@ export interface ThemeChangeJson extends AbstractEventJson {
|
|||||||
themeName: string;
|
themeName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(registry.Type.EVENT, eventUtils.THEME_CHANGE, ThemeChange);
|
registry.register(registry.Type.EVENT, EventType.THEME_CHANGE, ThemeChange);
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
// Former goog.module ID: Blockly.Events.ToolboxItemSelect
|
// Former goog.module ID: Blockly.Events.ToolboxItemSelect
|
||||||
|
|
||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
|
import type {Workspace} from '../workspace.js';
|
||||||
import {AbstractEventJson} from './events_abstract.js';
|
import {AbstractEventJson} from './events_abstract.js';
|
||||||
import {UiBase} from './events_ui_base.js';
|
import {UiBase} from './events_ui_base.js';
|
||||||
import * as eventUtils from './utils.js';
|
import {EventType} from './type.js';
|
||||||
import type {Workspace} from '../workspace.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners that a toolbox item has been selected.
|
* Notifies listeners that a toolbox item has been selected.
|
||||||
@@ -27,7 +27,7 @@ export class ToolboxItemSelect extends UiBase {
|
|||||||
/** The newly selected toolbox item. */
|
/** The newly selected toolbox item. */
|
||||||
newItem?: string;
|
newItem?: string;
|
||||||
|
|
||||||
override type = eventUtils.TOOLBOX_ITEM_SELECT;
|
override type = EventType.TOOLBOX_ITEM_SELECT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param opt_oldItem The previously selected toolbox item.
|
* @param opt_oldItem The previously selected toolbox item.
|
||||||
@@ -91,6 +91,6 @@ export interface ToolboxItemSelectJson extends AbstractEventJson {
|
|||||||
|
|
||||||
registry.register(
|
registry.register(
|
||||||
registry.Type.EVENT,
|
registry.Type.EVENT,
|
||||||
eventUtils.TOOLBOX_ITEM_SELECT,
|
EventType.TOOLBOX_ITEM_SELECT,
|
||||||
ToolboxItemSelect,
|
ToolboxItemSelect,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,11 +12,10 @@
|
|||||||
// Former goog.module ID: Blockly.Events.TrashcanOpen
|
// Former goog.module ID: Blockly.Events.TrashcanOpen
|
||||||
|
|
||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
import {AbstractEventJson} from './events_abstract.js';
|
|
||||||
|
|
||||||
import {UiBase} from './events_ui_base.js';
|
|
||||||
import * as eventUtils from './utils.js';
|
|
||||||
import type {Workspace} from '../workspace.js';
|
import type {Workspace} from '../workspace.js';
|
||||||
|
import {AbstractEventJson} from './events_abstract.js';
|
||||||
|
import {UiBase} from './events_ui_base.js';
|
||||||
|
import {EventType} from './type.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners when the trashcan is opening or closing.
|
* Notifies listeners when the trashcan is opening or closing.
|
||||||
@@ -27,7 +26,7 @@ export class TrashcanOpen extends UiBase {
|
|||||||
* False if it is currently closing (previously open).
|
* False if it is currently closing (previously open).
|
||||||
*/
|
*/
|
||||||
isOpen?: boolean;
|
isOpen?: boolean;
|
||||||
override type = eventUtils.TRASHCAN_OPEN;
|
override type = EventType.TRASHCAN_OPEN;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param opt_isOpen Whether the trashcan flyout is opening (false if
|
* @param opt_isOpen Whether the trashcan flyout is opening (false if
|
||||||
@@ -85,4 +84,4 @@ export interface TrashcanOpenJson extends AbstractEventJson {
|
|||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(registry.Type.EVENT, eventUtils.TRASHCAN_OPEN, TrashcanOpen);
|
registry.register(registry.Type.EVENT, EventType.TRASHCAN_OPEN, TrashcanOpen);
|
||||||
|
|||||||
@@ -15,12 +15,11 @@ import type {
|
|||||||
IVariableModel,
|
IVariableModel,
|
||||||
IVariableState,
|
IVariableState,
|
||||||
} from '../interfaces/i_variable_model.js';
|
} from '../interfaces/i_variable_model.js';
|
||||||
|
import type {Workspace} from '../workspace.js';
|
||||||
import {
|
import {
|
||||||
Abstract as AbstractEvent,
|
Abstract as AbstractEvent,
|
||||||
AbstractEventJson,
|
AbstractEventJson,
|
||||||
} from './events_abstract.js';
|
} from './events_abstract.js';
|
||||||
import type {Workspace} from '../workspace.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class for a variable event.
|
* Abstract class for a variable event.
|
||||||
|
|||||||
@@ -11,21 +11,21 @@
|
|||||||
*/
|
*/
|
||||||
// Former goog.module ID: Blockly.Events.VarCreate
|
// Former goog.module ID: Blockly.Events.VarCreate
|
||||||
|
|
||||||
import * as registry from '../registry.js';
|
|
||||||
import type {
|
import type {
|
||||||
IVariableModel,
|
IVariableModel,
|
||||||
IVariableState,
|
IVariableState,
|
||||||
} from '../interfaces/i_variable_model.js';
|
} from '../interfaces/i_variable_model.js';
|
||||||
|
import * as registry from '../registry.js';
|
||||||
|
|
||||||
import {VarBase, VarBaseJson} from './events_var_base.js';
|
|
||||||
import * as eventUtils from './utils.js';
|
|
||||||
import type {Workspace} from '../workspace.js';
|
import type {Workspace} from '../workspace.js';
|
||||||
|
import {VarBase, VarBaseJson} from './events_var_base.js';
|
||||||
|
import {EventType} from './type.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners that a variable model has been created.
|
* Notifies listeners that a variable model has been created.
|
||||||
*/
|
*/
|
||||||
export class VarCreate extends VarBase {
|
export class VarCreate extends VarBase {
|
||||||
override type = eventUtils.VAR_CREATE;
|
override type = EventType.VAR_CREATE;
|
||||||
|
|
||||||
/** The type of the variable that was created. */
|
/** The type of the variable that was created. */
|
||||||
varType?: string;
|
varType?: string;
|
||||||
@@ -126,4 +126,4 @@ export interface VarCreateJson extends VarBaseJson {
|
|||||||
varName: string;
|
varName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(registry.Type.EVENT, eventUtils.VAR_CREATE, VarCreate);
|
registry.register(registry.Type.EVENT, EventType.VAR_CREATE, VarCreate);
|
||||||
|
|||||||
@@ -6,15 +6,15 @@
|
|||||||
|
|
||||||
// Former goog.module ID: Blockly.Events.VarDelete
|
// Former goog.module ID: Blockly.Events.VarDelete
|
||||||
|
|
||||||
import * as registry from '../registry.js';
|
|
||||||
import type {
|
import type {
|
||||||
IVariableModel,
|
IVariableModel,
|
||||||
IVariableState,
|
IVariableState,
|
||||||
} from '../interfaces/i_variable_model.js';
|
} from '../interfaces/i_variable_model.js';
|
||||||
|
import * as registry from '../registry.js';
|
||||||
|
|
||||||
import {VarBase, VarBaseJson} from './events_var_base.js';
|
|
||||||
import * as eventUtils from './utils.js';
|
|
||||||
import type {Workspace} from '../workspace.js';
|
import type {Workspace} from '../workspace.js';
|
||||||
|
import {VarBase, VarBaseJson} from './events_var_base.js';
|
||||||
|
import {EventType} from './type.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners that a variable model has been deleted.
|
* Notifies listeners that a variable model has been deleted.
|
||||||
@@ -22,7 +22,7 @@ import type {Workspace} from '../workspace.js';
|
|||||||
* @class
|
* @class
|
||||||
*/
|
*/
|
||||||
export class VarDelete extends VarBase {
|
export class VarDelete extends VarBase {
|
||||||
override type = eventUtils.VAR_DELETE;
|
override type = EventType.VAR_DELETE;
|
||||||
/** The type of the variable that was deleted. */
|
/** The type of the variable that was deleted. */
|
||||||
varType?: string;
|
varType?: string;
|
||||||
/** The name of the variable that was deleted. */
|
/** The name of the variable that was deleted. */
|
||||||
@@ -121,4 +121,4 @@ export interface VarDeleteJson extends VarBaseJson {
|
|||||||
varName: string;
|
varName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(registry.Type.EVENT, eventUtils.VAR_DELETE, VarDelete);
|
registry.register(registry.Type.EVENT, EventType.VAR_DELETE, VarDelete);
|
||||||
|
|||||||
@@ -6,15 +6,15 @@
|
|||||||
|
|
||||||
// Former goog.module ID: Blockly.Events.VarRename
|
// Former goog.module ID: Blockly.Events.VarRename
|
||||||
|
|
||||||
import * as registry from '../registry.js';
|
|
||||||
import type {
|
import type {
|
||||||
IVariableModel,
|
IVariableModel,
|
||||||
IVariableState,
|
IVariableState,
|
||||||
} from '../interfaces/i_variable_model.js';
|
} from '../interfaces/i_variable_model.js';
|
||||||
|
import * as registry from '../registry.js';
|
||||||
|
|
||||||
import {VarBase, VarBaseJson} from './events_var_base.js';
|
|
||||||
import * as eventUtils from './utils.js';
|
|
||||||
import type {Workspace} from '../workspace.js';
|
import type {Workspace} from '../workspace.js';
|
||||||
|
import {VarBase, VarBaseJson} from './events_var_base.js';
|
||||||
|
import {EventType} from './type.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners that a variable model was renamed.
|
* Notifies listeners that a variable model was renamed.
|
||||||
@@ -22,7 +22,7 @@ import type {Workspace} from '../workspace.js';
|
|||||||
* @class
|
* @class
|
||||||
*/
|
*/
|
||||||
export class VarRename extends VarBase {
|
export class VarRename extends VarBase {
|
||||||
override type = eventUtils.VAR_RENAME;
|
override type = EventType.VAR_RENAME;
|
||||||
|
|
||||||
/** The previous name of the variable. */
|
/** The previous name of the variable. */
|
||||||
oldName?: string;
|
oldName?: string;
|
||||||
@@ -130,4 +130,4 @@ export interface VarRenameJson extends VarBaseJson {
|
|||||||
newName: string;
|
newName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.register(registry.Type.EVENT, eventUtils.VAR_RENAME, VarRename);
|
registry.register(registry.Type.EVENT, EventType.VAR_RENAME, VarRename);
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
// Former goog.module ID: Blockly.Events.ViewportChange
|
// Former goog.module ID: Blockly.Events.ViewportChange
|
||||||
|
|
||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
|
import type {Workspace} from '../workspace.js';
|
||||||
import {AbstractEventJson} from './events_abstract.js';
|
import {AbstractEventJson} from './events_abstract.js';
|
||||||
import {UiBase} from './events_ui_base.js';
|
import {UiBase} from './events_ui_base.js';
|
||||||
import * as eventUtils from './utils.js';
|
import {EventType} from './type.js';
|
||||||
import type {Workspace} from '../workspace.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners that the workspace surface's position or scale has
|
* Notifies listeners that the workspace surface's position or scale has
|
||||||
@@ -42,7 +42,7 @@ export class ViewportChange extends UiBase {
|
|||||||
/** The previous scale of the workspace. */
|
/** The previous scale of the workspace. */
|
||||||
oldScale?: number;
|
oldScale?: number;
|
||||||
|
|
||||||
override type = eventUtils.VIEWPORT_CHANGE;
|
override type = EventType.VIEWPORT_CHANGE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param opt_top Top-edge of the visible portion of the workspace, relative
|
* @param opt_top Top-edge of the visible portion of the workspace, relative
|
||||||
@@ -144,6 +144,6 @@ export interface ViewportChangeJson extends AbstractEventJson {
|
|||||||
|
|
||||||
registry.register(
|
registry.register(
|
||||||
registry.Type.EVENT,
|
registry.Type.EVENT,
|
||||||
eventUtils.VIEWPORT_CHANGE,
|
EventType.VIEWPORT_CHANGE,
|
||||||
ViewportChange,
|
ViewportChange,
|
||||||
);
|
);
|
||||||
|
|||||||
172
core/events/predicates.ts
Normal file
172
core/events/predicates.ts
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2024 Google LLC
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file Predicates for testing Abstract event subclasses based on
|
||||||
|
* their .type properties. These are useful because there are places
|
||||||
|
* where it is not possible to use instanceof <ClassConstructor> tests
|
||||||
|
* for type narrowing due to load ordering issues that would be caused
|
||||||
|
* by the need to import (rather than just import type) the class
|
||||||
|
* constructors in question.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type {Abstract} from './events_abstract.js';
|
||||||
|
import type {BlockChange} from './events_block_change.js';
|
||||||
|
import type {BlockCreate} from './events_block_create.js';
|
||||||
|
import type {BlockDelete} from './events_block_delete.js';
|
||||||
|
import type {BlockDrag} from './events_block_drag.js';
|
||||||
|
import type {BlockFieldIntermediateChange} from './events_block_field_intermediate_change.js';
|
||||||
|
import type {BlockMove} from './events_block_move.js';
|
||||||
|
import type {BubbleOpen} from './events_bubble_open.js';
|
||||||
|
import type {Click} from './events_click.js';
|
||||||
|
import type {CommentChange} from './events_comment_change.js';
|
||||||
|
import type {CommentCollapse} from './events_comment_collapse.js';
|
||||||
|
import type {CommentCreate} from './events_comment_create.js';
|
||||||
|
import type {CommentDelete} from './events_comment_delete.js';
|
||||||
|
import type {CommentDrag} from './events_comment_drag.js';
|
||||||
|
import type {CommentMove} from './events_comment_move.js';
|
||||||
|
import type {CommentResize} from './events_comment_resize.js';
|
||||||
|
import type {MarkerMove} from './events_marker_move.js';
|
||||||
|
import type {Selected} from './events_selected.js';
|
||||||
|
import type {ThemeChange} from './events_theme_change.js';
|
||||||
|
import type {ToolboxItemSelect} from './events_toolbox_item_select.js';
|
||||||
|
import type {TrashcanOpen} from './events_trashcan_open.js';
|
||||||
|
import type {VarCreate} from './events_var_create.js';
|
||||||
|
import type {VarDelete} from './events_var_delete.js';
|
||||||
|
import type {VarRename} from './events_var_rename.js';
|
||||||
|
import type {ViewportChange} from './events_viewport.js';
|
||||||
|
import type {FinishedLoading} from './workspace_events.js';
|
||||||
|
|
||||||
|
import {EventType} from './type.js';
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.BLOCK_CREATE */
|
||||||
|
export function isBlockCreate(event: Abstract): event is BlockCreate {
|
||||||
|
return event.type === EventType.BLOCK_CREATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.BLOCK_DELETE */
|
||||||
|
export function isBlockDelete(event: Abstract): event is BlockDelete {
|
||||||
|
return event.type === EventType.BLOCK_DELETE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.BLOCK_CHANGE */
|
||||||
|
export function isBlockChange(event: Abstract): event is BlockChange {
|
||||||
|
return event.type === EventType.BLOCK_CHANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.BLOCK_FIELD_INTERMEDIATE_CHANGE */
|
||||||
|
export function isBlockFieldIntermediateChange(
|
||||||
|
event: Abstract,
|
||||||
|
): event is BlockFieldIntermediateChange {
|
||||||
|
return event.type === EventType.BLOCK_FIELD_INTERMEDIATE_CHANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.BLOCK_MOVE */
|
||||||
|
export function isBlockMove(event: Abstract): event is BlockMove {
|
||||||
|
return event.type === EventType.BLOCK_MOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.VAR_CREATE */
|
||||||
|
export function isVarCreate(event: Abstract): event is VarCreate {
|
||||||
|
return event.type === EventType.VAR_CREATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.VAR_DELETE */
|
||||||
|
export function isVarDelete(event: Abstract): event is VarDelete {
|
||||||
|
return event.type === EventType.VAR_DELETE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.VAR_RENAME */
|
||||||
|
export function isVarRename(event: Abstract): event is VarRename {
|
||||||
|
return event.type === EventType.VAR_RENAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.BLOCK_DRAG */
|
||||||
|
export function isBlockDrag(event: Abstract): event is BlockDrag {
|
||||||
|
return event.type === EventType.BLOCK_DRAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.SELECTED */
|
||||||
|
export function isSelected(event: Abstract): event is Selected {
|
||||||
|
return event.type === EventType.SELECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.CLICK */
|
||||||
|
export function isClick(event: Abstract): event is Click {
|
||||||
|
return event.type === EventType.CLICK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.MARKER_MOVE */
|
||||||
|
export function isMarkerMove(event: Abstract): event is MarkerMove {
|
||||||
|
return event.type === EventType.MARKER_MOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.BUBBLE_OPEN */
|
||||||
|
export function isBubbleOpen(event: Abstract): event is BubbleOpen {
|
||||||
|
return event.type === EventType.BUBBLE_OPEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.TRASHCAN_OPEN */
|
||||||
|
export function isTrashcanOpen(event: Abstract): event is TrashcanOpen {
|
||||||
|
return event.type === EventType.TRASHCAN_OPEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.TOOLBOX_ITEM_SELECT */
|
||||||
|
export function isToolboxItemSelect(
|
||||||
|
event: Abstract,
|
||||||
|
): event is ToolboxItemSelect {
|
||||||
|
return event.type === EventType.TOOLBOX_ITEM_SELECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.THEME_CHANGE */
|
||||||
|
export function isThemeChange(event: Abstract): event is ThemeChange {
|
||||||
|
return event.type === EventType.THEME_CHANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.VIEWPORT_CHANGE */
|
||||||
|
export function isViewportChange(event: Abstract): event is ViewportChange {
|
||||||
|
return event.type === EventType.VIEWPORT_CHANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.COMMENT_CREATE */
|
||||||
|
export function isCommentCreate(event: Abstract): event is CommentCreate {
|
||||||
|
return event.type === EventType.COMMENT_CREATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.COMMENT_DELETE */
|
||||||
|
export function isCommentDelete(event: Abstract): event is CommentDelete {
|
||||||
|
return event.type === EventType.COMMENT_DELETE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.COMMENT_CHANGE */
|
||||||
|
export function isCommentChange(event: Abstract): event is CommentChange {
|
||||||
|
return event.type === EventType.COMMENT_CHANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.COMMENT_MOVE */
|
||||||
|
export function isCommentMove(event: Abstract): event is CommentMove {
|
||||||
|
return event.type === EventType.COMMENT_MOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.COMMENT_RESIZE */
|
||||||
|
export function isCommentResize(event: Abstract): event is CommentResize {
|
||||||
|
return event.type === EventType.COMMENT_RESIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.COMMENT_DRAG */
|
||||||
|
export function isCommentDrag(event: Abstract): event is CommentDrag {
|
||||||
|
return event.type === EventType.COMMENT_DRAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.COMMENT_COLLAPSE */
|
||||||
|
export function isCommentCollapse(event: Abstract): event is CommentCollapse {
|
||||||
|
return event.type === EventType.COMMENT_COLLAPSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns true iff event.type is EventType.FINISHED_LOADING */
|
||||||
|
export function isFinishedLoading(event: Abstract): event is FinishedLoading {
|
||||||
|
return event.type === EventType.FINISHED_LOADING;
|
||||||
|
}
|
||||||
85
core/events/type.ts
Normal file
85
core/events/type.ts
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2024 Google LLC
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum of values for the .type property for event classes (concrete subclasses
|
||||||
|
* of Abstract).
|
||||||
|
*/
|
||||||
|
export enum EventType {
|
||||||
|
/** Type of event that creates a block. */
|
||||||
|
BLOCK_CREATE = 'create',
|
||||||
|
/** Type of event that deletes a block. */
|
||||||
|
BLOCK_DELETE = 'delete',
|
||||||
|
/** Type of event that changes a block. */
|
||||||
|
BLOCK_CHANGE = 'change',
|
||||||
|
/**
|
||||||
|
* Type of event representing an in-progress change to a field of a
|
||||||
|
* block, which is expected to be followed by a block change event.
|
||||||
|
*/
|
||||||
|
BLOCK_FIELD_INTERMEDIATE_CHANGE = 'block_field_intermediate_change',
|
||||||
|
/** Type of event that moves a block. */
|
||||||
|
BLOCK_MOVE = 'move',
|
||||||
|
/** Type of event that creates a variable. */
|
||||||
|
VAR_CREATE = 'var_create',
|
||||||
|
/** Type of event that deletes a variable. */
|
||||||
|
VAR_DELETE = 'var_delete',
|
||||||
|
/** Type of event that renames a variable. */
|
||||||
|
VAR_RENAME = 'var_rename',
|
||||||
|
/**
|
||||||
|
* Type of generic event that records a UI change.
|
||||||
|
*
|
||||||
|
* @deprecated Was only ever intended for internal use.
|
||||||
|
*/
|
||||||
|
UI = 'ui',
|
||||||
|
/** Type of event that drags a block. */
|
||||||
|
BLOCK_DRAG = 'drag',
|
||||||
|
/** Type of event that records a change in selected element. */
|
||||||
|
SELECTED = 'selected',
|
||||||
|
/** Type of event that records a click. */
|
||||||
|
CLICK = 'click',
|
||||||
|
/** Type of event that records a marker move. */
|
||||||
|
MARKER_MOVE = 'marker_move',
|
||||||
|
/** Type of event that records a bubble open. */
|
||||||
|
BUBBLE_OPEN = 'bubble_open',
|
||||||
|
/** Type of event that records a trashcan open. */
|
||||||
|
TRASHCAN_OPEN = 'trashcan_open',
|
||||||
|
/** Type of event that records a toolbox item select. */
|
||||||
|
TOOLBOX_ITEM_SELECT = 'toolbox_item_select',
|
||||||
|
/** Type of event that records a theme change. */
|
||||||
|
THEME_CHANGE = 'theme_change',
|
||||||
|
/** Type of event that records a viewport change. */
|
||||||
|
VIEWPORT_CHANGE = 'viewport_change',
|
||||||
|
/** Type of event that creates a comment. */
|
||||||
|
COMMENT_CREATE = 'comment_create',
|
||||||
|
/** Type of event that deletes a comment. */
|
||||||
|
COMMENT_DELETE = 'comment_delete',
|
||||||
|
/** Type of event that changes a comment. */
|
||||||
|
COMMENT_CHANGE = 'comment_change',
|
||||||
|
/** Type of event that moves a comment. */
|
||||||
|
COMMENT_MOVE = 'comment_move',
|
||||||
|
/** Type of event that resizes a comment. */
|
||||||
|
COMMENT_RESIZE = 'comment_resize',
|
||||||
|
/** Type of event that drags a comment. */
|
||||||
|
COMMENT_DRAG = 'comment_drag',
|
||||||
|
/** Type of event that collapses a comment. */
|
||||||
|
COMMENT_COLLAPSE = 'comment_collapse',
|
||||||
|
/** Type of event that records a workspace load. */
|
||||||
|
FINISHED_LOADING = 'finished_loading',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of events that cause objects to be bumped back into the visible
|
||||||
|
* portion of the workspace.
|
||||||
|
*
|
||||||
|
* Not to be confused with bumping so that disconnected connections do not
|
||||||
|
* appear connected.
|
||||||
|
*/
|
||||||
|
export const BUMP_EVENTS: string[] = [
|
||||||
|
EventType.BLOCK_CREATE,
|
||||||
|
EventType.BLOCK_MOVE,
|
||||||
|
EventType.COMMENT_CREATE,
|
||||||
|
EventType.COMMENT_MOVE,
|
||||||
|
];
|
||||||
@@ -9,18 +9,24 @@
|
|||||||
import type {Block} from '../block.js';
|
import type {Block} from '../block.js';
|
||||||
import * as common from '../common.js';
|
import * as common from '../common.js';
|
||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
|
import * as deprecation from '../utils/deprecation.js';
|
||||||
import * as idGenerator from '../utils/idgenerator.js';
|
import * as idGenerator from '../utils/idgenerator.js';
|
||||||
import type {Workspace} from '../workspace.js';
|
import type {Workspace} from '../workspace.js';
|
||||||
import type {WorkspaceSvg} from '../workspace_svg.js';
|
import type {WorkspaceSvg} from '../workspace_svg.js';
|
||||||
|
|
||||||
import type {Abstract} from './events_abstract.js';
|
import type {Abstract} from './events_abstract.js';
|
||||||
import type {BlockChange} from './events_block_change.js';
|
|
||||||
import type {BlockCreate} from './events_block_create.js';
|
import type {BlockCreate} from './events_block_create.js';
|
||||||
import type {BlockMove} from './events_block_move.js';
|
import type {BlockMove} from './events_block_move.js';
|
||||||
import type {CommentCreate} from './events_comment_create.js';
|
import type {CommentCreate} from './events_comment_create.js';
|
||||||
import type {CommentMove} from './events_comment_move.js';
|
import type {CommentMove} from './events_comment_move.js';
|
||||||
import type {CommentResize} from './events_comment_resize.js';
|
import type {CommentResize} from './events_comment_resize.js';
|
||||||
import type {ViewportChange} from './events_viewport.js';
|
import {
|
||||||
|
isBlockChange,
|
||||||
|
isBlockCreate,
|
||||||
|
isBlockMove,
|
||||||
|
isBubbleOpen,
|
||||||
|
isClick,
|
||||||
|
isViewportChange,
|
||||||
|
} from './predicates.js';
|
||||||
|
|
||||||
/** Group ID for new events. Grouped events are indivisible. */
|
/** Group ID for new events. Grouped events are indivisible. */
|
||||||
let group = '';
|
let group = '';
|
||||||
@@ -49,157 +55,6 @@ export function getRecordUndo(): boolean {
|
|||||||
/** Allow change events to be created and fired. */
|
/** Allow change events to be created and fired. */
|
||||||
let disabled = 0;
|
let disabled = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that creates a block. Will be deprecated for BLOCK_CREATE.
|
|
||||||
*/
|
|
||||||
export const CREATE = 'create';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that creates a block.
|
|
||||||
*/
|
|
||||||
export const BLOCK_CREATE = CREATE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that deletes a block. Will be deprecated for BLOCK_DELETE.
|
|
||||||
*/
|
|
||||||
export const DELETE = 'delete';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that deletes a block.
|
|
||||||
*/
|
|
||||||
export const BLOCK_DELETE = DELETE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that changes a block. Will be deprecated for BLOCK_CHANGE.
|
|
||||||
*/
|
|
||||||
export const CHANGE = 'change';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that changes a block.
|
|
||||||
*/
|
|
||||||
export const BLOCK_CHANGE = CHANGE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event representing an in-progress change to a field of a block, which
|
|
||||||
* is expected to be followed by a block change event.
|
|
||||||
*/
|
|
||||||
export const BLOCK_FIELD_INTERMEDIATE_CHANGE =
|
|
||||||
'block_field_intermediate_change';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that moves a block. Will be deprecated for BLOCK_MOVE.
|
|
||||||
*/
|
|
||||||
export const MOVE = 'move';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that moves a block.
|
|
||||||
*/
|
|
||||||
export const BLOCK_MOVE = MOVE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that creates a variable.
|
|
||||||
*/
|
|
||||||
export const VAR_CREATE = 'var_create';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that deletes a variable.
|
|
||||||
*/
|
|
||||||
export const VAR_DELETE = 'var_delete';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that renames a variable.
|
|
||||||
*/
|
|
||||||
export const VAR_RENAME = 'var_rename';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that changes a variable's type.
|
|
||||||
*/
|
|
||||||
export const VAR_TYPE_CHANGE = 'var_type_change';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of generic event that records a UI change.
|
|
||||||
*/
|
|
||||||
export const UI = 'ui';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that drags a block.
|
|
||||||
*/
|
|
||||||
export const BLOCK_DRAG = 'drag';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that records a change in selected element.
|
|
||||||
*/
|
|
||||||
export const SELECTED = 'selected';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that records a click.
|
|
||||||
*/
|
|
||||||
export const CLICK = 'click';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that records a marker move.
|
|
||||||
*/
|
|
||||||
export const MARKER_MOVE = 'marker_move';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that records a bubble open.
|
|
||||||
*/
|
|
||||||
export const BUBBLE_OPEN = 'bubble_open';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that records a trashcan open.
|
|
||||||
*/
|
|
||||||
export const TRASHCAN_OPEN = 'trashcan_open';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that records a toolbox item select.
|
|
||||||
*/
|
|
||||||
export const TOOLBOX_ITEM_SELECT = 'toolbox_item_select';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that records a theme change.
|
|
||||||
*/
|
|
||||||
export const THEME_CHANGE = 'theme_change';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that records a viewport change.
|
|
||||||
*/
|
|
||||||
export const VIEWPORT_CHANGE = 'viewport_change';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that creates a comment.
|
|
||||||
*/
|
|
||||||
export const COMMENT_CREATE = 'comment_create';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that deletes a comment.
|
|
||||||
*/
|
|
||||||
export const COMMENT_DELETE = 'comment_delete';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that changes a comment.
|
|
||||||
*/
|
|
||||||
export const COMMENT_CHANGE = 'comment_change';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that moves a comment.
|
|
||||||
*/
|
|
||||||
export const COMMENT_MOVE = 'comment_move';
|
|
||||||
|
|
||||||
/** Name of event that resizes a comment. */
|
|
||||||
export const COMMENT_RESIZE = 'comment_resize';
|
|
||||||
|
|
||||||
/** Name of event that drags a comment. */
|
|
||||||
export const COMMENT_DRAG = 'comment_drag';
|
|
||||||
|
|
||||||
/** Type of event that collapses a comment. */
|
|
||||||
export const COMMENT_COLLAPSE = 'comment_collapse';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of event that records a workspace load.
|
|
||||||
*/
|
|
||||||
export const FINISHED_LOADING = 'finished_loading';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The language-neutral ID for when the reason why a block is disabled is
|
* The language-neutral ID for when the reason why a block is disabled is
|
||||||
* because the block is not descended from a root block.
|
* because the block is not descended from a root block.
|
||||||
@@ -220,27 +75,24 @@ export type BumpEvent =
|
|||||||
| CommentMove
|
| CommentMove
|
||||||
| CommentResize;
|
| CommentResize;
|
||||||
|
|
||||||
/**
|
|
||||||
* List of events that cause objects to be bumped back into the visible
|
|
||||||
* portion of the workspace.
|
|
||||||
*
|
|
||||||
* Not to be confused with bumping so that disconnected connections do not
|
|
||||||
* appear connected.
|
|
||||||
*/
|
|
||||||
export const BUMP_EVENTS: string[] = [
|
|
||||||
BLOCK_CREATE,
|
|
||||||
BLOCK_MOVE,
|
|
||||||
COMMENT_CREATE,
|
|
||||||
COMMENT_MOVE,
|
|
||||||
];
|
|
||||||
|
|
||||||
/** List of events queued for firing. */
|
/** List of events queued for firing. */
|
||||||
const FIRE_QUEUE: Abstract[] = [];
|
const FIRE_QUEUE: Abstract[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a custom event and fire it.
|
* Enqueue an event to be dispatched to change listeners.
|
||||||
*
|
*
|
||||||
* @param event Custom data for event.
|
* Notes:
|
||||||
|
*
|
||||||
|
* - Events are enqueued until a timeout, generally after rendering is
|
||||||
|
* complete or at the end of the current microtask, if not running
|
||||||
|
* in a browser.
|
||||||
|
* - Queued events are subject to destructive modification by being
|
||||||
|
* combined with later-enqueued events, but only until they are
|
||||||
|
* fired.
|
||||||
|
* - Events are dispatched via the fireChangeListener method on the
|
||||||
|
* affected workspace.
|
||||||
|
*
|
||||||
|
* @param event Any Blockly event.
|
||||||
*/
|
*/
|
||||||
export function fire(event: Abstract) {
|
export function fire(event: Abstract) {
|
||||||
TEST_ONLY.fireInternal(event);
|
TEST_ONLY.fireInternal(event);
|
||||||
@@ -261,166 +113,187 @@ function fireInternal(event: Abstract) {
|
|||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
setTimeout(fireNow, 0);
|
setTimeout(fireNow, 0);
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch {
|
||||||
// Otherwise we just want to delay so events can be coallesced.
|
// Otherwise we just want to delay so events can be coallesced.
|
||||||
// requestAnimationFrame will error triggering this.
|
// requestAnimationFrame will error triggering this.
|
||||||
setTimeout(fireNow, 0);
|
setTimeout(fireNow, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FIRE_QUEUE.push(event);
|
enqueueEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Fire all queued events. */
|
/** Dispatch all queued events. */
|
||||||
function fireNow() {
|
function fireNow() {
|
||||||
const queue = filter(FIRE_QUEUE, true);
|
const queue = filter(FIRE_QUEUE, true);
|
||||||
FIRE_QUEUE.length = 0;
|
FIRE_QUEUE.length = 0;
|
||||||
for (let i = 0, event; (event = queue[i]); i++) {
|
for (const event of queue) {
|
||||||
if (!event.workspaceId) {
|
if (!event.workspaceId) continue;
|
||||||
continue;
|
common.getWorkspaceById(event.workspaceId)?.fireChangeListener(event);
|
||||||
}
|
|
||||||
const eventWorkspace = common.getWorkspaceById(event.workspaceId);
|
|
||||||
if (eventWorkspace) {
|
|
||||||
eventWorkspace.fireChangeListener(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Post-filter the undo stack to squash and remove any events that result in
|
|
||||||
// a null event
|
|
||||||
|
|
||||||
// 1. Determine which workspaces will need to have their undo stacks validated
|
|
||||||
const workspaceIds = new Set(queue.map((e) => e.workspaceId));
|
|
||||||
for (const workspaceId of workspaceIds) {
|
|
||||||
// Only process valid workspaces
|
|
||||||
if (!workspaceId) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const eventWorkspace = common.getWorkspaceById(workspaceId);
|
|
||||||
if (!eventWorkspace) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the last contiguous group of events on the stack
|
|
||||||
const undoStack = eventWorkspace.getUndoStack();
|
|
||||||
let i;
|
|
||||||
let group: string | undefined = undefined;
|
|
||||||
for (i = undoStack.length; i > 0; i--) {
|
|
||||||
const event = undoStack[i - 1];
|
|
||||||
if (event.group === '') {
|
|
||||||
break;
|
|
||||||
} else if (group === undefined) {
|
|
||||||
group = event.group;
|
|
||||||
} else if (event.group !== group) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!group || i == undoStack.length - 1) {
|
|
||||||
// Need a group of two or more events on the stack. Nothing to do here.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract the event group, filter, and add back to the undo stack
|
|
||||||
let events = undoStack.splice(i, undoStack.length - i);
|
|
||||||
events = filter(events, true);
|
|
||||||
undoStack.push(...events);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter the queued events and merge duplicates.
|
* Enqueue an event on FIRE_QUEUE.
|
||||||
*
|
*
|
||||||
* @param queueIn Array of events.
|
* Normally this is equivalent to FIRE_QUEUE.push(event), but if the
|
||||||
|
* enqueued event is a BlockChange event and the most recent event(s)
|
||||||
|
* on the queue are BlockMove events that (re)connect other blocks to
|
||||||
|
* the changed block (and belong to the same event group) then the
|
||||||
|
* enqueued event will be enqueued before those events rather than
|
||||||
|
* after.
|
||||||
|
*
|
||||||
|
* This is a workaround for a problem caused by the fact that
|
||||||
|
* MutatorIcon.prototype.recomposeSourceBlock can only fire a
|
||||||
|
* BlockChange event after the mutating block's compose method
|
||||||
|
* returns, meaning that if the compose method reconnects child blocks
|
||||||
|
* the corresponding BlockMove events are emitted _before_ the
|
||||||
|
* BlockChange event, causing issues with undo, mirroring, etc.; see
|
||||||
|
* https://github.com/google/blockly/issues/8225#issuecomment-2195751783
|
||||||
|
* (and following) for details.
|
||||||
|
*/
|
||||||
|
function enqueueEvent(event: Abstract) {
|
||||||
|
if (isBlockChange(event) && event.element === 'mutation') {
|
||||||
|
let i;
|
||||||
|
for (i = FIRE_QUEUE.length; i > 0; i--) {
|
||||||
|
const otherEvent = FIRE_QUEUE[i - 1];
|
||||||
|
if (
|
||||||
|
otherEvent.group !== event.group ||
|
||||||
|
otherEvent.workspaceId !== event.workspaceId ||
|
||||||
|
!isBlockMove(otherEvent) ||
|
||||||
|
otherEvent.newParentId !== event.blockId
|
||||||
|
) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FIRE_QUEUE.splice(i, 0, event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FIRE_QUEUE.push(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter the queued events by merging duplicates, removing null
|
||||||
|
* events and reording BlockChange events.
|
||||||
|
*
|
||||||
|
* History of this function:
|
||||||
|
*
|
||||||
|
* This function was originally added in commit cf257ea5 with the
|
||||||
|
* intention of dramatically reduing the total number of dispatched
|
||||||
|
* events. Initialy it affected only BlockMove events but others were
|
||||||
|
* added over time.
|
||||||
|
*
|
||||||
|
* Code was added to reorder BlockChange events added in commit
|
||||||
|
* 5578458, for uncertain reasons but most probably as part of an
|
||||||
|
* only-partially-successful attemp to fix problems with event
|
||||||
|
* ordering during block mutations. This code should probably have
|
||||||
|
* been added to the top of the function, before merging and
|
||||||
|
* null-removal, but was added at the bottom for now-forgotten
|
||||||
|
* reasons. See these bug investigations for a fuller discussion of
|
||||||
|
* the underlying issue and some of the failures that arose because of
|
||||||
|
* this incomplete/incorrect fix:
|
||||||
|
*
|
||||||
|
* https://github.com/google/blockly/issues/8225#issuecomment-2195751783
|
||||||
|
* https://github.com/google/blockly/issues/2037#issuecomment-2209696351
|
||||||
|
*
|
||||||
|
* Later, in PR #1205 the original O(n^2) implementation was replaced
|
||||||
|
* by a linear-time implementation, though additonal fixes were made
|
||||||
|
* subsequently.
|
||||||
|
*
|
||||||
|
* In August 2024 a number of significant simplifications were made:
|
||||||
|
*
|
||||||
|
* This function was previously called from Workspace.prototype.undo,
|
||||||
|
* but the mutation of events by this function was the cause of issue
|
||||||
|
* #7026 (note that events would combine differently in reverse order
|
||||||
|
* vs. forward order). The originally-chosen fix for this was the
|
||||||
|
* addition (in PR #7069) of code to fireNow to post-filter the
|
||||||
|
* .undoStack_ and .redoStack_ of any workspace that had just been
|
||||||
|
* involved in dispatching events; this apparently resolved the issue
|
||||||
|
* but added considerable additional complexity and made it difficult
|
||||||
|
* to reason about how events are processed for undo/redo, so both the
|
||||||
|
* call from undo and the post-processing code was removed, and
|
||||||
|
* forward=true was made the default while calling the function with
|
||||||
|
* forward=false was deprecated.
|
||||||
|
*
|
||||||
|
* At the same time, the buggy code to reorder BlockChange events was
|
||||||
|
* replaced by a less-buggy version of the same functionality in a new
|
||||||
|
* function, enqueueEvent, called from fireInternal, thus assuring
|
||||||
|
* that events will be in the correct order at the time filter is
|
||||||
|
* called.
|
||||||
|
*
|
||||||
|
* Additionally, the event merging code was modified so that only
|
||||||
|
* immediately adjacent events would be merged. This simplified the
|
||||||
|
* implementation while ensuring that the merging of events cannot
|
||||||
|
* cause them to be reordered.
|
||||||
|
*
|
||||||
|
* @param queue Array of events.
|
||||||
* @param forward True if forward (redo), false if backward (undo).
|
* @param forward True if forward (redo), false if backward (undo).
|
||||||
|
* This parameter is deprecated: true is now the default and
|
||||||
|
* calling filter with it set to false will in future not be
|
||||||
|
* supported.
|
||||||
* @returns Array of filtered events.
|
* @returns Array of filtered events.
|
||||||
*/
|
*/
|
||||||
export function filter(queueIn: Abstract[], forward: boolean): Abstract[] {
|
export function filter(queue: Abstract[], forward = true): Abstract[] {
|
||||||
let queue = queueIn.slice();
|
|
||||||
// Shallow copy of queue.
|
|
||||||
if (!forward) {
|
if (!forward) {
|
||||||
// Undo is merged in reverse order.
|
deprecation.warn('filter(queue, /*forward=*/false)', 'v11.2', 'v12');
|
||||||
queue.reverse();
|
// Undo was merged in reverse order.
|
||||||
|
queue = queue.slice().reverse(); // Copy before reversing in place.
|
||||||
}
|
}
|
||||||
const mergedQueue = [];
|
const mergedQueue: Abstract[] = [];
|
||||||
const hash = Object.create(null);
|
|
||||||
// Merge duplicates.
|
// Merge duplicates.
|
||||||
for (let i = 0, event; (event = queue[i]); i++) {
|
for (const event of queue) {
|
||||||
if (!event.isNull()) {
|
const lastEvent = mergedQueue[mergedQueue.length - 1];
|
||||||
// Treat all UI events as the same type in hash table.
|
if (event.isNull()) continue;
|
||||||
const eventType = event.isUiEvent ? UI : event.type;
|
if (
|
||||||
// TODO(#5927): Check whether `blockId` exists before accessing it.
|
!lastEvent ||
|
||||||
const blockId = (event as AnyDuringMigration).blockId;
|
lastEvent.workspaceId !== event.workspaceId ||
|
||||||
const key = [eventType, blockId, event.workspaceId].join(' ');
|
lastEvent.group !== event.group
|
||||||
|
) {
|
||||||
const lastEntry = hash[key];
|
mergedQueue.push(event);
|
||||||
const lastEvent = lastEntry ? lastEntry.event : null;
|
continue;
|
||||||
if (!lastEntry) {
|
}
|
||||||
// Each item in the hash table has the event and the index of that event
|
if (
|
||||||
// in the input array. This lets us make sure we only merge adjacent
|
isBlockMove(event) &&
|
||||||
// move events.
|
isBlockMove(lastEvent) &&
|
||||||
hash[key] = {event, index: i};
|
event.blockId === lastEvent.blockId
|
||||||
mergedQueue.push(event);
|
) {
|
||||||
} else if (event.type === MOVE && lastEntry.index === i - 1) {
|
// Merge move events.
|
||||||
const moveEvent = event as BlockMove;
|
lastEvent.newParentId = event.newParentId;
|
||||||
// Merge move events.
|
lastEvent.newInputName = event.newInputName;
|
||||||
lastEvent.newParentId = moveEvent.newParentId;
|
lastEvent.newCoordinate = event.newCoordinate;
|
||||||
lastEvent.newInputName = moveEvent.newInputName;
|
// Concatenate reasons without duplicates.
|
||||||
lastEvent.newCoordinate = moveEvent.newCoordinate;
|
if (lastEvent.reason || event.reason) {
|
||||||
if (moveEvent.reason) {
|
lastEvent.reason = Array.from(
|
||||||
if (lastEvent.reason) {
|
new Set((lastEvent.reason ?? []).concat(event.reason ?? [])),
|
||||||
// Concatenate reasons without duplicates.
|
);
|
||||||
const reasonSet = new Set(
|
|
||||||
moveEvent.reason.concat(lastEvent.reason),
|
|
||||||
);
|
|
||||||
lastEvent.reason = Array.from(reasonSet);
|
|
||||||
} else {
|
|
||||||
lastEvent.reason = moveEvent.reason;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastEntry.index = i;
|
|
||||||
} else if (
|
|
||||||
event.type === CHANGE &&
|
|
||||||
(event as BlockChange).element === lastEvent.element &&
|
|
||||||
(event as BlockChange).name === lastEvent.name
|
|
||||||
) {
|
|
||||||
const changeEvent = event as BlockChange;
|
|
||||||
// Merge change events.
|
|
||||||
lastEvent.newValue = changeEvent.newValue;
|
|
||||||
} else if (event.type === VIEWPORT_CHANGE) {
|
|
||||||
const viewportEvent = event as ViewportChange;
|
|
||||||
// Merge viewport change events.
|
|
||||||
lastEvent.viewTop = viewportEvent.viewTop;
|
|
||||||
lastEvent.viewLeft = viewportEvent.viewLeft;
|
|
||||||
lastEvent.scale = viewportEvent.scale;
|
|
||||||
lastEvent.oldScale = viewportEvent.oldScale;
|
|
||||||
} else if (event.type === CLICK && lastEvent.type === BUBBLE_OPEN) {
|
|
||||||
// Drop click events caused by opening/closing bubbles.
|
|
||||||
} else {
|
|
||||||
// Collision: newer events should merge into this event to maintain
|
|
||||||
// order.
|
|
||||||
hash[key] = {event, index: i};
|
|
||||||
mergedQueue.push(event);
|
|
||||||
}
|
}
|
||||||
|
} else if (
|
||||||
|
isBlockChange(event) &&
|
||||||
|
isBlockChange(lastEvent) &&
|
||||||
|
event.blockId === lastEvent.blockId &&
|
||||||
|
event.element === lastEvent.element &&
|
||||||
|
event.name === lastEvent.name
|
||||||
|
) {
|
||||||
|
// Merge change events.
|
||||||
|
lastEvent.newValue = event.newValue;
|
||||||
|
} else if (isViewportChange(event) && isViewportChange(lastEvent)) {
|
||||||
|
// Merge viewport change events.
|
||||||
|
lastEvent.viewTop = event.viewTop;
|
||||||
|
lastEvent.viewLeft = event.viewLeft;
|
||||||
|
lastEvent.scale = event.scale;
|
||||||
|
lastEvent.oldScale = event.oldScale;
|
||||||
|
} else if (isClick(event) && isBubbleOpen(lastEvent)) {
|
||||||
|
// Drop click events caused by opening/closing bubbles.
|
||||||
|
} else {
|
||||||
|
mergedQueue.push(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Filter out any events that have become null due to merging.
|
// Filter out any events that have become null due to merging.
|
||||||
queue = mergedQueue.filter(function (e) {
|
queue = mergedQueue.filter((e) => !e.isNull());
|
||||||
return !e.isNull();
|
|
||||||
});
|
|
||||||
if (!forward) {
|
if (!forward) {
|
||||||
// Restore undo order.
|
// Restore undo order.
|
||||||
queue.reverse();
|
queue.reverse();
|
||||||
}
|
}
|
||||||
// Move mutation events to the top of the queue.
|
|
||||||
// Intentionally skip first event.
|
|
||||||
for (let i = 1, event; (event = queue[i]); i++) {
|
|
||||||
// AnyDuringMigration because: Property 'element' does not exist on type
|
|
||||||
// 'Abstract'.
|
|
||||||
if (
|
|
||||||
event.type === CHANGE &&
|
|
||||||
(event as AnyDuringMigration).element === 'mutation'
|
|
||||||
) {
|
|
||||||
queue.unshift(queue.splice(i, 1)[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return queue;
|
return queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -545,7 +418,7 @@ export function get(
|
|||||||
* @param event Custom data for event.
|
* @param event Custom data for event.
|
||||||
*/
|
*/
|
||||||
export function disableOrphans(event: Abstract) {
|
export function disableOrphans(event: Abstract) {
|
||||||
if (event.type === MOVE || event.type === CREATE) {
|
if (isBlockMove(event) || isBlockCreate(event)) {
|
||||||
const blockEvent = event as BlockMove | BlockCreate;
|
const blockEvent = event as BlockMove | BlockCreate;
|
||||||
if (!blockEvent.workspaceId) {
|
if (!blockEvent.workspaceId) {
|
||||||
return;
|
return;
|
||||||
@@ -589,6 +462,7 @@ export function disableOrphans(event: Abstract) {
|
|||||||
|
|
||||||
export const TEST_ONLY = {
|
export const TEST_ONLY = {
|
||||||
FIRE_QUEUE,
|
FIRE_QUEUE,
|
||||||
|
enqueueEvent,
|
||||||
fireNow,
|
fireNow,
|
||||||
fireInternal,
|
fireInternal,
|
||||||
setGroupInternal,
|
setGroupInternal,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
import * as registry from '../registry.js';
|
import * as registry from '../registry.js';
|
||||||
import type {Workspace} from '../workspace.js';
|
import type {Workspace} from '../workspace.js';
|
||||||
import {Abstract as AbstractEvent} from './events_abstract.js';
|
import {Abstract as AbstractEvent} from './events_abstract.js';
|
||||||
import * as eventUtils from './utils.js';
|
import {EventType} from './type.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies listeners when the workspace has finished deserializing from
|
* Notifies listeners when the workspace has finished deserializing from
|
||||||
@@ -23,7 +23,7 @@ import * as eventUtils from './utils.js';
|
|||||||
export class FinishedLoading extends AbstractEvent {
|
export class FinishedLoading extends AbstractEvent {
|
||||||
override isBlank = true;
|
override isBlank = true;
|
||||||
override recordUndo = false;
|
override recordUndo = false;
|
||||||
override type = eventUtils.FINISHED_LOADING;
|
override type = EventType.FINISHED_LOADING;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param opt_workspace The workspace that has finished loading. Undefined
|
* @param opt_workspace The workspace that has finished loading. Undefined
|
||||||
@@ -41,6 +41,6 @@ export class FinishedLoading extends AbstractEvent {
|
|||||||
|
|
||||||
registry.register(
|
registry.register(
|
||||||
registry.Type.EVENT,
|
registry.Type.EVENT,
|
||||||
eventUtils.FINISHED_LOADING,
|
EventType.FINISHED_LOADING,
|
||||||
FinishedLoading,
|
FinishedLoading,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -27,7 +27,10 @@ export const TEST_ONLY = {allExtensions};
|
|||||||
* @throws {Error} if the extension name is empty, the extension is already
|
* @throws {Error} if the extension name is empty, the extension is already
|
||||||
* registered, or extensionFn is not a function.
|
* registered, or extensionFn is not a function.
|
||||||
*/
|
*/
|
||||||
export function register(name: string, initFn: Function) {
|
export function register<T extends Block>(
|
||||||
|
name: string,
|
||||||
|
initFn: (this: T) => void,
|
||||||
|
) {
|
||||||
if (typeof name !== 'string' || name.trim() === '') {
|
if (typeof name !== 'string' || name.trim() === '') {
|
||||||
throw Error('Error: Invalid extension name "' + name + '"');
|
throw Error('Error: Invalid extension name "' + name + '"');
|
||||||
}
|
}
|
||||||
|
|||||||
142
core/field.ts
142
core/field.ts
@@ -20,12 +20,14 @@ import type {Block} from './block.js';
|
|||||||
import type {BlockSvg} from './block_svg.js';
|
import type {BlockSvg} from './block_svg.js';
|
||||||
import * as browserEvents from './browser_events.js';
|
import * as browserEvents from './browser_events.js';
|
||||||
import * as dropDownDiv from './dropdowndiv.js';
|
import * as dropDownDiv from './dropdowndiv.js';
|
||||||
|
import {EventType} from './events/type.js';
|
||||||
import * as eventUtils from './events/utils.js';
|
import * as eventUtils from './events/utils.js';
|
||||||
import type {Input} from './inputs/input.js';
|
import type {Input} from './inputs/input.js';
|
||||||
import type {IASTNodeLocationSvg} from './interfaces/i_ast_node_location_svg.js';
|
import type {IASTNodeLocationSvg} from './interfaces/i_ast_node_location_svg.js';
|
||||||
import type {IASTNodeLocationWithBlock} from './interfaces/i_ast_node_location_with_block.js';
|
import type {IASTNodeLocationWithBlock} from './interfaces/i_ast_node_location_with_block.js';
|
||||||
import type {IKeyboardAccessible} from './interfaces/i_keyboard_accessible.js';
|
import type {IKeyboardAccessible} from './interfaces/i_keyboard_accessible.js';
|
||||||
import type {IRegistrable} from './interfaces/i_registrable.js';
|
import type {IRegistrable} from './interfaces/i_registrable.js';
|
||||||
|
import {ISerializable} from './interfaces/i_serializable.js';
|
||||||
import {MarkerManager} from './marker_manager.js';
|
import {MarkerManager} from './marker_manager.js';
|
||||||
import type {ConstantProvider} from './renderers/common/constants.js';
|
import type {ConstantProvider} from './renderers/common/constants.js';
|
||||||
import type {KeyboardShortcut} from './shortcut_registry.js';
|
import type {KeyboardShortcut} from './shortcut_registry.js';
|
||||||
@@ -41,7 +43,6 @@ import * as userAgent from './utils/useragent.js';
|
|||||||
import * as utilsXml from './utils/xml.js';
|
import * as utilsXml from './utils/xml.js';
|
||||||
import * as WidgetDiv from './widgetdiv.js';
|
import * as WidgetDiv from './widgetdiv.js';
|
||||||
import type {WorkspaceSvg} from './workspace_svg.js';
|
import type {WorkspaceSvg} from './workspace_svg.js';
|
||||||
import {ISerializable} from './interfaces/i_serializable.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function that is called to validate changes to the field's value before
|
* A function that is called to validate changes to the field's value before
|
||||||
@@ -106,20 +107,20 @@ export abstract class Field<T = any>
|
|||||||
* Used to cache the field's tooltip value if setTooltip is called when the
|
* Used to cache the field's tooltip value if setTooltip is called when the
|
||||||
* field is not yet initialized. Is *not* guaranteed to be accurate.
|
* field is not yet initialized. Is *not* guaranteed to be accurate.
|
||||||
*/
|
*/
|
||||||
private tooltip_: Tooltip.TipInfo | null = null;
|
private tooltip: Tooltip.TipInfo | null = null;
|
||||||
protected size_: Size;
|
protected size_: Size;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the cursors svg element when the cursor is attached to the field.
|
* Holds the cursors svg element when the cursor is attached to the field.
|
||||||
* This is null if there is no cursor on the field.
|
* This is null if there is no cursor on the field.
|
||||||
*/
|
*/
|
||||||
private cursorSvg_: SVGElement | null = null;
|
private cursorSvg: SVGElement | null = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the markers svg element when the marker is attached to the field.
|
* Holds the markers svg element when the marker is attached to the field.
|
||||||
* This is null if there is no marker on the field.
|
* This is null if there is no marker on the field.
|
||||||
*/
|
*/
|
||||||
private markerSvg_: SVGElement | null = null;
|
private markerSvg: SVGElement | null = null;
|
||||||
|
|
||||||
/** The rendered field's SVG group element. */
|
/** The rendered field's SVG group element. */
|
||||||
protected fieldGroup_: SVGGElement | null = null;
|
protected fieldGroup_: SVGGElement | null = null;
|
||||||
@@ -134,7 +135,7 @@ export abstract class Field<T = any>
|
|||||||
protected textContent_: Text | null = null;
|
protected textContent_: Text | null = null;
|
||||||
|
|
||||||
/** Mouse down event listener data. */
|
/** Mouse down event listener data. */
|
||||||
private mouseDownWrapper_: browserEvents.Data | null = null;
|
private mouseDownWrapper: browserEvents.Data | null = null;
|
||||||
|
|
||||||
/** Constants associated with the source block's renderer. */
|
/** Constants associated with the source block's renderer. */
|
||||||
protected constants_: ConstantProvider | null = null;
|
protected constants_: ConstantProvider | null = null;
|
||||||
@@ -308,7 +309,7 @@ export abstract class Field<T = any>
|
|||||||
sourceBlockSvg.getSvgRoot().appendChild(this.fieldGroup_);
|
sourceBlockSvg.getSvgRoot().appendChild(this.fieldGroup_);
|
||||||
this.initView();
|
this.initView();
|
||||||
this.updateEditable();
|
this.updateEditable();
|
||||||
this.setTooltip(this.tooltip_);
|
this.setTooltip(this.tooltip);
|
||||||
this.bindEvents_();
|
this.bindEvents_();
|
||||||
this.initModel();
|
this.initModel();
|
||||||
this.applyColour();
|
this.applyColour();
|
||||||
@@ -392,7 +393,7 @@ export abstract class Field<T = any>
|
|||||||
const clickTarget = this.getClickTarget_();
|
const clickTarget = this.getClickTarget_();
|
||||||
if (!clickTarget) throw new Error('A click target has not been set.');
|
if (!clickTarget) throw new Error('A click target has not been set.');
|
||||||
Tooltip.bindMouseEvents(clickTarget);
|
Tooltip.bindMouseEvents(clickTarget);
|
||||||
this.mouseDownWrapper_ = browserEvents.conditionalBind(
|
this.mouseDownWrapper = browserEvents.conditionalBind(
|
||||||
clickTarget,
|
clickTarget,
|
||||||
'pointerdown',
|
'pointerdown',
|
||||||
this,
|
this,
|
||||||
@@ -1065,62 +1066,73 @@ export abstract class Field<T = any>
|
|||||||
setValue(newValue: AnyDuringMigration, fireChangeEvent = true) {
|
setValue(newValue: AnyDuringMigration, fireChangeEvent = true) {
|
||||||
const doLogging = false;
|
const doLogging = false;
|
||||||
if (newValue === null) {
|
if (newValue === null) {
|
||||||
doLogging && console.log('null, return');
|
if (doLogging) console.log('null, return');
|
||||||
// Not a valid value to check.
|
// Not a valid value to check.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const classValidation = this.doClassValidation_(newValue);
|
// Field validators are allowed to make changes to the workspace, which
|
||||||
const classValue = this.processValidation_(
|
// should get grouped with the field value change event.
|
||||||
newValue,
|
const existingGroup = eventUtils.getGroup();
|
||||||
classValidation,
|
if (!existingGroup) {
|
||||||
fireChangeEvent,
|
eventUtils.setGroup(true);
|
||||||
);
|
|
||||||
if (classValue instanceof Error) {
|
|
||||||
doLogging && console.log('invalid class validation, return');
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const localValidation = this.getValidator()?.call(this, classValue);
|
try {
|
||||||
const localValue = this.processValidation_(
|
const classValidation = this.doClassValidation_(newValue);
|
||||||
classValue,
|
const classValue = this.processValidation(
|
||||||
localValidation,
|
newValue,
|
||||||
fireChangeEvent,
|
classValidation,
|
||||||
);
|
fireChangeEvent,
|
||||||
if (localValue instanceof Error) {
|
|
||||||
doLogging && console.log('invalid local validation, return');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const source = this.sourceBlock_;
|
|
||||||
if (source && source.disposed) {
|
|
||||||
doLogging && console.log('source disposed, return');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const oldValue = this.getValue();
|
|
||||||
if (oldValue === localValue) {
|
|
||||||
doLogging && console.log('same, doValueUpdate_, return');
|
|
||||||
this.doValueUpdate_(localValue);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.doValueUpdate_(localValue);
|
|
||||||
if (fireChangeEvent && source && eventUtils.isEnabled()) {
|
|
||||||
eventUtils.fire(
|
|
||||||
new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
|
|
||||||
source,
|
|
||||||
'field',
|
|
||||||
this.name || null,
|
|
||||||
oldValue,
|
|
||||||
localValue,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
if (classValue instanceof Error) {
|
||||||
|
if (doLogging) console.log('invalid class validation, return');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const localValidation = this.getValidator()?.call(this, classValue);
|
||||||
|
const localValue = this.processValidation(
|
||||||
|
classValue,
|
||||||
|
localValidation,
|
||||||
|
fireChangeEvent,
|
||||||
|
);
|
||||||
|
if (localValue instanceof Error) {
|
||||||
|
if (doLogging) console.log('invalid local validation, return');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const source = this.sourceBlock_;
|
||||||
|
if (source && source.disposed) {
|
||||||
|
if (doLogging) console.log('source disposed, return');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldValue = this.getValue();
|
||||||
|
if (oldValue === localValue) {
|
||||||
|
if (doLogging) console.log('same, doValueUpdate_, return');
|
||||||
|
this.doValueUpdate_(localValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.doValueUpdate_(localValue);
|
||||||
|
if (fireChangeEvent && source && eventUtils.isEnabled()) {
|
||||||
|
eventUtils.fire(
|
||||||
|
new (eventUtils.get(EventType.BLOCK_CHANGE))(
|
||||||
|
source,
|
||||||
|
'field',
|
||||||
|
this.name || null,
|
||||||
|
oldValue,
|
||||||
|
localValue,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (this.isDirty_) {
|
||||||
|
this.forceRerender();
|
||||||
|
}
|
||||||
|
if (doLogging) console.log(this.value_);
|
||||||
|
} finally {
|
||||||
|
eventUtils.setGroup(existingGroup);
|
||||||
}
|
}
|
||||||
if (this.isDirty_) {
|
|
||||||
this.forceRerender();
|
|
||||||
}
|
|
||||||
doLogging && console.log(this.value_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1131,7 +1143,7 @@ export abstract class Field<T = any>
|
|||||||
* @param fireChangeEvent Whether to fire a change event if the value changes.
|
* @param fireChangeEvent Whether to fire a change event if the value changes.
|
||||||
* @returns New value, or an Error object.
|
* @returns New value, or an Error object.
|
||||||
*/
|
*/
|
||||||
private processValidation_(
|
private processValidation(
|
||||||
newValue: AnyDuringMigration,
|
newValue: AnyDuringMigration,
|
||||||
validatedValue: T | null | undefined,
|
validatedValue: T | null | undefined,
|
||||||
fireChangeEvent: boolean,
|
fireChangeEvent: boolean,
|
||||||
@@ -1245,7 +1257,7 @@ export abstract class Field<T = any>
|
|||||||
(clickTarget as AnyDuringMigration).tooltip = newTip;
|
(clickTarget as AnyDuringMigration).tooltip = newTip;
|
||||||
} else {
|
} else {
|
||||||
// Field has not been initialized yet.
|
// Field has not been initialized yet.
|
||||||
this.tooltip_ = newTip;
|
this.tooltip = newTip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1259,8 +1271,8 @@ export abstract class Field<T = any>
|
|||||||
if (clickTarget) {
|
if (clickTarget) {
|
||||||
return Tooltip.getTooltipOfObject(clickTarget);
|
return Tooltip.getTooltipOfObject(clickTarget);
|
||||||
}
|
}
|
||||||
// Field has not been initialized yet. Return stashed this.tooltip_ value.
|
// Field has not been initialized yet. Return stashed this.tooltip value.
|
||||||
return Tooltip.getTooltipOfObject({tooltip: this.tooltip_});
|
return Tooltip.getTooltipOfObject({tooltip: this.tooltip});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1366,7 +1378,7 @@ export abstract class Field<T = any>
|
|||||||
*/
|
*/
|
||||||
setCursorSvg(cursorSvg: SVGElement) {
|
setCursorSvg(cursorSvg: SVGElement) {
|
||||||
if (!cursorSvg) {
|
if (!cursorSvg) {
|
||||||
this.cursorSvg_ = null;
|
this.cursorSvg = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1374,7 +1386,7 @@ export abstract class Field<T = any>
|
|||||||
throw new Error(`The field group is ${this.fieldGroup_}.`);
|
throw new Error(`The field group is ${this.fieldGroup_}.`);
|
||||||
}
|
}
|
||||||
this.fieldGroup_.appendChild(cursorSvg);
|
this.fieldGroup_.appendChild(cursorSvg);
|
||||||
this.cursorSvg_ = cursorSvg;
|
this.cursorSvg = cursorSvg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1385,7 +1397,7 @@ export abstract class Field<T = any>
|
|||||||
*/
|
*/
|
||||||
setMarkerSvg(markerSvg: SVGElement) {
|
setMarkerSvg(markerSvg: SVGElement) {
|
||||||
if (!markerSvg) {
|
if (!markerSvg) {
|
||||||
this.markerSvg_ = null;
|
this.markerSvg = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1393,7 +1405,7 @@ export abstract class Field<T = any>
|
|||||||
throw new Error(`The field group is ${this.fieldGroup_}.`);
|
throw new Error(`The field group is ${this.fieldGroup_}.`);
|
||||||
}
|
}
|
||||||
this.fieldGroup_.appendChild(markerSvg);
|
this.fieldGroup_.appendChild(markerSvg);
|
||||||
this.markerSvg_ = markerSvg;
|
this.markerSvg = markerSvg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1407,10 +1419,10 @@ export abstract class Field<T = any>
|
|||||||
throw new UnattachedFieldError();
|
throw new UnattachedFieldError();
|
||||||
}
|
}
|
||||||
const workspace = block.workspace as WorkspaceSvg;
|
const workspace = block.workspace as WorkspaceSvg;
|
||||||
if (workspace.keyboardAccessibilityMode && this.cursorSvg_) {
|
if (workspace.keyboardAccessibilityMode && this.cursorSvg) {
|
||||||
workspace.getCursor()!.draw();
|
workspace.getCursor()!.draw();
|
||||||
}
|
}
|
||||||
if (workspace.keyboardAccessibilityMode && this.markerSvg_) {
|
if (workspace.keyboardAccessibilityMode && this.markerSvg) {
|
||||||
// TODO(#4592): Update all markers on the field.
|
// TODO(#4592): Update all markers on the field.
|
||||||
workspace.getMarker(MarkerManager.LOCAL_MARKER)!.draw();
|
workspace.getMarker(MarkerManager.LOCAL_MARKER)!.draw();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,9 @@
|
|||||||
// Unused import preserved for side-effects. Remove if unneeded.
|
// Unused import preserved for side-effects. Remove if unneeded.
|
||||||
import './events/events_block_change.js';
|
import './events/events_block_change.js';
|
||||||
|
|
||||||
import * as dom from './utils/dom.js';
|
|
||||||
import {Field, FieldConfig, FieldValidator} from './field.js';
|
import {Field, FieldConfig, FieldValidator} from './field.js';
|
||||||
import * as fieldRegistry from './field_registry.js';
|
import * as fieldRegistry from './field_registry.js';
|
||||||
|
import * as dom from './utils/dom.js';
|
||||||
|
|
||||||
type BoolString = 'TRUE' | 'FALSE';
|
type BoolString = 'TRUE' | 'FALSE';
|
||||||
type CheckboxBool = BoolString | boolean;
|
type CheckboxBool = BoolString | boolean;
|
||||||
@@ -165,7 +165,7 @@ export class FieldCheckbox extends Field<CheckboxBool> {
|
|||||||
* that this is a either 'TRUE' or 'FALSE'.
|
* that this is a either 'TRUE' or 'FALSE'.
|
||||||
*/
|
*/
|
||||||
protected override doValueUpdate_(newValue: BoolString) {
|
protected override doValueUpdate_(newValue: BoolString) {
|
||||||
this.value_ = this.convertValueToBool_(newValue);
|
this.value_ = this.convertValueToBool(newValue);
|
||||||
// Update visual.
|
// Update visual.
|
||||||
if (this.textElement_) {
|
if (this.textElement_) {
|
||||||
this.textElement_.style.display = this.value_ ? 'block' : 'none';
|
this.textElement_.style.display = this.value_ ? 'block' : 'none';
|
||||||
@@ -196,7 +196,7 @@ export class FieldCheckbox extends Field<CheckboxBool> {
|
|||||||
* @returns Text representing the value of this field ('true' or 'false').
|
* @returns Text representing the value of this field ('true' or 'false').
|
||||||
*/
|
*/
|
||||||
override getText(): string {
|
override getText(): string {
|
||||||
return String(this.convertValueToBool_(this.value_));
|
return String(this.convertValueToBool(this.value_));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -208,7 +208,7 @@ export class FieldCheckbox extends Field<CheckboxBool> {
|
|||||||
* @param value The value to convert.
|
* @param value The value to convert.
|
||||||
* @returns The converted value.
|
* @returns The converted value.
|
||||||
*/
|
*/
|
||||||
private convertValueToBool_(value: CheckboxBool | null): boolean {
|
private convertValueToBool(value: CheckboxBool | null): boolean {
|
||||||
if (typeof value === 'string') return value === 'TRUE';
|
if (typeof value === 'string') return value === 'TRUE';
|
||||||
return !!value;
|
return !!value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,12 +24,12 @@ import {
|
|||||||
import * as fieldRegistry from './field_registry.js';
|
import * as fieldRegistry from './field_registry.js';
|
||||||
import {Menu} from './menu.js';
|
import {Menu} from './menu.js';
|
||||||
import {MenuItem} from './menuitem.js';
|
import {MenuItem} from './menuitem.js';
|
||||||
import * as style from './utils/style.js';
|
|
||||||
import * as aria from './utils/aria.js';
|
import * as aria from './utils/aria.js';
|
||||||
import {Coordinate} from './utils/coordinate.js';
|
import {Coordinate} from './utils/coordinate.js';
|
||||||
import * as dom from './utils/dom.js';
|
import * as dom from './utils/dom.js';
|
||||||
import * as parsing from './utils/parsing.js';
|
import * as parsing from './utils/parsing.js';
|
||||||
import * as utilsString from './utils/string.js';
|
import * as utilsString from './utils/string.js';
|
||||||
|
import * as style from './utils/style.js';
|
||||||
import {Svg} from './utils/svg.js';
|
import {Svg} from './utils/svg.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -92,6 +92,15 @@ export class FieldDropdown extends Field<string> {
|
|||||||
private selectedOption!: MenuOption;
|
private selectedOption!: MenuOption;
|
||||||
override clickTarget_: SVGElement | null = null;
|
override clickTarget_: SVGElement | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The y offset from the top of the field to the top of the image, if an image
|
||||||
|
* is selected.
|
||||||
|
*/
|
||||||
|
protected static IMAGE_Y_OFFSET = 5;
|
||||||
|
|
||||||
|
/** The total vertical padding above and below an image. */
|
||||||
|
protected static IMAGE_Y_PADDING = FieldDropdown.IMAGE_Y_OFFSET * 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param menuGenerator A non-empty array of options for a dropdown list, or a
|
* @param menuGenerator A non-empty array of options for a dropdown list, or a
|
||||||
* function which generates these options. Also accepts Field.SKIP_SETUP
|
* function which generates these options. Also accepts Field.SKIP_SETUP
|
||||||
@@ -125,8 +134,8 @@ export class FieldDropdown extends Field<string> {
|
|||||||
if (menuGenerator === Field.SKIP_SETUP) return;
|
if (menuGenerator === Field.SKIP_SETUP) return;
|
||||||
|
|
||||||
if (Array.isArray(menuGenerator)) {
|
if (Array.isArray(menuGenerator)) {
|
||||||
validateOptions(menuGenerator);
|
this.validateOptions(menuGenerator);
|
||||||
const trimmed = trimOptions(menuGenerator);
|
const trimmed = this.trimOptions(menuGenerator);
|
||||||
this.menuGenerator_ = trimmed.options;
|
this.menuGenerator_ = trimmed.options;
|
||||||
this.prefixField = trimmed.prefix || null;
|
this.prefixField = trimmed.prefix || null;
|
||||||
this.suffixField = trimmed.suffix || null;
|
this.suffixField = trimmed.suffix || null;
|
||||||
@@ -403,7 +412,7 @@ export class FieldDropdown extends Field<string> {
|
|||||||
if (useCache && this.generatedOptions) return this.generatedOptions;
|
if (useCache && this.generatedOptions) return this.generatedOptions;
|
||||||
|
|
||||||
this.generatedOptions = this.menuGenerator_();
|
this.generatedOptions = this.menuGenerator_();
|
||||||
validateOptions(this.generatedOptions);
|
this.validateOptions(this.generatedOptions);
|
||||||
return this.generatedOptions;
|
return this.generatedOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,7 +531,7 @@ export class FieldDropdown extends Field<string> {
|
|||||||
const hasBorder = !!this.borderRect_;
|
const hasBorder = !!this.borderRect_;
|
||||||
const height = Math.max(
|
const height = Math.max(
|
||||||
hasBorder ? this.getConstants()!.FIELD_DROPDOWN_BORDER_RECT_HEIGHT : 0,
|
hasBorder ? this.getConstants()!.FIELD_DROPDOWN_BORDER_RECT_HEIGHT : 0,
|
||||||
imageHeight + IMAGE_Y_PADDING,
|
imageHeight + FieldDropdown.IMAGE_Y_PADDING,
|
||||||
);
|
);
|
||||||
const xPadding = hasBorder
|
const xPadding = hasBorder
|
||||||
? this.getConstants()!.FIELD_BORDER_RECT_X_PADDING
|
? this.getConstants()!.FIELD_BORDER_RECT_X_PADDING
|
||||||
@@ -653,6 +662,127 @@ export class FieldDropdown extends Field<string> {
|
|||||||
// override the static fromJson method.
|
// override the static fromJson method.
|
||||||
return new this(options.options, undefined, options);
|
return new this(options.options, undefined, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factor out common words in statically defined options.
|
||||||
|
* Create prefix and/or suffix labels.
|
||||||
|
*/
|
||||||
|
protected trimOptions(options: MenuOption[]): {
|
||||||
|
options: MenuOption[];
|
||||||
|
prefix?: string;
|
||||||
|
suffix?: string;
|
||||||
|
} {
|
||||||
|
let hasImages = false;
|
||||||
|
const trimmedOptions = options.map(([label, value]): MenuOption => {
|
||||||
|
if (typeof label === 'string') {
|
||||||
|
return [parsing.replaceMessageReferences(label), value];
|
||||||
|
}
|
||||||
|
|
||||||
|
hasImages = true;
|
||||||
|
// Copy the image properties so they're not influenced by the original.
|
||||||
|
// NOTE: No need to deep copy since image properties are only 1 level deep.
|
||||||
|
const imageLabel =
|
||||||
|
label.alt !== null
|
||||||
|
? {...label, alt: parsing.replaceMessageReferences(label.alt)}
|
||||||
|
: {...label};
|
||||||
|
return [imageLabel, value];
|
||||||
|
});
|
||||||
|
|
||||||
|
if (hasImages || options.length < 2) return {options: trimmedOptions};
|
||||||
|
|
||||||
|
const stringOptions = trimmedOptions as [string, string][];
|
||||||
|
const stringLabels = stringOptions.map(([label]) => label);
|
||||||
|
|
||||||
|
const shortest = utilsString.shortestStringLength(stringLabels);
|
||||||
|
const prefixLength = utilsString.commonWordPrefix(stringLabels, shortest);
|
||||||
|
const suffixLength = utilsString.commonWordSuffix(stringLabels, shortest);
|
||||||
|
|
||||||
|
if (
|
||||||
|
(!prefixLength && !suffixLength) ||
|
||||||
|
shortest <= prefixLength + suffixLength
|
||||||
|
) {
|
||||||
|
// One or more strings will entirely vanish if we proceed. Abort.
|
||||||
|
return {options: stringOptions};
|
||||||
|
}
|
||||||
|
|
||||||
|
const prefix = prefixLength
|
||||||
|
? stringLabels[0].substring(0, prefixLength - 1)
|
||||||
|
: undefined;
|
||||||
|
const suffix = suffixLength
|
||||||
|
? stringLabels[0].substr(1 - suffixLength)
|
||||||
|
: undefined;
|
||||||
|
return {
|
||||||
|
options: this.applyTrim(stringOptions, prefixLength, suffixLength),
|
||||||
|
prefix,
|
||||||
|
suffix,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the calculated prefix and suffix lengths to trim all of the options in
|
||||||
|
* the given array.
|
||||||
|
*
|
||||||
|
* @param options Array of option tuples:
|
||||||
|
* (human-readable text or image, language-neutral name).
|
||||||
|
* @param prefixLength The length of the common prefix.
|
||||||
|
* @param suffixLength The length of the common suffix
|
||||||
|
* @returns A new array with all of the option text trimmed.
|
||||||
|
*/
|
||||||
|
private applyTrim(
|
||||||
|
options: [string, string][],
|
||||||
|
prefixLength: number,
|
||||||
|
suffixLength: number,
|
||||||
|
): MenuOption[] {
|
||||||
|
return options.map(([text, value]) => [
|
||||||
|
text.substring(prefixLength, text.length - suffixLength),
|
||||||
|
value,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the data structure to be processed as an options list.
|
||||||
|
*
|
||||||
|
* @param options The proposed dropdown options.
|
||||||
|
* @throws {TypeError} If proposed options are incorrectly structured.
|
||||||
|
*/
|
||||||
|
protected validateOptions(options: MenuOption[]) {
|
||||||
|
if (!Array.isArray(options)) {
|
||||||
|
throw TypeError('FieldDropdown options must be an array.');
|
||||||
|
}
|
||||||
|
if (!options.length) {
|
||||||
|
throw TypeError('FieldDropdown options must not be an empty array.');
|
||||||
|
}
|
||||||
|
let foundError = false;
|
||||||
|
for (let i = 0; i < options.length; i++) {
|
||||||
|
const tuple = options[i];
|
||||||
|
if (!Array.isArray(tuple)) {
|
||||||
|
foundError = true;
|
||||||
|
console.error(
|
||||||
|
`Invalid option[${i}]: Each FieldDropdown option must be an array.
|
||||||
|
Found: ${tuple}`,
|
||||||
|
);
|
||||||
|
} else if (typeof tuple[1] !== 'string') {
|
||||||
|
foundError = true;
|
||||||
|
console.error(
|
||||||
|
`Invalid option[${i}]: Each FieldDropdown option id must be a string.
|
||||||
|
Found ${tuple[1]} in: ${tuple}`,
|
||||||
|
);
|
||||||
|
} else if (
|
||||||
|
tuple[0] &&
|
||||||
|
typeof tuple[0] !== 'string' &&
|
||||||
|
typeof tuple[0].src !== 'string'
|
||||||
|
) {
|
||||||
|
foundError = true;
|
||||||
|
console.error(
|
||||||
|
`Invalid option[${i}]: Each FieldDropdown option must have a string
|
||||||
|
label or image description. Found ${tuple[0]} in: ${tuple}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (foundError) {
|
||||||
|
throw TypeError('Found invalid FieldDropdown options.');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -713,147 +843,4 @@ export interface FieldDropdownFromJsonConfig extends FieldDropdownConfig {
|
|||||||
*/
|
*/
|
||||||
export type FieldDropdownValidator = FieldValidator<string>;
|
export type FieldDropdownValidator = FieldValidator<string>;
|
||||||
|
|
||||||
/**
|
|
||||||
* The y offset from the top of the field to the top of the image, if an image
|
|
||||||
* is selected.
|
|
||||||
*/
|
|
||||||
const IMAGE_Y_OFFSET = 5;
|
|
||||||
|
|
||||||
/** The total vertical padding above and below an image. */
|
|
||||||
const IMAGE_Y_PADDING: number = IMAGE_Y_OFFSET * 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factor out common words in statically defined options.
|
|
||||||
* Create prefix and/or suffix labels.
|
|
||||||
*/
|
|
||||||
function trimOptions(options: MenuOption[]): {
|
|
||||||
options: MenuOption[];
|
|
||||||
prefix?: string;
|
|
||||||
suffix?: string;
|
|
||||||
} {
|
|
||||||
let hasImages = false;
|
|
||||||
const trimmedOptions = options.map(([label, value]): MenuOption => {
|
|
||||||
if (typeof label === 'string') {
|
|
||||||
return [parsing.replaceMessageReferences(label), value];
|
|
||||||
}
|
|
||||||
|
|
||||||
hasImages = true;
|
|
||||||
// Copy the image properties so they're not influenced by the original.
|
|
||||||
// NOTE: No need to deep copy since image properties are only 1 level deep.
|
|
||||||
const imageLabel =
|
|
||||||
label.alt !== null
|
|
||||||
? {...label, alt: parsing.replaceMessageReferences(label.alt)}
|
|
||||||
: {...label};
|
|
||||||
return [imageLabel, value];
|
|
||||||
});
|
|
||||||
|
|
||||||
if (hasImages || options.length < 2) return {options: trimmedOptions};
|
|
||||||
|
|
||||||
const stringOptions = trimmedOptions as [string, string][];
|
|
||||||
const stringLabels = stringOptions.map(([label]) => label);
|
|
||||||
|
|
||||||
const shortest = utilsString.shortestStringLength(stringLabels);
|
|
||||||
const prefixLength = utilsString.commonWordPrefix(stringLabels, shortest);
|
|
||||||
const suffixLength = utilsString.commonWordSuffix(stringLabels, shortest);
|
|
||||||
|
|
||||||
if (
|
|
||||||
(!prefixLength && !suffixLength) ||
|
|
||||||
shortest <= prefixLength + suffixLength
|
|
||||||
) {
|
|
||||||
// One or more strings will entirely vanish if we proceed. Abort.
|
|
||||||
return {options: stringOptions};
|
|
||||||
}
|
|
||||||
|
|
||||||
const prefix = prefixLength
|
|
||||||
? stringLabels[0].substring(0, prefixLength - 1)
|
|
||||||
: undefined;
|
|
||||||
const suffix = suffixLength
|
|
||||||
? stringLabels[0].substr(1 - suffixLength)
|
|
||||||
: undefined;
|
|
||||||
return {
|
|
||||||
options: applyTrim(stringOptions, prefixLength, suffixLength),
|
|
||||||
prefix,
|
|
||||||
suffix,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use the calculated prefix and suffix lengths to trim all of the options in
|
|
||||||
* the given array.
|
|
||||||
*
|
|
||||||
* @param options Array of option tuples:
|
|
||||||
* (human-readable text or image, language-neutral name).
|
|
||||||
* @param prefixLength The length of the common prefix.
|
|
||||||
* @param suffixLength The length of the common suffix
|
|
||||||
* @returns A new array with all of the option text trimmed.
|
|
||||||
*/
|
|
||||||
function applyTrim(
|
|
||||||
options: [string, string][],
|
|
||||||
prefixLength: number,
|
|
||||||
suffixLength: number,
|
|
||||||
): MenuOption[] {
|
|
||||||
return options.map(([text, value]) => [
|
|
||||||
text.substring(prefixLength, text.length - suffixLength),
|
|
||||||
value,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates the data structure to be processed as an options list.
|
|
||||||
*
|
|
||||||
* @param options The proposed dropdown options.
|
|
||||||
* @throws {TypeError} If proposed options are incorrectly structured.
|
|
||||||
*/
|
|
||||||
function validateOptions(options: MenuOption[]) {
|
|
||||||
if (!Array.isArray(options)) {
|
|
||||||
throw TypeError('FieldDropdown options must be an array.');
|
|
||||||
}
|
|
||||||
if (!options.length) {
|
|
||||||
throw TypeError('FieldDropdown options must not be an empty array.');
|
|
||||||
}
|
|
||||||
let foundError = false;
|
|
||||||
for (let i = 0; i < options.length; i++) {
|
|
||||||
const tuple = options[i];
|
|
||||||
if (!Array.isArray(tuple)) {
|
|
||||||
foundError = true;
|
|
||||||
console.error(
|
|
||||||
'Invalid option[' +
|
|
||||||
i +
|
|
||||||
']: Each FieldDropdown option must be an ' +
|
|
||||||
'array. Found: ',
|
|
||||||
tuple,
|
|
||||||
);
|
|
||||||
} else if (typeof tuple[1] !== 'string') {
|
|
||||||
foundError = true;
|
|
||||||
console.error(
|
|
||||||
'Invalid option[' +
|
|
||||||
i +
|
|
||||||
']: Each FieldDropdown option id must be ' +
|
|
||||||
'a string. Found ' +
|
|
||||||
tuple[1] +
|
|
||||||
' in: ',
|
|
||||||
tuple,
|
|
||||||
);
|
|
||||||
} else if (
|
|
||||||
tuple[0] &&
|
|
||||||
typeof tuple[0] !== 'string' &&
|
|
||||||
typeof tuple[0].src !== 'string'
|
|
||||||
) {
|
|
||||||
foundError = true;
|
|
||||||
console.error(
|
|
||||||
'Invalid option[' +
|
|
||||||
i +
|
|
||||||
']: Each FieldDropdown option must have a ' +
|
|
||||||
'string label or image description. Found' +
|
|
||||||
tuple[0] +
|
|
||||||
' in: ',
|
|
||||||
tuple,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (foundError) {
|
|
||||||
throw TypeError('Found invalid FieldDropdown options.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldRegistry.register('field_dropdown', FieldDropdown);
|
fieldRegistry.register('field_dropdown', FieldDropdown);
|
||||||
|
|||||||
@@ -15,11 +15,11 @@
|
|||||||
import './events/events_block_change.js';
|
import './events/events_block_change.js';
|
||||||
|
|
||||||
import {BlockSvg} from './block_svg.js';
|
import {BlockSvg} from './block_svg.js';
|
||||||
import * as bumpObjects from './bump_objects.js';
|
|
||||||
import * as browserEvents from './browser_events.js';
|
import * as browserEvents from './browser_events.js';
|
||||||
|
import * as bumpObjects from './bump_objects.js';
|
||||||
import * as dialog from './dialog.js';
|
import * as dialog from './dialog.js';
|
||||||
import * as dom from './utils/dom.js';
|
|
||||||
import * as dropDownDiv from './dropdowndiv.js';
|
import * as dropDownDiv from './dropdowndiv.js';
|
||||||
|
import {EventType} from './events/type.js';
|
||||||
import * as eventUtils from './events/utils.js';
|
import * as eventUtils from './events/utils.js';
|
||||||
import {
|
import {
|
||||||
Field,
|
Field,
|
||||||
@@ -28,12 +28,13 @@ import {
|
|||||||
UnattachedFieldError,
|
UnattachedFieldError,
|
||||||
} from './field.js';
|
} from './field.js';
|
||||||
import {Msg} from './msg.js';
|
import {Msg} from './msg.js';
|
||||||
|
import * as renderManagement from './render_management.js';
|
||||||
import * as aria from './utils/aria.js';
|
import * as aria from './utils/aria.js';
|
||||||
import {Coordinate} from './utils/coordinate.js';
|
import * as dom from './utils/dom.js';
|
||||||
|
import {Size} from './utils/size.js';
|
||||||
import * as userAgent from './utils/useragent.js';
|
import * as userAgent from './utils/useragent.js';
|
||||||
import * as WidgetDiv from './widgetdiv.js';
|
import * as WidgetDiv from './widgetdiv.js';
|
||||||
import type {WorkspaceSvg} from './workspace_svg.js';
|
import type {WorkspaceSvg} from './workspace_svg.js';
|
||||||
import {Size} from './utils/size.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Supported types for FieldInput subclasses.
|
* Supported types for FieldInput subclasses.
|
||||||
@@ -79,10 +80,10 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
|
|||||||
protected valueWhenEditorWasOpened_: string | T | null = null;
|
protected valueWhenEditorWasOpened_: string | T | null = null;
|
||||||
|
|
||||||
/** Key down event data. */
|
/** Key down event data. */
|
||||||
private onKeyDownWrapper_: browserEvents.Data | null = null;
|
private onKeyDownWrapper: browserEvents.Data | null = null;
|
||||||
|
|
||||||
/** Key input event data. */
|
/** Key input event data. */
|
||||||
private onKeyInputWrapper_: browserEvents.Data | null = null;
|
private onKeyInputWrapper: browserEvents.Data | null = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the field should consider the whole parent block to be its click
|
* Whether the field should consider the whole parent block to be its click
|
||||||
@@ -188,7 +189,7 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
|
|||||||
fireChangeEvent
|
fireChangeEvent
|
||||||
) {
|
) {
|
||||||
eventUtils.fire(
|
eventUtils.fire(
|
||||||
new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
|
new (eventUtils.get(EventType.BLOCK_CHANGE))(
|
||||||
this.sourceBlock_,
|
this.sourceBlock_,
|
||||||
'field',
|
'field',
|
||||||
this.name || null,
|
this.name || null,
|
||||||
@@ -338,9 +339,9 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
|
|||||||
this.workspace_.options.modalInputs &&
|
this.workspace_.options.modalInputs &&
|
||||||
(userAgent.MOBILE || userAgent.ANDROID || userAgent.IPAD)
|
(userAgent.MOBILE || userAgent.ANDROID || userAgent.IPAD)
|
||||||
) {
|
) {
|
||||||
this.showPromptEditor_();
|
this.showPromptEditor();
|
||||||
} else {
|
} else {
|
||||||
this.showInlineEditor_(quietInput);
|
this.showInlineEditor(quietInput);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,7 +350,7 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
|
|||||||
* Mobile browsers may have issues with in-line textareas (focus and
|
* Mobile browsers may have issues with in-line textareas (focus and
|
||||||
* keyboards).
|
* keyboards).
|
||||||
*/
|
*/
|
||||||
private showPromptEditor_() {
|
private showPromptEditor() {
|
||||||
dialog.prompt(
|
dialog.prompt(
|
||||||
Msg['CHANGE_VALUE_TITLE'],
|
Msg['CHANGE_VALUE_TITLE'],
|
||||||
this.getText(),
|
this.getText(),
|
||||||
@@ -368,7 +369,7 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
|
|||||||
*
|
*
|
||||||
* @param quietInput True if editor should be created without focus.
|
* @param quietInput True if editor should be created without focus.
|
||||||
*/
|
*/
|
||||||
private showInlineEditor_(quietInput: boolean) {
|
private showInlineEditor(quietInput: boolean) {
|
||||||
const block = this.getSourceBlock();
|
const block = this.getSourceBlock();
|
||||||
if (!block) {
|
if (!block) {
|
||||||
throw new UnattachedFieldError();
|
throw new UnattachedFieldError();
|
||||||
@@ -476,7 +477,7 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
|
|||||||
// multiple times while the editor was open, but this will fire an event
|
// multiple times while the editor was open, but this will fire an event
|
||||||
// containing the value when the editor was opened as well as the new one.
|
// containing the value when the editor was opened as well as the new one.
|
||||||
eventUtils.fire(
|
eventUtils.fire(
|
||||||
new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
|
new (eventUtils.get(EventType.BLOCK_CHANGE))(
|
||||||
this.sourceBlock_,
|
this.sourceBlock_,
|
||||||
'field',
|
'field',
|
||||||
this.name || null,
|
this.name || null,
|
||||||
@@ -518,30 +519,30 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
|
|||||||
*/
|
*/
|
||||||
protected bindInputEvents_(htmlInput: HTMLElement) {
|
protected bindInputEvents_(htmlInput: HTMLElement) {
|
||||||
// Trap Enter without IME and Esc to hide.
|
// Trap Enter without IME and Esc to hide.
|
||||||
this.onKeyDownWrapper_ = browserEvents.conditionalBind(
|
this.onKeyDownWrapper = browserEvents.conditionalBind(
|
||||||
htmlInput,
|
htmlInput,
|
||||||
'keydown',
|
'keydown',
|
||||||
this,
|
this,
|
||||||
this.onHtmlInputKeyDown_,
|
this.onHtmlInputKeyDown_,
|
||||||
);
|
);
|
||||||
// Resize after every input change.
|
// Resize after every input change.
|
||||||
this.onKeyInputWrapper_ = browserEvents.conditionalBind(
|
this.onKeyInputWrapper = browserEvents.conditionalBind(
|
||||||
htmlInput,
|
htmlInput,
|
||||||
'input',
|
'input',
|
||||||
this,
|
this,
|
||||||
this.onHtmlInputChange_,
|
this.onHtmlInputChange,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Unbind handlers for user input and workspace size changes. */
|
/** Unbind handlers for user input and workspace size changes. */
|
||||||
protected unbindInputEvents_() {
|
protected unbindInputEvents_() {
|
||||||
if (this.onKeyDownWrapper_) {
|
if (this.onKeyDownWrapper) {
|
||||||
browserEvents.unbind(this.onKeyDownWrapper_);
|
browserEvents.unbind(this.onKeyDownWrapper);
|
||||||
this.onKeyDownWrapper_ = null;
|
this.onKeyDownWrapper = null;
|
||||||
}
|
}
|
||||||
if (this.onKeyInputWrapper_) {
|
if (this.onKeyInputWrapper) {
|
||||||
browserEvents.unbind(this.onKeyInputWrapper_);
|
browserEvents.unbind(this.onKeyInputWrapper);
|
||||||
this.onKeyInputWrapper_ = null;
|
this.onKeyInputWrapper = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,7 +575,7 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
|
|||||||
*
|
*
|
||||||
* @param _e Keyboard event.
|
* @param _e Keyboard event.
|
||||||
*/
|
*/
|
||||||
private onHtmlInputChange_(_e: Event) {
|
private onHtmlInputChange(_e: Event) {
|
||||||
// Intermediate value changes from user input are not confirmed until the
|
// Intermediate value changes from user input are not confirmed until the
|
||||||
// user closes the editor, and may be numerous. Inhibit reporting these as
|
// user closes the editor, and may be numerous. Inhibit reporting these as
|
||||||
// normal block change events, and instead report them as special
|
// normal block change events, and instead report them as special
|
||||||
@@ -593,7 +594,7 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
|
|||||||
// Fire a special event indicating that the value changed but the change
|
// Fire a special event indicating that the value changed but the change
|
||||||
// isn't complete yet and normal field change listeners can wait.
|
// isn't complete yet and normal field change listeners can wait.
|
||||||
eventUtils.fire(
|
eventUtils.fire(
|
||||||
new (eventUtils.get(eventUtils.BLOCK_FIELD_INTERMEDIATE_CHANGE))(
|
new (eventUtils.get(EventType.BLOCK_FIELD_INTERMEDIATE_CHANGE))(
|
||||||
this.sourceBlock_,
|
this.sourceBlock_,
|
||||||
this.name || null,
|
this.name || null,
|
||||||
oldValue,
|
oldValue,
|
||||||
@@ -630,22 +631,22 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
|
|||||||
|
|
||||||
/** Resize the editor to fit the text. */
|
/** Resize the editor to fit the text. */
|
||||||
protected resizeEditor_() {
|
protected resizeEditor_() {
|
||||||
const block = this.getSourceBlock();
|
renderManagement.finishQueuedRenders().then(() => {
|
||||||
if (!block) {
|
const block = this.getSourceBlock();
|
||||||
throw new UnattachedFieldError();
|
if (!block) throw new UnattachedFieldError();
|
||||||
}
|
const div = WidgetDiv.getDiv();
|
||||||
const div = WidgetDiv.getDiv();
|
const bBox = this.getScaledBBox();
|
||||||
const bBox = this.getScaledBBox();
|
div!.style.width = bBox.right - bBox.left + 'px';
|
||||||
div!.style.width = bBox.right - bBox.left + 'px';
|
div!.style.height = bBox.bottom - bBox.top + 'px';
|
||||||
div!.style.height = bBox.bottom - bBox.top + 'px';
|
|
||||||
|
|
||||||
// In RTL mode block fields and LTR input fields the left edge moves,
|
// In RTL mode block fields and LTR input fields the left edge moves,
|
||||||
// whereas the right edge is fixed. Reposition the editor.
|
// whereas the right edge is fixed. Reposition the editor.
|
||||||
const x = block.RTL ? bBox.right - div!.offsetWidth : bBox.left;
|
const x = block.RTL ? bBox.right - div!.offsetWidth : bBox.left;
|
||||||
const xy = new Coordinate(x, bBox.top);
|
const y = bBox.top;
|
||||||
|
|
||||||
div!.style.left = xy.x + 'px';
|
div!.style.left = `${x}px`;
|
||||||
div!.style.top = xy.y + 'px';
|
div!.style.top = `${y}px`;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -657,7 +658,7 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
|
|||||||
* div.
|
* div.
|
||||||
*/
|
*/
|
||||||
override repositionForWindowResize(): boolean {
|
override repositionForWindowResize(): boolean {
|
||||||
const block = this.getSourceBlock();
|
const block = this.getSourceBlock()?.getRootBlock();
|
||||||
// This shouldn't be possible. We should never have a WidgetDiv if not using
|
// This shouldn't be possible. We should never have a WidgetDiv if not using
|
||||||
// rendered blocks.
|
// rendered blocks.
|
||||||
if (!(block instanceof BlockSvg)) return false;
|
if (!(block instanceof BlockSvg)) return false;
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
*/
|
*/
|
||||||
// Former goog.module ID: Blockly.FieldLabel
|
// Former goog.module ID: Blockly.FieldLabel
|
||||||
|
|
||||||
import * as dom from './utils/dom.js';
|
|
||||||
import {Field, FieldConfig} from './field.js';
|
import {Field, FieldConfig} from './field.js';
|
||||||
import * as fieldRegistry from './field_registry.js';
|
import * as fieldRegistry from './field_registry.js';
|
||||||
|
import * as dom from './utils/dom.js';
|
||||||
import * as parsing from './utils/parsing.js';
|
import * as parsing from './utils/parsing.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -12,12 +12,12 @@
|
|||||||
// Former goog.module ID: Blockly.FieldNumber
|
// Former goog.module ID: Blockly.FieldNumber
|
||||||
|
|
||||||
import {Field} from './field.js';
|
import {Field} from './field.js';
|
||||||
import * as fieldRegistry from './field_registry.js';
|
|
||||||
import {
|
import {
|
||||||
FieldInput,
|
FieldInput,
|
||||||
FieldInputConfig,
|
FieldInputConfig,
|
||||||
FieldInputValidator,
|
FieldInputValidator,
|
||||||
} from './field_input.js';
|
} from './field_input.js';
|
||||||
|
import * as fieldRegistry from './field_registry.js';
|
||||||
import * as aria from './utils/aria.js';
|
import * as aria from './utils/aria.js';
|
||||||
import * as dom from './utils/dom.js';
|
import * as dom from './utils/dom.js';
|
||||||
|
|
||||||
|
|||||||
@@ -11,17 +11,22 @@
|
|||||||
*/
|
*/
|
||||||
// Former goog.module ID: Blockly.Flyout
|
// Former goog.module ID: Blockly.Flyout
|
||||||
|
|
||||||
import type {Abstract as AbstractEvent} from './events/events_abstract.js';
|
|
||||||
import {BlockSvg} from './block_svg.js';
|
import {BlockSvg} from './block_svg.js';
|
||||||
import * as browserEvents from './browser_events.js';
|
import * as browserEvents from './browser_events.js';
|
||||||
import {ComponentManager} from './component_manager.js';
|
import {ComponentManager} from './component_manager.js';
|
||||||
import {DeleteArea} from './delete_area.js';
|
import {DeleteArea} from './delete_area.js';
|
||||||
|
import type {Abstract as AbstractEvent} from './events/events_abstract.js';
|
||||||
|
import {EventType} from './events/type.js';
|
||||||
import * as eventUtils from './events/utils.js';
|
import * as eventUtils from './events/utils.js';
|
||||||
import {FlyoutMetricsManager} from './flyout_metrics_manager.js';
|
import {FlyoutMetricsManager} from './flyout_metrics_manager.js';
|
||||||
|
import {FlyoutSeparator, SeparatorAxis} from './flyout_separator.js';
|
||||||
|
import {IAutoHideable} from './interfaces/i_autohideable.js';
|
||||||
|
import type {IBoundedElement} from './interfaces/i_bounded_element.js';
|
||||||
import type {IFlyout} from './interfaces/i_flyout.js';
|
import type {IFlyout} from './interfaces/i_flyout.js';
|
||||||
import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js';
|
import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js';
|
||||||
import type {IBoundedElement} from './interfaces/i_bounded_element.js';
|
|
||||||
import type {Options} from './options.js';
|
import type {Options} from './options.js';
|
||||||
|
import * as registry from './registry.js';
|
||||||
|
import * as renderManagement from './render_management.js';
|
||||||
import {ScrollbarPair} from './scrollbar_pair.js';
|
import {ScrollbarPair} from './scrollbar_pair.js';
|
||||||
import * as blocks from './serialization/blocks.js';
|
import * as blocks from './serialization/blocks.js';
|
||||||
import {Coordinate} from './utils/coordinate.js';
|
import {Coordinate} from './utils/coordinate.js';
|
||||||
@@ -31,10 +36,6 @@ import {Svg} from './utils/svg.js';
|
|||||||
import * as toolbox from './utils/toolbox.js';
|
import * as toolbox from './utils/toolbox.js';
|
||||||
import * as Variables from './variables.js';
|
import * as Variables from './variables.js';
|
||||||
import {WorkspaceSvg} from './workspace_svg.js';
|
import {WorkspaceSvg} from './workspace_svg.js';
|
||||||
import * as registry from './registry.js';
|
|
||||||
import * as renderManagement from './render_management.js';
|
|
||||||
import {IAutoHideable} from './interfaces/i_autohideable.js';
|
|
||||||
import {FlyoutSeparator, SeparatorAxis} from './flyout_separator.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for a flyout.
|
* Class for a flyout.
|
||||||
@@ -152,7 +153,7 @@ export abstract class Flyout
|
|||||||
/**
|
/**
|
||||||
* Whether the flyout is visible.
|
* Whether the flyout is visible.
|
||||||
*/
|
*/
|
||||||
private isVisible_ = false;
|
private visible = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the workspace containing this flyout is visible.
|
* Whether the workspace containing this flyout is visible.
|
||||||
@@ -237,7 +238,7 @@ export abstract class Flyout
|
|||||||
|
|
||||||
this.workspace_.internalIsFlyout = true;
|
this.workspace_.internalIsFlyout = true;
|
||||||
// Keep the workspace visibility consistent with the flyout's visibility.
|
// Keep the workspace visibility consistent with the flyout's visibility.
|
||||||
this.workspace_.setVisible(this.isVisible_);
|
this.workspace_.setVisible(this.visible);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The unique id for this component that is used to register with the
|
* The unique id for this component that is used to register with the
|
||||||
@@ -369,7 +370,7 @@ export abstract class Flyout
|
|||||||
|
|
||||||
targetWorkspace.getComponentManager().addComponent({
|
targetWorkspace.getComponentManager().addComponent({
|
||||||
component: this,
|
component: this,
|
||||||
weight: 1,
|
weight: ComponentManager.ComponentWeight.FLYOUT_WEIGHT,
|
||||||
capabilities: [
|
capabilities: [
|
||||||
ComponentManager.Capability.AUTOHIDEABLE,
|
ComponentManager.Capability.AUTOHIDEABLE,
|
||||||
ComponentManager.Capability.DELETE_AREA,
|
ComponentManager.Capability.DELETE_AREA,
|
||||||
@@ -470,7 +471,7 @@ export abstract class Flyout
|
|||||||
* @returns True if visible.
|
* @returns True if visible.
|
||||||
*/
|
*/
|
||||||
isVisible(): boolean {
|
isVisible(): boolean {
|
||||||
return this.isVisible_;
|
return this.visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -483,7 +484,7 @@ export abstract class Flyout
|
|||||||
setVisible(visible: boolean) {
|
setVisible(visible: boolean) {
|
||||||
const visibilityChanged = visible !== this.isVisible();
|
const visibilityChanged = visible !== this.isVisible();
|
||||||
|
|
||||||
this.isVisible_ = visible;
|
this.visible = visible;
|
||||||
if (visibilityChanged) {
|
if (visibilityChanged) {
|
||||||
if (!this.autoClose) {
|
if (!this.autoClose) {
|
||||||
// Auto-close flyouts are ignored as drag targets, so only non
|
// Auto-close flyouts are ignored as drag targets, so only non
|
||||||
@@ -818,13 +819,13 @@ export abstract class Flyout
|
|||||||
for (let i = 0; i < newVariables.length; i++) {
|
for (let i = 0; i < newVariables.length; i++) {
|
||||||
const thisVariable = newVariables[i];
|
const thisVariable = newVariables[i];
|
||||||
eventUtils.fire(
|
eventUtils.fire(
|
||||||
new (eventUtils.get(eventUtils.VAR_CREATE))(thisVariable),
|
new (eventUtils.get(EventType.VAR_CREATE))(thisVariable),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block events come after var events, in case they refer to newly created
|
// Block events come after var events, in case they refer to newly created
|
||||||
// variables.
|
// variables.
|
||||||
eventUtils.fire(new (eventUtils.get(eventUtils.BLOCK_CREATE))(newBlock));
|
eventUtils.fire(new (eventUtils.get(EventType.BLOCK_CREATE))(newBlock));
|
||||||
}
|
}
|
||||||
if (this.autoClose) {
|
if (this.autoClose) {
|
||||||
this.hide();
|
this.hide();
|
||||||
|
|||||||
@@ -11,19 +11,19 @@
|
|||||||
*/
|
*/
|
||||||
// Former goog.module ID: Blockly.FlyoutButton
|
// Former goog.module ID: Blockly.FlyoutButton
|
||||||
|
|
||||||
|
import type {IASTNodeLocationSvg} from './blockly.js';
|
||||||
import * as browserEvents from './browser_events.js';
|
import * as browserEvents from './browser_events.js';
|
||||||
import * as Css from './css.js';
|
import * as Css from './css.js';
|
||||||
|
import type {IBoundedElement} from './interfaces/i_bounded_element.js';
|
||||||
|
import type {IRenderedElement} from './interfaces/i_rendered_element.js';
|
||||||
import {Coordinate} from './utils/coordinate.js';
|
import {Coordinate} from './utils/coordinate.js';
|
||||||
import * as dom from './utils/dom.js';
|
import * as dom from './utils/dom.js';
|
||||||
import * as parsing from './utils/parsing.js';
|
import * as parsing from './utils/parsing.js';
|
||||||
|
import {Rect} from './utils/rect.js';
|
||||||
import * as style from './utils/style.js';
|
import * as style from './utils/style.js';
|
||||||
import {Svg} from './utils/svg.js';
|
import {Svg} from './utils/svg.js';
|
||||||
import type * as toolbox from './utils/toolbox.js';
|
import type * as toolbox from './utils/toolbox.js';
|
||||||
import type {WorkspaceSvg} from './workspace_svg.js';
|
import type {WorkspaceSvg} from './workspace_svg.js';
|
||||||
import type {IASTNodeLocationSvg} from './interfaces/i_ast_node_location_svg.js';
|
|
||||||
import type {IBoundedElement} from './interfaces/i_bounded_element.js';
|
|
||||||
import type {IRenderedElement} from './interfaces/i_rendered_element.js';
|
|
||||||
import {Rect} from './utils/rect.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for a button or label in the flyout.
|
* Class for a button or label in the flyout.
|
||||||
|
|||||||
@@ -38,13 +38,13 @@ export class FlyoutMetricsManager extends MetricsManager {
|
|||||||
*
|
*
|
||||||
* @returns The bounding box of the blocks on the workspace.
|
* @returns The bounding box of the blocks on the workspace.
|
||||||
*/
|
*/
|
||||||
private getBoundingBox_():
|
private getBoundingBox():
|
||||||
| SVGRect
|
| SVGRect
|
||||||
| {height: number; y: number; width: number; x: number} {
|
| {height: number; y: number; width: number; x: number} {
|
||||||
let blockBoundingBox;
|
let blockBoundingBox;
|
||||||
try {
|
try {
|
||||||
blockBoundingBox = this.workspace_.getCanvas().getBBox();
|
blockBoundingBox = this.workspace_.getCanvas().getBBox();
|
||||||
} catch (e) {
|
} catch {
|
||||||
// Firefox has trouble with hidden elements (Bug 528969).
|
// Firefox has trouble with hidden elements (Bug 528969).
|
||||||
// 2021 Update: It looks like this was fixed around Firefox 77 released in
|
// 2021 Update: It looks like this was fixed around Firefox 77 released in
|
||||||
// 2020.
|
// 2020.
|
||||||
@@ -55,7 +55,7 @@ export class FlyoutMetricsManager extends MetricsManager {
|
|||||||
|
|
||||||
override getContentMetrics(opt_getWorkspaceCoordinates?: boolean) {
|
override getContentMetrics(opt_getWorkspaceCoordinates?: boolean) {
|
||||||
// The bounding box is in workspace coordinates.
|
// The bounding box is in workspace coordinates.
|
||||||
const blockBoundingBox = this.getBoundingBox_();
|
const blockBoundingBox = this.getBoundingBox();
|
||||||
const scale = opt_getWorkspaceCoordinates ? 1 : this.workspace_.scale;
|
const scale = opt_getWorkspaceCoordinates ? 1 : this.workspace_.scale;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import type {Workspace} from './workspace.js';
|
|||||||
* @deprecated
|
* @deprecated
|
||||||
* @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/generating-code}
|
* @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/generating-code}
|
||||||
* @param block The Block instance to generate code for.
|
* @param block The Block instance to generate code for.
|
||||||
* @param genearator The CodeGenerator calling the function.
|
* @param generator The CodeGenerator calling the function.
|
||||||
* @returns A string containing the generated code (for statement blocks),
|
* @returns A string containing the generated code (for statement blocks),
|
||||||
* or a [code, precedence] tuple (for value/expression blocks), or
|
* or a [code, precedence] tuple (for value/expression blocks), or
|
||||||
* null if no code should be emitted for block.
|
* null if no code should be emitted for block.
|
||||||
|
|||||||
@@ -18,23 +18,24 @@ import './events/events_click.js';
|
|||||||
import * as blockAnimations from './block_animations.js';
|
import * as blockAnimations from './block_animations.js';
|
||||||
import type {BlockSvg} from './block_svg.js';
|
import type {BlockSvg} from './block_svg.js';
|
||||||
import * as browserEvents from './browser_events.js';
|
import * as browserEvents from './browser_events.js';
|
||||||
|
import {RenderedWorkspaceComment} from './comments.js';
|
||||||
import * as common from './common.js';
|
import * as common from './common.js';
|
||||||
import {config} from './config.js';
|
import {config} from './config.js';
|
||||||
import * as dropDownDiv from './dropdowndiv.js';
|
import * as dropDownDiv from './dropdowndiv.js';
|
||||||
|
import {EventType} from './events/type.js';
|
||||||
import * as eventUtils from './events/utils.js';
|
import * as eventUtils from './events/utils.js';
|
||||||
import type {Field} from './field.js';
|
import type {Field} from './field.js';
|
||||||
import type {IBubble} from './interfaces/i_bubble.js';
|
import type {IBubble} from './interfaces/i_bubble.js';
|
||||||
|
import {IDraggable, isDraggable} from './interfaces/i_draggable.js';
|
||||||
|
import {IDragger} from './interfaces/i_dragger.js';
|
||||||
import type {IFlyout} from './interfaces/i_flyout.js';
|
import type {IFlyout} from './interfaces/i_flyout.js';
|
||||||
|
import type {IIcon} from './interfaces/i_icon.js';
|
||||||
|
import * as registry from './registry.js';
|
||||||
import * as Tooltip from './tooltip.js';
|
import * as Tooltip from './tooltip.js';
|
||||||
import * as Touch from './touch.js';
|
import * as Touch from './touch.js';
|
||||||
import {Coordinate} from './utils/coordinate.js';
|
import {Coordinate} from './utils/coordinate.js';
|
||||||
import {WorkspaceDragger} from './workspace_dragger.js';
|
import {WorkspaceDragger} from './workspace_dragger.js';
|
||||||
import type {WorkspaceSvg} from './workspace_svg.js';
|
import type {WorkspaceSvg} from './workspace_svg.js';
|
||||||
import type {IIcon} from './interfaces/i_icon.js';
|
|
||||||
import {IDragger} from './interfaces/i_dragger.js';
|
|
||||||
import * as registry from './registry.js';
|
|
||||||
import {IDraggable, isDraggable} from './interfaces/i_draggable.js';
|
|
||||||
import {RenderedWorkspaceComment} from './comments.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note: In this file "start" refers to pointerdown
|
* Note: In this file "start" refers to pointerdown
|
||||||
@@ -145,7 +146,7 @@ export class Gesture {
|
|||||||
private mostRecentEvent: PointerEvent;
|
private mostRecentEvent: PointerEvent;
|
||||||
|
|
||||||
/** Boolean for whether or not this gesture is a multi-touch gesture. */
|
/** Boolean for whether or not this gesture is a multi-touch gesture. */
|
||||||
private isMultiTouch_ = false;
|
private multiTouch = false;
|
||||||
|
|
||||||
/** A map of cached points used for tracking multi-touch gestures. */
|
/** A map of cached points used for tracking multi-touch gestures. */
|
||||||
private cachedPoints = new Map<string, Coordinate | null>();
|
private cachedPoints = new Map<string, Coordinate | null>();
|
||||||
@@ -585,7 +586,7 @@ export class Gesture {
|
|||||||
const point0 = this.cachedPoints.get(pointers[0])!;
|
const point0 = this.cachedPoints.get(pointers[0])!;
|
||||||
const point1 = this.cachedPoints.get(pointers[1])!;
|
const point1 = this.cachedPoints.get(pointers[1])!;
|
||||||
this.startDistance = Coordinate.distance(point0, point1);
|
this.startDistance = Coordinate.distance(point0, point1);
|
||||||
this.isMultiTouch_ = true;
|
this.multiTouch = true;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -599,13 +600,20 @@ export class Gesture {
|
|||||||
*/
|
*/
|
||||||
handleTouchMove(e: PointerEvent) {
|
handleTouchMove(e: PointerEvent) {
|
||||||
const pointerId = Touch.getTouchIdentifierFromEvent(e);
|
const pointerId = Touch.getTouchIdentifierFromEvent(e);
|
||||||
// Update the cache
|
|
||||||
this.cachedPoints.set(pointerId, this.getTouchPoint(e));
|
this.cachedPoints.set(pointerId, this.getTouchPoint(e));
|
||||||
|
|
||||||
if (this.isPinchZoomEnabled && this.cachedPoints.size === 2) {
|
if (this.isPinchZoomEnabled && this.cachedPoints.size === 2) {
|
||||||
this.handlePinch(e);
|
this.handlePinch(e);
|
||||||
} else {
|
} else {
|
||||||
this.handleMove(e);
|
// Handle the move directly instead of calling handleMove
|
||||||
|
this.updateFromEvent(e);
|
||||||
|
if (this.workspaceDragger) {
|
||||||
|
this.workspaceDragger.drag(this.currentDragDeltaXY);
|
||||||
|
} else if (this.dragger) {
|
||||||
|
this.dragger.onDrag(this.mostRecentEvent, this.currentDragDeltaXY);
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -683,7 +691,7 @@ export class Gesture {
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
isMultiTouch(): boolean {
|
isMultiTouch(): boolean {
|
||||||
return this.isMultiTouch_;
|
return this.multiTouch;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -769,7 +777,7 @@ export class Gesture {
|
|||||||
*/
|
*/
|
||||||
private fireWorkspaceClick(ws: WorkspaceSvg) {
|
private fireWorkspaceClick(ws: WorkspaceSvg) {
|
||||||
eventUtils.fire(
|
eventUtils.fire(
|
||||||
new (eventUtils.get(eventUtils.CLICK))(null, ws.id, 'workspace'),
|
new (eventUtils.get(EventType.CLICK))(null, ws.id, 'workspace'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -902,7 +910,7 @@ export class Gesture {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Clicks events are on the start block, even if it was a shadow.
|
// Clicks events are on the start block, even if it was a shadow.
|
||||||
const event = new (eventUtils.get(eventUtils.CLICK))(
|
const event = new (eventUtils.get(EventType.CLICK))(
|
||||||
this.startBlock,
|
this.startBlock,
|
||||||
this.startWorkspace_.id,
|
this.startWorkspace_.id,
|
||||||
'block',
|
'block',
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
*/
|
*/
|
||||||
// Former goog.module ID: Blockly.Grid
|
// Former goog.module ID: Blockly.Grid
|
||||||
|
|
||||||
import * as dom from './utils/dom.js';
|
|
||||||
import {Coordinate} from './utils/coordinate.js';
|
|
||||||
import {Svg} from './utils/svg.js';
|
|
||||||
import {GridOptions} from './options.js';
|
import {GridOptions} from './options.js';
|
||||||
|
import {Coordinate} from './utils/coordinate.js';
|
||||||
|
import * as dom from './utils/dom.js';
|
||||||
|
import {Svg} from './utils/svg.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for a workspace's grid.
|
* Class for a workspace's grid.
|
||||||
|
|||||||
@@ -4,21 +4,21 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Icon} from './icons/icon.js';
|
|
||||||
import {CommentIcon, CommentState} from './icons/comment_icon.js';
|
import {CommentIcon, CommentState} from './icons/comment_icon.js';
|
||||||
import {MutatorIcon} from './icons/mutator_icon.js';
|
|
||||||
import {WarningIcon} from './icons/warning_icon.js';
|
|
||||||
import {IconType} from './icons/icon_types.js';
|
|
||||||
import * as exceptions from './icons/exceptions.js';
|
import * as exceptions from './icons/exceptions.js';
|
||||||
|
import {Icon} from './icons/icon.js';
|
||||||
|
import {IconType} from './icons/icon_types.js';
|
||||||
|
import {MutatorIcon} from './icons/mutator_icon.js';
|
||||||
import * as registry from './icons/registry.js';
|
import * as registry from './icons/registry.js';
|
||||||
|
import {WarningIcon} from './icons/warning_icon.js';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Icon,
|
|
||||||
CommentIcon,
|
CommentIcon,
|
||||||
CommentState,
|
CommentState,
|
||||||
MutatorIcon,
|
|
||||||
WarningIcon,
|
|
||||||
IconType,
|
|
||||||
exceptions,
|
exceptions,
|
||||||
|
Icon,
|
||||||
|
IconType,
|
||||||
|
MutatorIcon,
|
||||||
registry,
|
registry,
|
||||||
|
WarningIcon,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,21 +8,21 @@
|
|||||||
|
|
||||||
import type {Block} from '../block.js';
|
import type {Block} from '../block.js';
|
||||||
import type {BlockSvg} from '../block_svg.js';
|
import type {BlockSvg} from '../block_svg.js';
|
||||||
import {IconType} from './icon_types.js';
|
import {TextInputBubble} from '../bubbles/textinput_bubble.js';
|
||||||
import {Coordinate} from '../utils.js';
|
import {EventType} from '../events/type.js';
|
||||||
import * as dom from '../utils/dom.js';
|
|
||||||
import * as eventUtils from '../events/utils.js';
|
import * as eventUtils from '../events/utils.js';
|
||||||
import {Icon} from './icon.js';
|
|
||||||
import type {IHasBubble} from '../interfaces/i_has_bubble.js';
|
import type {IHasBubble} from '../interfaces/i_has_bubble.js';
|
||||||
import type {ISerializable} from '../interfaces/i_serializable.js';
|
import type {ISerializable} from '../interfaces/i_serializable.js';
|
||||||
|
import * as renderManagement from '../render_management.js';
|
||||||
|
import {Coordinate} from '../utils.js';
|
||||||
|
import * as dom from '../utils/dom.js';
|
||||||
import {Rect} from '../utils/rect.js';
|
import {Rect} from '../utils/rect.js';
|
||||||
import * as registry from './registry.js';
|
|
||||||
import {Size} from '../utils/size.js';
|
import {Size} from '../utils/size.js';
|
||||||
import {Svg} from '../utils/svg.js';
|
import {Svg} from '../utils/svg.js';
|
||||||
import {TextBubble} from '../bubbles/text_bubble.js';
|
|
||||||
import {TextInputBubble} from '../bubbles/textinput_bubble.js';
|
|
||||||
import type {WorkspaceSvg} from '../workspace_svg.js';
|
import type {WorkspaceSvg} from '../workspace_svg.js';
|
||||||
import * as renderManagement from '../render_management.js';
|
import {Icon} from './icon.js';
|
||||||
|
import {IconType} from './icon_types.js';
|
||||||
|
import * as registry from './registry.js';
|
||||||
|
|
||||||
/** The size of the comment icon in workspace-scale units. */
|
/** The size of the comment icon in workspace-scale units. */
|
||||||
const SIZE = 17;
|
const SIZE = 17;
|
||||||
@@ -46,12 +46,9 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable {
|
|||||||
*/
|
*/
|
||||||
static readonly WEIGHT = 3;
|
static readonly WEIGHT = 3;
|
||||||
|
|
||||||
/** The bubble used to show editable text to the user. */
|
/** The bubble used to show comment text to the user. */
|
||||||
private textInputBubble: TextInputBubble | null = null;
|
private textInputBubble: TextInputBubble | null = null;
|
||||||
|
|
||||||
/** The bubble used to show non-editable text to the user. */
|
|
||||||
private textBubble: TextBubble | null = null;
|
|
||||||
|
|
||||||
/** The text of this comment. */
|
/** The text of this comment. */
|
||||||
private text = '';
|
private text = '';
|
||||||
|
|
||||||
@@ -120,7 +117,6 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable {
|
|||||||
override dispose() {
|
override dispose() {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
this.textInputBubble?.dispose();
|
this.textInputBubble?.dispose();
|
||||||
this.textBubble?.dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override getWeight(): number {
|
override getWeight(): number {
|
||||||
@@ -135,7 +131,6 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable {
|
|||||||
super.applyColour();
|
super.applyColour();
|
||||||
const colour = (this.sourceBlock as BlockSvg).style.colourPrimary;
|
const colour = (this.sourceBlock as BlockSvg).style.colourPrimary;
|
||||||
this.textInputBubble?.setColour(colour);
|
this.textInputBubble?.setColour(colour);
|
||||||
this.textBubble?.setColour(colour);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -161,14 +156,13 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable {
|
|||||||
}
|
}
|
||||||
const anchorLocation = this.getAnchorLocation();
|
const anchorLocation = this.getAnchorLocation();
|
||||||
this.textInputBubble?.setAnchorLocation(anchorLocation);
|
this.textInputBubble?.setAnchorLocation(anchorLocation);
|
||||||
this.textBubble?.setAnchorLocation(anchorLocation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets the text of this comment. Updates any bubbles if they are visible. */
|
/** Sets the text of this comment. Updates any bubbles if they are visible. */
|
||||||
setText(text: string) {
|
setText(text: string) {
|
||||||
const oldText = this.text;
|
const oldText = this.text;
|
||||||
eventUtils.fire(
|
eventUtils.fire(
|
||||||
new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
|
new (eventUtils.get(EventType.BLOCK_CHANGE))(
|
||||||
this.sourceBlock,
|
this.sourceBlock,
|
||||||
'comment',
|
'comment',
|
||||||
null,
|
null,
|
||||||
@@ -178,7 +172,6 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable {
|
|||||||
);
|
);
|
||||||
this.text = text;
|
this.text = text;
|
||||||
this.textInputBubble?.setText(this.text);
|
this.textInputBubble?.setText(this.text);
|
||||||
this.textBubble?.setText(this.text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the text of this comment. */
|
/** Returns the text of this comment. */
|
||||||
@@ -282,7 +275,7 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable {
|
|||||||
if (this.text === newText) return;
|
if (this.text === newText) return;
|
||||||
|
|
||||||
eventUtils.fire(
|
eventUtils.fire(
|
||||||
new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
|
new (eventUtils.get(EventType.BLOCK_CHANGE))(
|
||||||
this.sourceBlock,
|
this.sourceBlock,
|
||||||
'comment',
|
'comment',
|
||||||
null,
|
null,
|
||||||
@@ -338,7 +331,7 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
eventUtils.fire(
|
eventUtils.fire(
|
||||||
new (eventUtils.get(eventUtils.BUBBLE_OPEN))(
|
new (eventUtils.get(EventType.BUBBLE_OPEN))(
|
||||||
this.sourceBlock,
|
this.sourceBlock,
|
||||||
visible,
|
visible,
|
||||||
'comment',
|
'comment',
|
||||||
@@ -351,6 +344,18 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable {
|
|||||||
* to update the state of this icon in response to changes in the bubble.
|
* to update the state of this icon in response to changes in the bubble.
|
||||||
*/
|
*/
|
||||||
private showEditableBubble() {
|
private showEditableBubble() {
|
||||||
|
this.createBubble();
|
||||||
|
this.textInputBubble?.addTextChangeListener(() => this.onTextChange());
|
||||||
|
this.textInputBubble?.addSizeChangeListener(() => this.onSizeChange());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Shows the non editable text bubble for this comment. */
|
||||||
|
private showNonEditableBubble() {
|
||||||
|
this.createBubble();
|
||||||
|
this.textInputBubble?.setEditable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected createBubble() {
|
||||||
this.textInputBubble = new TextInputBubble(
|
this.textInputBubble = new TextInputBubble(
|
||||||
this.sourceBlock.workspace as WorkspaceSvg,
|
this.sourceBlock.workspace as WorkspaceSvg,
|
||||||
this.getAnchorLocation(),
|
this.getAnchorLocation(),
|
||||||
@@ -368,25 +373,10 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Shows the non editable text bubble for this comment. */
|
|
||||||
private showNonEditableBubble() {
|
|
||||||
this.textBubble = new TextBubble(
|
|
||||||
this.getText(),
|
|
||||||
this.sourceBlock.workspace as WorkspaceSvg,
|
|
||||||
this.getAnchorLocation(),
|
|
||||||
this.getBubbleOwnerRect(),
|
|
||||||
);
|
|
||||||
if (this.bubbleLocation) {
|
|
||||||
this.textBubble.moveDuringDrag(this.bubbleLocation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Hides any open bubbles owned by this comment. */
|
/** Hides any open bubbles owned by this comment. */
|
||||||
private hideBubble() {
|
private hideBubble() {
|
||||||
this.textInputBubble?.dispose();
|
this.textInputBubble?.dispose();
|
||||||
this.textInputBubble = null;
|
this.textInputBubble = null;
|
||||||
this.textBubble?.dispose();
|
|
||||||
this.textBubble = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -406,8 +396,7 @@ export class CommentIcon extends Icon implements IHasBubble, ISerializable {
|
|||||||
* I.E. the block that owns this icon.
|
* I.E. the block that owns this icon.
|
||||||
*/
|
*/
|
||||||
private getBubbleOwnerRect(): Rect {
|
private getBubbleOwnerRect(): Rect {
|
||||||
const bbox = (this.sourceBlock as BlockSvg).getSvgRoot().getBBox();
|
return (this.sourceBlock as BlockSvg).getBoundingRectangleWithoutChildren();
|
||||||
return new Rect(bbox.y, bbox.y + bbox.height, bbox.x, bbox.x + bbox.width);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import type {BlockSvg} from '../block_svg.js';
|
|||||||
import * as browserEvents from '../browser_events.js';
|
import * as browserEvents from '../browser_events.js';
|
||||||
import {hasBubble} from '../interfaces/i_has_bubble.js';
|
import {hasBubble} from '../interfaces/i_has_bubble.js';
|
||||||
import type {IIcon} from '../interfaces/i_icon.js';
|
import type {IIcon} from '../interfaces/i_icon.js';
|
||||||
|
import * as tooltip from '../tooltip.js';
|
||||||
import {Coordinate} from '../utils/coordinate.js';
|
import {Coordinate} from '../utils/coordinate.js';
|
||||||
import * as dom from '../utils/dom.js';
|
import * as dom from '../utils/dom.js';
|
||||||
import {Size} from '../utils/size.js';
|
import {Size} from '../utils/size.js';
|
||||||
import {Svg} from '../utils/svg.js';
|
import {Svg} from '../utils/svg.js';
|
||||||
import type {IconType} from './icon_types.js';
|
import type {IconType} from './icon_types.js';
|
||||||
import * as tooltip from '../tooltip.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The abstract icon class. Icons are visual elements that live in the top-start
|
* The abstract icon class. Icons are visual elements that live in the top-start
|
||||||
|
|||||||
@@ -6,22 +6,24 @@
|
|||||||
|
|
||||||
// Former goog.module ID: Blockly.Mutator
|
// Former goog.module ID: Blockly.Mutator
|
||||||
|
|
||||||
|
import type {BlockSvg} from '../block_svg.js';
|
||||||
|
import type {BlocklyOptions} from '../blockly_options.js';
|
||||||
|
import {MiniWorkspaceBubble} from '../bubbles/mini_workspace_bubble.js';
|
||||||
import type {Abstract} from '../events/events_abstract.js';
|
import type {Abstract} from '../events/events_abstract.js';
|
||||||
import {BlockChange} from '../events/events_block_change.js';
|
import {BlockChange} from '../events/events_block_change.js';
|
||||||
import type {BlocklyOptions} from '../blockly_options.js';
|
import {isBlockChange, isBlockCreate} from '../events/predicates.js';
|
||||||
import type {BlockSvg} from '../block_svg.js';
|
import {EventType} from '../events/type.js';
|
||||||
import {Coordinate} from '../utils/coordinate.js';
|
|
||||||
import * as dom from '../utils/dom.js';
|
|
||||||
import * as eventUtils from '../events/utils.js';
|
import * as eventUtils from '../events/utils.js';
|
||||||
import type {IHasBubble} from '../interfaces/i_has_bubble.js';
|
import type {IHasBubble} from '../interfaces/i_has_bubble.js';
|
||||||
import {Icon} from './icon.js';
|
import * as renderManagement from '../render_management.js';
|
||||||
import {MiniWorkspaceBubble} from '../bubbles/mini_workspace_bubble.js';
|
import {Coordinate} from '../utils/coordinate.js';
|
||||||
|
import * as dom from '../utils/dom.js';
|
||||||
import {Rect} from '../utils/rect.js';
|
import {Rect} from '../utils/rect.js';
|
||||||
import {Size} from '../utils/size.js';
|
import {Size} from '../utils/size.js';
|
||||||
import {Svg} from '../utils/svg.js';
|
import {Svg} from '../utils/svg.js';
|
||||||
import type {WorkspaceSvg} from '../workspace_svg.js';
|
import type {WorkspaceSvg} from '../workspace_svg.js';
|
||||||
|
import {Icon} from './icon.js';
|
||||||
import {IconType} from './icon_types.js';
|
import {IconType} from './icon_types.js';
|
||||||
import * as renderManagement from '../render_management.js';
|
|
||||||
|
|
||||||
/** The size of the mutator icon in workspace-scale units. */
|
/** The size of the mutator icon in workspace-scale units. */
|
||||||
const SIZE = 17;
|
const SIZE = 17;
|
||||||
@@ -193,7 +195,7 @@ export class MutatorIcon extends Icon implements IHasBubble {
|
|||||||
}
|
}
|
||||||
|
|
||||||
eventUtils.fire(
|
eventUtils.fire(
|
||||||
new (eventUtils.get(eventUtils.BUBBLE_OPEN))(
|
new (eventUtils.get(EventType.BUBBLE_OPEN))(
|
||||||
this.sourceBlock,
|
this.sourceBlock,
|
||||||
visible,
|
visible,
|
||||||
'mutator',
|
'mutator',
|
||||||
@@ -307,9 +309,8 @@ export class MutatorIcon extends Icon implements IHasBubble {
|
|||||||
static isIgnorableMutatorEvent(e: Abstract) {
|
static isIgnorableMutatorEvent(e: Abstract) {
|
||||||
return (
|
return (
|
||||||
e.isUiEvent ||
|
e.isUiEvent ||
|
||||||
e.type === eventUtils.CREATE ||
|
isBlockCreate(e) ||
|
||||||
(e.type === eventUtils.CHANGE &&
|
(isBlockChange(e) && e.element === 'disabled')
|
||||||
(e as BlockChange).element === 'disabled')
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,7 +332,7 @@ export class MutatorIcon extends Icon implements IHasBubble {
|
|||||||
|
|
||||||
if (oldExtraState !== newExtraState) {
|
if (oldExtraState !== newExtraState) {
|
||||||
eventUtils.fire(
|
eventUtils.fire(
|
||||||
new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
|
new (eventUtils.get(EventType.BLOCK_CHANGE))(
|
||||||
this.sourceBlock,
|
this.sourceBlock,
|
||||||
'mutation',
|
'mutation',
|
||||||
null,
|
null,
|
||||||
|
|||||||
@@ -7,17 +7,18 @@
|
|||||||
// Former goog.module ID: Blockly.Warning
|
// Former goog.module ID: Blockly.Warning
|
||||||
|
|
||||||
import type {BlockSvg} from '../block_svg.js';
|
import type {BlockSvg} from '../block_svg.js';
|
||||||
|
import {TextBubble} from '../bubbles/text_bubble.js';
|
||||||
|
import {EventType} from '../events/type.js';
|
||||||
|
import * as eventUtils from '../events/utils.js';
|
||||||
|
import type {IHasBubble} from '../interfaces/i_has_bubble.js';
|
||||||
|
import * as renderManagement from '../render_management.js';
|
||||||
|
import {Size} from '../utils.js';
|
||||||
import {Coordinate} from '../utils/coordinate.js';
|
import {Coordinate} from '../utils/coordinate.js';
|
||||||
import * as dom from '../utils/dom.js';
|
import * as dom from '../utils/dom.js';
|
||||||
import * as eventUtils from '../events/utils.js';
|
|
||||||
import {Icon} from './icon.js';
|
|
||||||
import type {IHasBubble} from '../interfaces/i_has_bubble.js';
|
|
||||||
import {Rect} from '../utils/rect.js';
|
import {Rect} from '../utils/rect.js';
|
||||||
import {Size} from '../utils.js';
|
|
||||||
import {Svg} from '../utils/svg.js';
|
import {Svg} from '../utils/svg.js';
|
||||||
import {TextBubble} from '../bubbles/text_bubble.js';
|
import {Icon} from './icon.js';
|
||||||
import {IconType} from './icon_types.js';
|
import {IconType} from './icon_types.js';
|
||||||
import * as renderManagement from '../render_management.js';
|
|
||||||
|
|
||||||
/** The size of the warning icon in workspace-scale units. */
|
/** The size of the warning icon in workspace-scale units. */
|
||||||
const SIZE = 17;
|
const SIZE = 17;
|
||||||
@@ -188,7 +189,7 @@ export class WarningIcon extends Icon implements IHasBubble {
|
|||||||
}
|
}
|
||||||
|
|
||||||
eventUtils.fire(
|
eventUtils.fire(
|
||||||
new (eventUtils.get(eventUtils.BUBBLE_OPEN))(
|
new (eventUtils.get(EventType.BUBBLE_OPEN))(
|
||||||
this.sourceBlock,
|
this.sourceBlock,
|
||||||
visible,
|
visible,
|
||||||
'warning',
|
'warning',
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import * as Touch from './touch.js';
|
|||||||
import * as aria from './utils/aria.js';
|
import * as aria from './utils/aria.js';
|
||||||
import * as dom from './utils/dom.js';
|
import * as dom from './utils/dom.js';
|
||||||
import {Svg} from './utils/svg.js';
|
import {Svg} from './utils/svg.js';
|
||||||
import * as userAgent from './utils/useragent.js';
|
|
||||||
import * as WidgetDiv from './widgetdiv.js';
|
import * as WidgetDiv from './widgetdiv.js';
|
||||||
import {WorkspaceSvg} from './workspace_svg.js';
|
import {WorkspaceSvg} from './workspace_svg.js';
|
||||||
|
|
||||||
@@ -342,18 +341,6 @@ function bindDocumentEvents() {
|
|||||||
// should run regardless of what other touch event handlers have run.
|
// should run regardless of what other touch event handlers have run.
|
||||||
browserEvents.bind(document, 'touchend', null, Touch.longStop);
|
browserEvents.bind(document, 'touchend', null, Touch.longStop);
|
||||||
browserEvents.bind(document, 'touchcancel', null, Touch.longStop);
|
browserEvents.bind(document, 'touchcancel', null, Touch.longStop);
|
||||||
// Some iPad versions don't fire resize after portrait to landscape change.
|
|
||||||
if (userAgent.IPAD) {
|
|
||||||
browserEvents.conditionalBind(
|
|
||||||
window,
|
|
||||||
'orientationchange',
|
|
||||||
document,
|
|
||||||
function () {
|
|
||||||
// TODO (#397): Fix for multiple Blockly workspaces.
|
|
||||||
common.svgResize(common.getMainWorkspace() as WorkspaceSvg);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
documentEventsBound = true;
|
documentEventsBound = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,19 +5,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Align} from './inputs/align.js';
|
import {Align} from './inputs/align.js';
|
||||||
import {Input} from './inputs/input.js';
|
|
||||||
import {DummyInput} from './inputs/dummy_input.js';
|
import {DummyInput} from './inputs/dummy_input.js';
|
||||||
import {EndRowInput} from './inputs/end_row_input.js';
|
import {EndRowInput} from './inputs/end_row_input.js';
|
||||||
|
import {Input} from './inputs/input.js';
|
||||||
|
import {inputTypes} from './inputs/input_types.js';
|
||||||
import {StatementInput} from './inputs/statement_input.js';
|
import {StatementInput} from './inputs/statement_input.js';
|
||||||
import {ValueInput} from './inputs/value_input.js';
|
import {ValueInput} from './inputs/value_input.js';
|
||||||
import {inputTypes} from './inputs/input_types.js';
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Align,
|
Align,
|
||||||
Input,
|
|
||||||
DummyInput,
|
DummyInput,
|
||||||
EndRowInput,
|
EndRowInput,
|
||||||
|
Input,
|
||||||
|
inputTypes,
|
||||||
StatementInput,
|
StatementInput,
|
||||||
ValueInput,
|
ValueInput,
|
||||||
inputTypes,
|
|
||||||
};
|
};
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user