mirror of
https://github.com/google/blockly.git
synced 2026-01-13 03:47:08 +01:00
Merge branch 'goog_module' of github.com:google/blockly into module_aria
This commit is contained in:
@@ -2,29 +2,6 @@
|
||||
"rules": {
|
||||
"curly": ["error"],
|
||||
"eol-last": ["error"],
|
||||
// Blockly/Google use 2-space indents.
|
||||
// Blockly/Google uses +4 space indents for line continuations.
|
||||
// Ignore default rules for ternary expressions.
|
||||
"indent": [
|
||||
"error", 2,
|
||||
{
|
||||
"SwitchCase": 1,
|
||||
"MemberExpression": 2,
|
||||
"ObjectExpression": 1,
|
||||
"FunctionDeclaration": {
|
||||
"body": 1,
|
||||
"parameters": 2
|
||||
},
|
||||
"FunctionExpression": {
|
||||
"body": 1,
|
||||
"parameters": 2
|
||||
},
|
||||
"CallExpression": {
|
||||
"arguments": 2
|
||||
},
|
||||
"ignoredNodes": ["ConditionalExpression"]
|
||||
}
|
||||
],
|
||||
"keyword-spacing": ["error"],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
"max-len": [
|
||||
@@ -39,7 +16,7 @@
|
||||
],
|
||||
"no-trailing-spaces": ["error", { "skipBlankLines": true }],
|
||||
"no-unused-vars": [
|
||||
"error",
|
||||
"warn",
|
||||
{
|
||||
"args": "after-used",
|
||||
// Ignore vars starting with an underscore.
|
||||
@@ -48,7 +25,6 @@
|
||||
"argsIgnorePattern": "^_"
|
||||
}
|
||||
],
|
||||
"no-use-before-define": ["error"],
|
||||
// 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.
|
||||
|
||||
16
.github/workflows/build.yml
vendored
16
.github/workflows/build.yml
vendored
@@ -41,3 +41,19 @@ jobs:
|
||||
|
||||
env:
|
||||
CI: true
|
||||
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Use Node.js 16.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 16.x
|
||||
|
||||
- name: Npm Install
|
||||
run: npm install
|
||||
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
|
||||
35
.github/workflows/tag_module_cleanup.yml
vendored
Normal file
35
.github/workflows/tag_module_cleanup.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
# For new pull requests against the goog_module branch, adds the 'type: cleanup'
|
||||
# label and sets the milestone to q3 2021 release.
|
||||
|
||||
name: Tag module cleanup
|
||||
|
||||
# Trigger on pull requests against goog_module branch only
|
||||
# Uses pull_request_target to get write permissions so that it can write labels.
|
||||
on:
|
||||
pull_request_target:
|
||||
branches:
|
||||
- goog_module
|
||||
|
||||
jobs:
|
||||
tag-module-cleanup:
|
||||
|
||||
# Add the type: cleanup label
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/github-script@a3e7071a34d7e1f219a8a4de9a5e0a34d1ee1293
|
||||
with:
|
||||
script: |
|
||||
// 2021 q3 release milestone.
|
||||
// https://github.com/google/blockly/milestone/18
|
||||
const milestoneNumber = 18;
|
||||
// Note that pull requests are accessed through the issues API.
|
||||
const issuesUpdateParams = {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
// Adds the milestone
|
||||
milestone: milestoneNumber,
|
||||
issue_number: context.issue.number,
|
||||
// Sets the labels
|
||||
labels: ['type: cleanup']
|
||||
}
|
||||
await github.issues.update(issuesUpdateParams)
|
||||
40
.github/workflows/update_metadata.yml
vendored
Normal file
40
.github/workflows/update_metadata.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
# This workflow updates the check_metadata.sh script, which compares the current
|
||||
# size of build artifacts against their size in the previous version of Blockly.
|
||||
|
||||
name: Update Metadata
|
||||
|
||||
on: [workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
update-metadata:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check Out Blockly
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: 'develop'
|
||||
|
||||
- name: Use Node.js 16.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 16.x
|
||||
|
||||
- name: Build Blockly
|
||||
run: npm run build:compressed
|
||||
|
||||
- name: Build Blockly blocks
|
||||
run: npm run build:blocks
|
||||
|
||||
- name: Update Metadata
|
||||
run: source ./tests/scripts/update_metadata.sh
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@9825ae65b1cb54b543b938503728b432a0176d29
|
||||
with:
|
||||
commit-message: Update build artifact sizes in check_metadata.sh
|
||||
delete-branch: true
|
||||
title: Update build artifact sizes in check_metadata.sh
|
||||
|
||||
- name: View Pull Request
|
||||
run: echo "View Pull Request - ${{ steps.cpr.outputs.pull-request-url }}"
|
||||
@@ -10,50 +10,49 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.blockAnimations');
|
||||
goog.module('Blockly.blockAnimations');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
|
||||
|
||||
/**
|
||||
* PID of disconnect UI animation. There can only be one at a time.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
Blockly.blockAnimations.disconnectPid_ = 0;
|
||||
let disconnectPid = 0;
|
||||
|
||||
/**
|
||||
* SVG group of wobbling block. There can only be one at a time.
|
||||
* @type {Element}
|
||||
* @private
|
||||
*/
|
||||
Blockly.blockAnimations.disconnectGroup_ = null;
|
||||
let disconnectGroup = null;
|
||||
|
||||
/**
|
||||
* Play some UI effects (sound, animation) when disposing of a block.
|
||||
* @param {!Blockly.BlockSvg} block The block being disposed of.
|
||||
* @package
|
||||
* @param {!BlockSvg} block The block being disposed of.
|
||||
*/
|
||||
Blockly.blockAnimations.disposeUiEffect = function(block) {
|
||||
var workspace = block.workspace;
|
||||
var svgGroup = block.getSvgRoot();
|
||||
const disposeUiEffect = function(block) {
|
||||
const workspace = block.workspace;
|
||||
const svgGroup = block.getSvgRoot();
|
||||
workspace.getAudioManager().play('delete');
|
||||
|
||||
var xy = workspace.getSvgXY(svgGroup);
|
||||
const xy = workspace.getSvgXY(svgGroup);
|
||||
// Deeply clone the current block.
|
||||
var clone = svgGroup.cloneNode(true);
|
||||
const clone = svgGroup.cloneNode(true);
|
||||
clone.translateX_ = xy.x;
|
||||
clone.translateY_ = xy.y;
|
||||
clone.setAttribute('transform', 'translate(' + xy.x + ',' + xy.y + ')');
|
||||
workspace.getParentSvg().appendChild(clone);
|
||||
clone.bBox_ = clone.getBBox();
|
||||
// Start the animation.
|
||||
Blockly.blockAnimations.disposeUiStep_(clone, workspace.RTL, new Date,
|
||||
workspace.scale);
|
||||
disposeUiStep(clone, workspace.RTL, new Date, workspace.scale);
|
||||
};
|
||||
/** @package */
|
||||
exports.disposeUiEffect = disposeUiEffect;
|
||||
|
||||
/**
|
||||
* Animate a cloned block and eventually dispose of it.
|
||||
@@ -63,40 +62,38 @@ Blockly.blockAnimations.disposeUiEffect = function(block) {
|
||||
* @param {boolean} rtl True if RTL, false if LTR.
|
||||
* @param {!Date} start Date of animation's start.
|
||||
* @param {number} workspaceScale Scale of workspace.
|
||||
* @private
|
||||
*/
|
||||
Blockly.blockAnimations.disposeUiStep_ = function(clone, rtl, start,
|
||||
workspaceScale) {
|
||||
var ms = new Date - start;
|
||||
var percent = ms / 150;
|
||||
const disposeUiStep = function(clone, rtl, start, workspaceScale) {
|
||||
const ms = new Date - start;
|
||||
const percent = ms / 150;
|
||||
if (percent > 1) {
|
||||
Blockly.utils.dom.removeNode(clone);
|
||||
dom.removeNode(clone);
|
||||
} else {
|
||||
var x = clone.translateX_ +
|
||||
const x = clone.translateX_ +
|
||||
(rtl ? -1 : 1) * clone.bBox_.width * workspaceScale / 2 * percent;
|
||||
var y = clone.translateY_ + clone.bBox_.height * workspaceScale * percent;
|
||||
var scale = (1 - percent) * workspaceScale;
|
||||
clone.setAttribute('transform', 'translate(' + x + ',' + y + ')' +
|
||||
' scale(' + scale + ')');
|
||||
setTimeout(Blockly.blockAnimations.disposeUiStep_, 10, clone, rtl, start,
|
||||
workspaceScale);
|
||||
const y = clone.translateY_ + clone.bBox_.height * workspaceScale * percent;
|
||||
const scale = (1 - percent) * workspaceScale;
|
||||
clone.setAttribute(
|
||||
'transform',
|
||||
'translate(' + x + ',' + y + ')' +
|
||||
' scale(' + scale + ')');
|
||||
setTimeout(disposeUiStep, 10, clone, rtl, start, workspaceScale);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Play some UI effects (sound, ripple) after a connection has been established.
|
||||
* @param {!Blockly.BlockSvg} block The block being connected.
|
||||
* @package
|
||||
* @param {!BlockSvg} block The block being connected.
|
||||
*/
|
||||
Blockly.blockAnimations.connectionUiEffect = function(block) {
|
||||
var workspace = block.workspace;
|
||||
var scale = workspace.scale;
|
||||
const connectionUiEffect = function(block) {
|
||||
const workspace = block.workspace;
|
||||
const scale = workspace.scale;
|
||||
workspace.getAudioManager().play('click');
|
||||
if (scale < 1) {
|
||||
return; // Too small to care about visual effects.
|
||||
}
|
||||
// Determine the absolute coordinates of the inferior block.
|
||||
var xy = workspace.getSvgXY(block.getSvgRoot());
|
||||
const xy = workspace.getSvgXY(block.getSvgRoot());
|
||||
// Offset the coordinates based on the two connection types, fix scale.
|
||||
if (block.outputConnection) {
|
||||
xy.x += (block.RTL ? 3 : -3) * scale;
|
||||
@@ -105,9 +102,8 @@ Blockly.blockAnimations.connectionUiEffect = function(block) {
|
||||
xy.x += (block.RTL ? -23 : 23) * scale;
|
||||
xy.y += 3 * scale;
|
||||
}
|
||||
var ripple = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.CIRCLE,
|
||||
{
|
||||
const ripple = dom.createSvgElement(
|
||||
Svg.CIRCLE, {
|
||||
'cx': xy.x,
|
||||
'cy': xy.y,
|
||||
'r': 0,
|
||||
@@ -117,89 +113,88 @@ Blockly.blockAnimations.connectionUiEffect = function(block) {
|
||||
},
|
||||
workspace.getParentSvg());
|
||||
// Start the animation.
|
||||
Blockly.blockAnimations.connectionUiStep_(ripple, new Date, scale);
|
||||
connectionUiStep(ripple, new Date, scale);
|
||||
};
|
||||
/** @package */
|
||||
exports.connectionUiEffect = connectionUiEffect;
|
||||
|
||||
/**
|
||||
* Expand a ripple around a connection.
|
||||
* @param {!SVGElement} ripple Element to animate.
|
||||
* @param {!Date} start Date of animation's start.
|
||||
* @param {number} scale Scale of workspace.
|
||||
* @private
|
||||
*/
|
||||
Blockly.blockAnimations.connectionUiStep_ = function(ripple, start, scale) {
|
||||
var ms = new Date - start;
|
||||
var percent = ms / 150;
|
||||
const connectionUiStep = function(ripple, start, scale) {
|
||||
const ms = new Date - start;
|
||||
const percent = ms / 150;
|
||||
if (percent > 1) {
|
||||
Blockly.utils.dom.removeNode(ripple);
|
||||
dom.removeNode(ripple);
|
||||
} else {
|
||||
ripple.setAttribute('r', percent * 25 * scale);
|
||||
ripple.style.opacity = 1 - percent;
|
||||
Blockly.blockAnimations.disconnectPid_ = setTimeout(
|
||||
Blockly.blockAnimations.connectionUiStep_, 10, ripple, start, scale);
|
||||
disconnectPid = setTimeout(connectionUiStep, 10, ripple, start, scale);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Play some UI effects (sound, animation) when disconnecting a block.
|
||||
* @param {!Blockly.BlockSvg} block The block being disconnected.
|
||||
* @package
|
||||
* @param {!BlockSvg} block The block being disconnected.
|
||||
*/
|
||||
Blockly.blockAnimations.disconnectUiEffect = function(block) {
|
||||
const disconnectUiEffect = function(block) {
|
||||
block.workspace.getAudioManager().play('disconnect');
|
||||
if (block.workspace.scale < 1) {
|
||||
return; // Too small to care about visual effects.
|
||||
}
|
||||
// Horizontal distance for bottom of block to wiggle.
|
||||
var DISPLACEMENT = 10;
|
||||
const DISPLACEMENT = 10;
|
||||
// Scale magnitude of skew to height of block.
|
||||
var height = block.getHeightWidth().height;
|
||||
var magnitude = Math.atan(DISPLACEMENT / height) / Math.PI * 180;
|
||||
const height = block.getHeightWidth().height;
|
||||
let magnitude = Math.atan(DISPLACEMENT / height) / Math.PI * 180;
|
||||
if (!block.RTL) {
|
||||
magnitude *= -1;
|
||||
}
|
||||
// Start the animation.
|
||||
Blockly.blockAnimations.disconnectUiStep_(
|
||||
block.getSvgRoot(), magnitude, new Date);
|
||||
disconnectUiStep(block.getSvgRoot(), magnitude, new Date);
|
||||
};
|
||||
/** @package */
|
||||
exports.disconnectUiEffect = disconnectUiEffect;
|
||||
|
||||
/**
|
||||
* Animate a brief wiggle of a disconnected block.
|
||||
* @param {!SVGElement} group SVG element to animate.
|
||||
* @param {number} magnitude Maximum degrees skew (reversed for RTL).
|
||||
* @param {!Date} start Date of animation's start.
|
||||
* @private
|
||||
*/
|
||||
Blockly.blockAnimations.disconnectUiStep_ = function(group, magnitude, start) {
|
||||
var DURATION = 200; // Milliseconds.
|
||||
var WIGGLES = 3; // Half oscillations.
|
||||
const disconnectUiStep = function(group, magnitude, start) {
|
||||
const DURATION = 200; // Milliseconds.
|
||||
const WIGGLES = 3; // Half oscillations.
|
||||
|
||||
var ms = new Date - start;
|
||||
var percent = ms / DURATION;
|
||||
const ms = new Date - start;
|
||||
const percent = ms / DURATION;
|
||||
|
||||
if (percent > 1) {
|
||||
group.skew_ = '';
|
||||
} else {
|
||||
var skew = Math.round(
|
||||
const skew = Math.round(
|
||||
Math.sin(percent * Math.PI * WIGGLES) * (1 - percent) * magnitude);
|
||||
group.skew_ = 'skewX(' + skew + ')';
|
||||
Blockly.blockAnimations.disconnectGroup_ = group;
|
||||
Blockly.blockAnimations.disconnectPid_ =
|
||||
setTimeout(Blockly.blockAnimations.disconnectUiStep_, 10, group,
|
||||
magnitude, start);
|
||||
disconnectGroup = group;
|
||||
disconnectPid = setTimeout(disconnectUiStep, 10, group, magnitude, start);
|
||||
}
|
||||
group.setAttribute('transform', group.translate_ + group.skew_);
|
||||
};
|
||||
|
||||
/**
|
||||
* Stop the disconnect UI animation immediately.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockAnimations.disconnectUiStop = function() {
|
||||
if (Blockly.blockAnimations.disconnectGroup_) {
|
||||
clearTimeout(Blockly.blockAnimations.disconnectPid_);
|
||||
var group = Blockly.blockAnimations.disconnectGroup_;
|
||||
const disconnectUiStop = function() {
|
||||
if (disconnectGroup) {
|
||||
clearTimeout(disconnectPid);
|
||||
const group = disconnectGroup;
|
||||
group.skew_ = '';
|
||||
group.setAttribute('transform', group.translate_);
|
||||
Blockly.blockAnimations.disconnectGroup_ = null;
|
||||
disconnectGroup = null;
|
||||
}
|
||||
};
|
||||
/** @package */
|
||||
exports.disconnectUiStop = disconnectUiStop;
|
||||
|
||||
@@ -15,11 +15,13 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.BlockDragSurfaceSvg');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
goog.module('Blockly.BlockDragSurfaceSvg');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
const {G, SVG} = goog.require('Blockly.utils.Svg');
|
||||
const {createSvgElement, HTML_NS, setCssTransform, SVG_NS, XLINK_NS} = goog.require('Blockly.utils.dom');
|
||||
const {getRelativeXY} = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
@@ -28,7 +30,7 @@ goog.require('Blockly.utils.Svg');
|
||||
* @param {!Element} container Containing element.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg = function(container) {
|
||||
const BlockDragSurfaceSvg = function(container) {
|
||||
/**
|
||||
* @type {!Element}
|
||||
* @private
|
||||
@@ -38,11 +40,11 @@ Blockly.BlockDragSurfaceSvg = function(container) {
|
||||
};
|
||||
|
||||
/**
|
||||
* The SVG drag surface. Set once by Blockly.BlockDragSurfaceSvg.createDom.
|
||||
* The SVG drag surface. Set once by BlockDragSurfaceSvg.createDom.
|
||||
* @type {?SVGElement}
|
||||
* @private
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.SVG_ = null;
|
||||
BlockDragSurfaceSvg.prototype.SVG_ = null;
|
||||
|
||||
/**
|
||||
* This is where blocks live while they are being dragged if the drag surface
|
||||
@@ -50,14 +52,14 @@ Blockly.BlockDragSurfaceSvg.prototype.SVG_ = null;
|
||||
* @type {?SVGElement}
|
||||
* @private
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.dragGroup_ = null;
|
||||
BlockDragSurfaceSvg.prototype.dragGroup_ = null;
|
||||
|
||||
/**
|
||||
* Containing HTML element; parent of the workspace and the drag surface.
|
||||
* @type {?Element}
|
||||
* @private
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.container_ = null;
|
||||
BlockDragSurfaceSvg.prototype.container_ = null;
|
||||
|
||||
/**
|
||||
* Cached value for the scale of the drag surface.
|
||||
@@ -65,45 +67,43 @@ Blockly.BlockDragSurfaceSvg.prototype.container_ = null;
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.scale_ = 1;
|
||||
BlockDragSurfaceSvg.prototype.scale_ = 1;
|
||||
|
||||
/**
|
||||
* Cached value for the translation of the drag surface.
|
||||
* This translation is in pixel units, because the scale is applied to the
|
||||
* drag group rather than the top-level SVG.
|
||||
* @type {?Blockly.utils.Coordinate}
|
||||
* @type {?Coordinate}
|
||||
* @private
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.surfaceXY_ = null;
|
||||
BlockDragSurfaceSvg.prototype.surfaceXY_ = null;
|
||||
|
||||
/**
|
||||
* Cached value for the translation of the child drag surface in pixel units.
|
||||
* Since the child drag surface tracks the translation of the workspace this is
|
||||
* ultimately the translation of the workspace.
|
||||
* @type {!Blockly.utils.Coordinate}
|
||||
* @type {!Coordinate}
|
||||
* @private
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.childSurfaceXY_ =
|
||||
new Blockly.utils.Coordinate(0, 0);
|
||||
BlockDragSurfaceSvg.prototype.childSurfaceXY_ = new Coordinate(0, 0);
|
||||
|
||||
/**
|
||||
* Create the drag surface and inject it into the container.
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.createDom = function() {
|
||||
BlockDragSurfaceSvg.prototype.createDom = function() {
|
||||
if (this.SVG_) {
|
||||
return; // Already created.
|
||||
}
|
||||
this.SVG_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.SVG, {
|
||||
'xmlns': Blockly.utils.dom.SVG_NS,
|
||||
'xmlns:html': Blockly.utils.dom.HTML_NS,
|
||||
'xmlns:xlink': Blockly.utils.dom.XLINK_NS,
|
||||
this.SVG_ = createSvgElement(
|
||||
SVG, {
|
||||
'xmlns': SVG_NS,
|
||||
'xmlns:html': HTML_NS,
|
||||
'xmlns:xlink': XLINK_NS,
|
||||
'version': '1.1',
|
||||
'class': 'blocklyBlockDragSurface'
|
||||
},
|
||||
this.container_);
|
||||
this.dragGroup_ =
|
||||
Blockly.utils.dom.createSvgElement(Blockly.utils.Svg.G, {}, this.SVG_);
|
||||
this.dragGroup_ = createSvgElement(G, {}, this.SVG_);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -112,14 +112,14 @@ Blockly.BlockDragSurfaceSvg.prototype.createDom = function() {
|
||||
* @param {!SVGElement} blocks Block or group of blocks to place on the drag
|
||||
* surface.
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.setBlocksAndShow = function(blocks) {
|
||||
BlockDragSurfaceSvg.prototype.setBlocksAndShow = function(blocks) {
|
||||
if (this.dragGroup_.childNodes.length) {
|
||||
throw Error('Already dragging a block.');
|
||||
}
|
||||
// appendChild removes the blocks from the previous parent
|
||||
this.dragGroup_.appendChild(blocks);
|
||||
this.SVG_.style.display = 'block';
|
||||
this.surfaceXY_ = new Blockly.utils.Coordinate(0, 0);
|
||||
this.surfaceXY_ = new Coordinate(0, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -129,13 +129,12 @@ Blockly.BlockDragSurfaceSvg.prototype.setBlocksAndShow = function(blocks) {
|
||||
* @param {number} y Y translation in pixel coordinates.
|
||||
* @param {number} scale Scale of the group.
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.translateAndScaleGroup = function(
|
||||
x, y, scale) {
|
||||
BlockDragSurfaceSvg.prototype.translateAndScaleGroup = function(x, y, scale) {
|
||||
this.scale_ = scale;
|
||||
// This is a work-around to prevent a the blocks from rendering
|
||||
// fuzzy while they are being dragged on the drag surface.
|
||||
var fixedX = x.toFixed(0);
|
||||
var fixedY = y.toFixed(0);
|
||||
const fixedX = x.toFixed(0);
|
||||
const fixedY = y.toFixed(0);
|
||||
|
||||
this.childSurfaceXY_.x = parseInt(fixedX, 10);
|
||||
this.childSurfaceXY_.y = parseInt(fixedY, 10);
|
||||
@@ -149,17 +148,16 @@ Blockly.BlockDragSurfaceSvg.prototype.translateAndScaleGroup = function(
|
||||
* Translate the drag surface's SVG based on its internal state.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.translateSurfaceInternal_ = function() {
|
||||
var x = this.surfaceXY_.x;
|
||||
var y = this.surfaceXY_.y;
|
||||
BlockDragSurfaceSvg.prototype.translateSurfaceInternal_ = function() {
|
||||
let x = this.surfaceXY_.x;
|
||||
let y = this.surfaceXY_.y;
|
||||
// This is a work-around to prevent a the blocks from rendering
|
||||
// fuzzy while they are being dragged on the drag surface.
|
||||
x = x.toFixed(0);
|
||||
y = y.toFixed(0);
|
||||
this.SVG_.style.display = 'block';
|
||||
|
||||
Blockly.utils.dom.setCssTransform(
|
||||
this.SVG_, 'translate3d(' + x + 'px, ' + y + 'px, 0)');
|
||||
setCssTransform(this.SVG_, 'translate3d(' + x + 'px, ' + y + 'px, 0)');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -167,10 +165,10 @@ Blockly.BlockDragSurfaceSvg.prototype.translateSurfaceInternal_ = function() {
|
||||
* @param {number} deltaX Horizontal offset in pixel units.
|
||||
* @param {number} deltaY Vertical offset in pixel units.
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.translateBy = function(deltaX, deltaY) {
|
||||
var x = this.surfaceXY_.x + deltaX;
|
||||
var y = this.surfaceXY_.y + deltaY;
|
||||
this.surfaceXY_ = new Blockly.utils.Coordinate(x, y);
|
||||
BlockDragSurfaceSvg.prototype.translateBy = function(deltaX, deltaY) {
|
||||
const x = this.surfaceXY_.x + deltaX;
|
||||
const y = this.surfaceXY_.y + deltaY;
|
||||
this.surfaceXY_ = new Coordinate(x, y);
|
||||
this.translateSurfaceInternal_();
|
||||
};
|
||||
|
||||
@@ -182,20 +180,19 @@ Blockly.BlockDragSurfaceSvg.prototype.translateBy = function(deltaX, deltaY) {
|
||||
* @param {number} x X translation for the entire surface.
|
||||
* @param {number} y Y translation for the entire surface.
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.translateSurface = function(x, y) {
|
||||
this.surfaceXY_ =
|
||||
new Blockly.utils.Coordinate(x * this.scale_, y * this.scale_);
|
||||
BlockDragSurfaceSvg.prototype.translateSurface = function(x, y) {
|
||||
this.surfaceXY_ = new Coordinate(x * this.scale_, y * this.scale_);
|
||||
this.translateSurfaceInternal_();
|
||||
};
|
||||
|
||||
/**
|
||||
* Reports the surface translation in scaled workspace coordinates.
|
||||
* Use this when finishing a drag to return blocks to the correct position.
|
||||
* @return {!Blockly.utils.Coordinate} Current translation of the surface.
|
||||
* @return {!Coordinate} Current translation of the surface.
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.getSurfaceTranslation = function() {
|
||||
var xy = Blockly.utils.getRelativeXY(/** @type {!SVGElement} */ (this.SVG_));
|
||||
return new Blockly.utils.Coordinate(xy.x / this.scale_, xy.y / this.scale_);
|
||||
BlockDragSurfaceSvg.prototype.getSurfaceTranslation = function() {
|
||||
const xy = getRelativeXY(/** @type {!SVGElement} */ (this.SVG_));
|
||||
return new Coordinate(xy.x / this.scale_, xy.y / this.scale_);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -203,7 +200,7 @@ Blockly.BlockDragSurfaceSvg.prototype.getSurfaceTranslation = function() {
|
||||
* BlockSvg.getRelativeToSurfaceXY).
|
||||
* @return {?SVGElement} Drag surface group element.
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.getGroup = function() {
|
||||
BlockDragSurfaceSvg.prototype.getGroup = function() {
|
||||
return this.dragGroup_;
|
||||
};
|
||||
|
||||
@@ -211,16 +208,17 @@ Blockly.BlockDragSurfaceSvg.prototype.getGroup = function() {
|
||||
* Returns the SVG drag surface.
|
||||
* @returns {?SVGElement} The SVG drag surface.
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.getSvgRoot = function() {
|
||||
BlockDragSurfaceSvg.prototype.getSvgRoot = function() {
|
||||
return this.SVG_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current blocks on the drag surface, if any (primarily
|
||||
* for BlockSvg.getRelativeToSurfaceXY).
|
||||
* @return {?Element} Drag surface block DOM element, or null if no blocks exist.
|
||||
* @return {?Element} Drag surface block DOM element, or null if no blocks
|
||||
* exist.
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.getCurrentBlock = function() {
|
||||
BlockDragSurfaceSvg.prototype.getCurrentBlock = function() {
|
||||
return /** @type {Element} */ (this.dragGroup_.firstChild);
|
||||
};
|
||||
|
||||
@@ -228,9 +226,9 @@ Blockly.BlockDragSurfaceSvg.prototype.getCurrentBlock = function() {
|
||||
* Gets the translation of the child block surface
|
||||
* This surface is in charge of keeping track of how much the workspace has
|
||||
* moved.
|
||||
* @return {!Blockly.utils.Coordinate} The amount the workspace has been moved.
|
||||
* @return {!Coordinate} The amount the workspace has been moved.
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.getWsTranslation = function() {
|
||||
BlockDragSurfaceSvg.prototype.getWsTranslation = function() {
|
||||
// Returning a copy so the coordinate can not be changed outside this class.
|
||||
return this.childSurfaceXY_.clone();
|
||||
};
|
||||
@@ -244,7 +242,7 @@ Blockly.BlockDragSurfaceSvg.prototype.getWsTranslation = function() {
|
||||
* to, or null if the blocks should be removed from this surface without
|
||||
* being moved to a different surface.
|
||||
*/
|
||||
Blockly.BlockDragSurfaceSvg.prototype.clearAndHide = function(opt_newSurface) {
|
||||
BlockDragSurfaceSvg.prototype.clearAndHide = function(opt_newSurface) {
|
||||
if (opt_newSurface) {
|
||||
// appendChild removes the node from this.dragGroup_
|
||||
opt_newSurface.appendChild(this.getCurrentBlock());
|
||||
@@ -257,3 +255,5 @@ Blockly.BlockDragSurfaceSvg.prototype.clearAndHide = function(opt_newSurface) {
|
||||
}
|
||||
this.surfaceXY_ = null;
|
||||
};
|
||||
|
||||
exports = BlockDragSurfaceSvg;
|
||||
|
||||
@@ -10,61 +10,63 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.BlockDragger');
|
||||
goog.module('Blockly.BlockDragger');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.blockAnimations');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.Events');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IBlockDragger = goog.require('Blockly.IBlockDragger');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDragTarget = goog.requireType('Blockly.IDragTarget');
|
||||
const InsertionMarkerManager = goog.require('Blockly.InsertionMarkerManager');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const blockAnimation = goog.require('Blockly.blockAnimations');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const events = goog.require('Blockly.Events');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockDrag');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockMove');
|
||||
goog.require('Blockly.IBlockDragger');
|
||||
goog.require('Blockly.InsertionMarkerManager');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.utils.dom');
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.IDragTarget');
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a block dragger. It moves blocks around the workspace when they
|
||||
* are being dragged by a mouse or touch.
|
||||
* @param {!Blockly.BlockSvg} block The block to drag.
|
||||
* @param {!Blockly.WorkspaceSvg} workspace The workspace to drag on.
|
||||
* @param {!BlockSvg} block The block to drag.
|
||||
* @param {!WorkspaceSvg} workspace The workspace to drag on.
|
||||
* @constructor
|
||||
* @implements {Blockly.IBlockDragger}
|
||||
* @implements {IBlockDragger}
|
||||
*/
|
||||
Blockly.BlockDragger = function(block, workspace) {
|
||||
const BlockDragger = function(block, workspace) {
|
||||
/**
|
||||
* The top block in the stack that is being dragged.
|
||||
* @type {!Blockly.BlockSvg}
|
||||
* @type {!BlockSvg}
|
||||
* @protected
|
||||
*/
|
||||
this.draggingBlock_ = block;
|
||||
|
||||
/**
|
||||
* The workspace on which the block is being dragged.
|
||||
* @type {!Blockly.WorkspaceSvg}
|
||||
* @type {!WorkspaceSvg}
|
||||
* @protected
|
||||
*/
|
||||
this.workspace_ = workspace;
|
||||
|
||||
/**
|
||||
* Object that keeps track of connections on dragged blocks.
|
||||
* @type {!Blockly.InsertionMarkerManager}
|
||||
* @type {!InsertionMarkerManager}
|
||||
* @protected
|
||||
*/
|
||||
this.draggedConnectionManager_ =
|
||||
new Blockly.InsertionMarkerManager(this.draggingBlock_);
|
||||
new InsertionMarkerManager(this.draggingBlock_);
|
||||
|
||||
/**
|
||||
* Which drag area the mouse pointer is over, if any.
|
||||
* @type {?Blockly.IDragTarget}
|
||||
* @type {?IDragTarget}
|
||||
* @private
|
||||
*/
|
||||
this.dragTarget_ = null;
|
||||
@@ -79,7 +81,7 @@ Blockly.BlockDragger = function(block, workspace) {
|
||||
/**
|
||||
* The location of the top left corner of the dragging block at the beginning
|
||||
* of the drag in workspace coordinates.
|
||||
* @type {!Blockly.utils.Coordinate}
|
||||
* @type {!Coordinate}
|
||||
* @protected
|
||||
*/
|
||||
this.startXY_ = this.draggingBlock_.getRelativeToSurfaceXY();
|
||||
@@ -91,14 +93,14 @@ Blockly.BlockDragger = function(block, workspace) {
|
||||
* @type {Array<!Object>}
|
||||
* @protected
|
||||
*/
|
||||
this.dragIconData_ = Blockly.BlockDragger.initIconData_(block);
|
||||
this.dragIconData_ = initIconData(block);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sever all links from this object.
|
||||
* @package
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.dispose = function() {
|
||||
BlockDragger.prototype.dispose = function() {
|
||||
this.dragIconData_.length = 0;
|
||||
|
||||
if (this.draggedConnectionManager_) {
|
||||
@@ -110,19 +112,19 @@ Blockly.BlockDragger.prototype.dispose = function() {
|
||||
* Make a list of all of the icons (comment, warning, and mutator) that are
|
||||
* on this block and its descendants. Moving an icon moves the bubble that
|
||||
* extends from it if that bubble is open.
|
||||
* @param {!Blockly.BlockSvg} block The root block that is being dragged.
|
||||
* @param {!BlockSvg} block The root block that is being dragged.
|
||||
* @return {!Array<!Object>} The list of all icons and their locations.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BlockDragger.initIconData_ = function(block) {
|
||||
const initIconData = function(block) {
|
||||
// Build a list of icons that need to be moved and where they started.
|
||||
var dragIconData = [];
|
||||
var descendants = block.getDescendants(false);
|
||||
for (var i = 0, descendant; (descendant = descendants[i]); i++) {
|
||||
var icons = descendant.getIcons();
|
||||
for (var j = 0; j < icons.length; j++) {
|
||||
var data = {
|
||||
// Blockly.utils.Coordinate with x and y properties (workspace
|
||||
const dragIconData = [];
|
||||
const descendants = block.getDescendants(false);
|
||||
|
||||
for (let i = 0, descendant; (descendant = descendants[i]); i++) {
|
||||
const icons = descendant.getIcons();
|
||||
for (let j = 0; j < icons.length; j++) {
|
||||
const data = {
|
||||
// Coordinate with x and y properties (workspace
|
||||
// coordinates).
|
||||
location: icons[j].getIconLocation(),
|
||||
// Blockly.Icon
|
||||
@@ -136,16 +138,15 @@ Blockly.BlockDragger.initIconData_ = function(block) {
|
||||
|
||||
/**
|
||||
* Start dragging a block. This includes moving it to the drag surface.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the position at mouse down, in pixel units.
|
||||
* @param {boolean} healStack Whether or not to heal the stack after
|
||||
* disconnecting.
|
||||
* @public
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.startDrag = function(
|
||||
currentDragDeltaXY, healStack) {
|
||||
if (!Blockly.Events.getGroup()) {
|
||||
Blockly.Events.setGroup(true);
|
||||
BlockDragger.prototype.startDrag = function(currentDragDeltaXY, healStack) {
|
||||
if (!events.getGroup()) {
|
||||
events.setGroup(true);
|
||||
}
|
||||
this.fireDragStartEvent_();
|
||||
|
||||
@@ -159,9 +160,9 @@ Blockly.BlockDragger.prototype.startDrag = function(
|
||||
|
||||
// During a drag there may be a lot of rerenders, but not field changes.
|
||||
// Turn the cache on so we don't do spurious remeasures during the drag.
|
||||
Blockly.utils.dom.startTextWidthCache();
|
||||
dom.startTextWidthCache();
|
||||
this.workspace_.setResizesEnabled(false);
|
||||
Blockly.blockAnimations.disconnectUiStop();
|
||||
blockAnimation.disconnectUiStop();
|
||||
|
||||
if (this.shouldDisconnect_(healStack)) {
|
||||
this.disconnectBlock_(healStack, currentDragDeltaXY);
|
||||
@@ -180,9 +181,9 @@ Blockly.BlockDragger.prototype.startDrag = function(
|
||||
* @return {boolean} True to disconnect the block, false otherwise.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.shouldDisconnect_ = function(healStack) {
|
||||
BlockDragger.prototype.shouldDisconnect_ = function(healStack) {
|
||||
return !!(
|
||||
this.draggingBlock_.getParent() ||
|
||||
this.draggingBlock_.getParent() ||
|
||||
(healStack && this.draggingBlock_.nextConnection &&
|
||||
this.draggingBlock_.nextConnection.targetBlock()));
|
||||
};
|
||||
@@ -191,18 +192,18 @@ Blockly.BlockDragger.prototype.shouldDisconnect_ = function(healStack) {
|
||||
* Disconnects the block and moves it to a new location.
|
||||
* @param {boolean} healStack Whether or not to heal the stack after
|
||||
* disconnecting.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the position at mouse down, in pixel units.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.disconnectBlock_ = function(
|
||||
BlockDragger.prototype.disconnectBlock_ = function(
|
||||
healStack, currentDragDeltaXY) {
|
||||
this.draggingBlock_.unplug(healStack);
|
||||
var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
|
||||
var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta);
|
||||
const delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
|
||||
const newLoc = Coordinate.sum(this.startXY_, delta);
|
||||
|
||||
this.draggingBlock_.translate(newLoc.x, newLoc.y);
|
||||
Blockly.blockAnimations.disconnectUiEffect(this.draggingBlock_);
|
||||
blockAnimation.disconnectUiEffect(this.draggingBlock_);
|
||||
this.draggedConnectionManager_.updateAvailableConnections();
|
||||
};
|
||||
|
||||
@@ -210,31 +211,31 @@ Blockly.BlockDragger.prototype.disconnectBlock_ = function(
|
||||
* Fire a UI event at the start of a block drag.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.fireDragStartEvent_ = function() {
|
||||
var event = new (Blockly.Events.get(Blockly.Events.BLOCK_DRAG))(
|
||||
BlockDragger.prototype.fireDragStartEvent_ = function() {
|
||||
const event = new (events.get(events.BLOCK_DRAG))(
|
||||
this.draggingBlock_, true, this.draggingBlock_.getDescendants(false));
|
||||
Blockly.Events.fire(event);
|
||||
events.fire(event);
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a step of block dragging, based on the given event. Update the
|
||||
* display accordingly.
|
||||
* @param {!Event} e The most recent move event.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the position at the start of the drag, in pixel units.
|
||||
* @public
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.drag = function(e, currentDragDeltaXY) {
|
||||
var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
|
||||
var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta);
|
||||
BlockDragger.prototype.drag = function(e, currentDragDeltaXY) {
|
||||
const delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
|
||||
const newLoc = Coordinate.sum(this.startXY_, delta);
|
||||
this.draggingBlock_.moveDuringDrag(newLoc);
|
||||
this.dragIcons_(delta);
|
||||
|
||||
var oldDragTarget = this.dragTarget_;
|
||||
const oldDragTarget = this.dragTarget_;
|
||||
this.dragTarget_ = this.workspace_.getDragTarget(e);
|
||||
|
||||
this.draggedConnectionManager_.update(delta, this.dragTarget_);
|
||||
var oldWouldDeleteBlock = this.wouldDeleteBlock_;
|
||||
const oldWouldDeleteBlock = this.wouldDeleteBlock_;
|
||||
this.wouldDeleteBlock_ = this.draggedConnectionManager_.wouldDeleteBlock();
|
||||
if (oldWouldDeleteBlock != this.wouldDeleteBlock_) {
|
||||
// Prevent unnecessary add/remove class calls.
|
||||
@@ -253,26 +254,26 @@ Blockly.BlockDragger.prototype.drag = function(e, currentDragDeltaXY) {
|
||||
/**
|
||||
* Finish a block drag and put the block back on the workspace.
|
||||
* @param {!Event} e The mouseup/touchend event.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the position at the start of the drag, in pixel units.
|
||||
* @public
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.endDrag = function(e, currentDragDeltaXY) {
|
||||
BlockDragger.prototype.endDrag = function(e, currentDragDeltaXY) {
|
||||
// Make sure internal state is fresh.
|
||||
this.drag(e, currentDragDeltaXY);
|
||||
this.dragIconData_ = [];
|
||||
this.fireDragEndEvent_();
|
||||
|
||||
Blockly.utils.dom.stopTextWidthCache();
|
||||
dom.stopTextWidthCache();
|
||||
|
||||
Blockly.blockAnimations.disconnectUiStop();
|
||||
blockAnimation.disconnectUiStop();
|
||||
|
||||
var preventMove = !!this.dragTarget_ &&
|
||||
const preventMove = !!this.dragTarget_ &&
|
||||
this.dragTarget_.shouldPreventMove(this.draggingBlock_);
|
||||
if (preventMove) {
|
||||
var newLoc = this.startXY_;
|
||||
} else {
|
||||
var newValues = this.getNewLocationAfterDrag_(currentDragDeltaXY);
|
||||
const newValues = this.getNewLocationAfterDrag_(currentDragDeltaXY);
|
||||
var delta = newValues.delta;
|
||||
var newLoc = newValues.newLocation;
|
||||
}
|
||||
@@ -282,7 +283,7 @@ Blockly.BlockDragger.prototype.endDrag = function(e, currentDragDeltaXY) {
|
||||
this.dragTarget_.onDrop(this.draggingBlock_);
|
||||
}
|
||||
|
||||
var deleted = this.maybeDeleteBlock_();
|
||||
const deleted = this.maybeDeleteBlock_();
|
||||
if (!deleted) {
|
||||
// These are expensive and don't need to be done if we're deleting.
|
||||
this.draggingBlock_.setDragging(false);
|
||||
@@ -299,25 +300,23 @@ Blockly.BlockDragger.prototype.endDrag = function(e, currentDragDeltaXY) {
|
||||
}
|
||||
this.workspace_.setResizesEnabled(true);
|
||||
|
||||
Blockly.Events.setGroup(false);
|
||||
events.setGroup(false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates the drag delta and new location values after a block is dragged.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the start of the drag, in pixel units.
|
||||
* @return {{delta: !Blockly.utils.Coordinate, newLocation:
|
||||
* !Blockly.utils.Coordinate}} New location after drag. delta is in
|
||||
* @return {{delta: !Coordinate, newLocation:
|
||||
* !Coordinate}} New location after drag. delta is in
|
||||
* workspace units. newLocation is the new coordinate where the block should
|
||||
* end up.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.getNewLocationAfterDrag_ = function(
|
||||
currentDragDeltaXY) {
|
||||
var newValues = {};
|
||||
BlockDragger.prototype.getNewLocationAfterDrag_ = function(currentDragDeltaXY) {
|
||||
const newValues = {};
|
||||
newValues.delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
|
||||
newValues.newLocation =
|
||||
Blockly.utils.Coordinate.sum(this.startXY_, newValues.delta);
|
||||
newValues.newLocation = Coordinate.sum(this.startXY_, newValues.delta);
|
||||
return newValues;
|
||||
};
|
||||
|
||||
@@ -328,7 +327,7 @@ Blockly.BlockDragger.prototype.getNewLocationAfterDrag_ = function(
|
||||
* @return {boolean} True if the block was deleted.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.maybeDeleteBlock_ = function() {
|
||||
BlockDragger.prototype.maybeDeleteBlock_ = function() {
|
||||
if (this.wouldDeleteBlock_) {
|
||||
// Fire a move event, so we know where to go back to for an undo.
|
||||
this.fireMoveEvent_();
|
||||
@@ -341,11 +340,11 @@ Blockly.BlockDragger.prototype.maybeDeleteBlock_ = function() {
|
||||
|
||||
/**
|
||||
* Updates the necessary information to place a block at a certain location.
|
||||
* @param {!Blockly.utils.Coordinate} delta The change in location from where
|
||||
* @param {!Coordinate} delta The change in location from where
|
||||
* the block started the drag to where it ended the drag.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.updateBlockAfterMove_ = function(delta) {
|
||||
BlockDragger.prototype.updateBlockAfterMove_ = function(delta) {
|
||||
this.draggingBlock_.moveConnections(delta.x, delta.y);
|
||||
this.fireMoveEvent_();
|
||||
if (this.draggedConnectionManager_.wouldConnectBlock()) {
|
||||
@@ -361,10 +360,10 @@ Blockly.BlockDragger.prototype.updateBlockAfterMove_ = function(delta) {
|
||||
* Fire a UI event at the end of a block drag.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.fireDragEndEvent_ = function() {
|
||||
var event = new (Blockly.Events.get(Blockly.Events.BLOCK_DRAG))(
|
||||
BlockDragger.prototype.fireDragEndEvent_ = function() {
|
||||
const event = new (events.get(events.BLOCK_DRAG))(
|
||||
this.draggingBlock_, false, this.draggingBlock_.getDescendants(false));
|
||||
Blockly.Events.fire(event);
|
||||
events.fire(event);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -374,12 +373,12 @@ Blockly.BlockDragger.prototype.fireDragEndEvent_ = function() {
|
||||
* @param {boolean} isEnd True if we are at the end of a drag, false otherwise.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.updateToolboxStyle_ = function(isEnd) {
|
||||
var toolbox = this.workspace_.getToolbox();
|
||||
BlockDragger.prototype.updateToolboxStyle_ = function(isEnd) {
|
||||
const toolbox = this.workspace_.getToolbox();
|
||||
|
||||
if (toolbox) {
|
||||
var style = this.draggingBlock_.isDeletable() ? 'blocklyToolboxDelete' :
|
||||
'blocklyToolboxGrab';
|
||||
const style = this.draggingBlock_.isDeletable() ? 'blocklyToolboxDelete' :
|
||||
'blocklyToolboxGrab';
|
||||
|
||||
if (isEnd && typeof toolbox.removeStyle == 'function') {
|
||||
toolbox.removeStyle(style);
|
||||
@@ -394,12 +393,11 @@ Blockly.BlockDragger.prototype.updateToolboxStyle_ = function(isEnd) {
|
||||
* Fire a move event at the end of a block drag.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.fireMoveEvent_ = function() {
|
||||
var event =
|
||||
new (Blockly.Events.get(Blockly.Events.BLOCK_MOVE))(this.draggingBlock_);
|
||||
BlockDragger.prototype.fireMoveEvent_ = function() {
|
||||
const event = new (events.get(events.BLOCK_MOVE))(this.draggingBlock_);
|
||||
event.oldCoordinate = this.startXY_;
|
||||
event.recordNew();
|
||||
Blockly.Events.fire(event);
|
||||
events.fire(event);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -407,7 +405,7 @@ Blockly.BlockDragger.prototype.fireMoveEvent_ = function() {
|
||||
* dragging block would be deleted if released immediately.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.updateCursorDuringBlockDrag_ = function() {
|
||||
BlockDragger.prototype.updateCursorDuringBlockDrag_ = function() {
|
||||
this.draggingBlock_.setDeleteStyle(this.wouldDeleteBlock_);
|
||||
};
|
||||
|
||||
@@ -416,14 +414,14 @@ Blockly.BlockDragger.prototype.updateCursorDuringBlockDrag_ = function() {
|
||||
* correction for mutator workspaces.
|
||||
* This function does not consider differing origins. It simply scales the
|
||||
* input's x and y values.
|
||||
* @param {!Blockly.utils.Coordinate} pixelCoord A coordinate with x and y
|
||||
* @param {!Coordinate} pixelCoord A coordinate with x and y
|
||||
* values in CSS pixel units.
|
||||
* @return {!Blockly.utils.Coordinate} The input coordinate divided by the
|
||||
* @return {!Coordinate} The input coordinate divided by the
|
||||
* workspace scale.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) {
|
||||
var result = new Blockly.utils.Coordinate(
|
||||
BlockDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) {
|
||||
const result = new Coordinate(
|
||||
pixelCoord.x / this.workspace_.scale,
|
||||
pixelCoord.y / this.workspace_.scale);
|
||||
if (this.workspace_.isMutator) {
|
||||
@@ -431,7 +429,7 @@ Blockly.BlockDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) {
|
||||
// oddities in our rendering optimizations. The actual scale is the same as
|
||||
// the scale on the parent workspace.
|
||||
// Fix that for dragging.
|
||||
var mainScale = this.workspace_.options.parentWorkspace.scale;
|
||||
const mainScale = this.workspace_.options.parentWorkspace.scale;
|
||||
result.scale(1 / mainScale);
|
||||
}
|
||||
return result;
|
||||
@@ -439,26 +437,26 @@ Blockly.BlockDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) {
|
||||
|
||||
/**
|
||||
* Move all of the icons connected to this drag.
|
||||
* @param {!Blockly.utils.Coordinate} dxy How far to move the icons from their
|
||||
* @param {!Coordinate} dxy How far to move the icons from their
|
||||
* original positions, in workspace units.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.dragIcons_ = function(dxy) {
|
||||
BlockDragger.prototype.dragIcons_ = function(dxy) {
|
||||
// Moving icons moves their associated bubbles.
|
||||
for (var i = 0; i < this.dragIconData_.length; i++) {
|
||||
var data = this.dragIconData_[i];
|
||||
data.icon.setIconLocation(Blockly.utils.Coordinate.sum(data.location, dxy));
|
||||
for (let i = 0; i < this.dragIconData_.length; i++) {
|
||||
const data = this.dragIconData_[i];
|
||||
data.icon.setIconLocation(Coordinate.sum(data.location, dxy));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a list of the insertion markers that currently exist. Drags have 0, 1,
|
||||
* or 2 insertion markers.
|
||||
* @return {!Array<!Blockly.BlockSvg>} A possibly empty list of insertion
|
||||
* @return {!Array<!BlockSvg>} A possibly empty list of insertion
|
||||
* marker blocks.
|
||||
* @public
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.getInsertionMarkers = function() {
|
||||
BlockDragger.prototype.getInsertionMarkers = function() {
|
||||
// No insertion markers with the old style of dragged connection managers.
|
||||
if (this.draggedConnectionManager_ &&
|
||||
this.draggedConnectionManager_.getInsertionMarkers) {
|
||||
@@ -467,6 +465,6 @@ Blockly.BlockDragger.prototype.getInsertionMarkers = function() {
|
||||
return [];
|
||||
};
|
||||
|
||||
Blockly.registry.register(
|
||||
Blockly.registry.Type.BLOCK_DRAGGER, Blockly.registry.DEFAULT,
|
||||
Blockly.BlockDragger);
|
||||
registry.register(registry.Type.BLOCK_DRAGGER, registry.DEFAULT, BlockDragger);
|
||||
|
||||
exports = BlockDragger;
|
||||
|
||||
@@ -18,7 +18,6 @@ goog.require('Blockly.blockAnimations');
|
||||
goog.require('Blockly.blockRendering.IPathObject');
|
||||
goog.require('Blockly.browserEvents');
|
||||
goog.require('Blockly.connectionTypes');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.ContextMenu');
|
||||
goog.require('Blockly.ContextMenuRegistry');
|
||||
@@ -31,6 +30,7 @@ goog.require('Blockly.IASTNodeLocationSvg');
|
||||
goog.require('Blockly.IBoundedElement');
|
||||
goog.require('Blockly.ICopyable');
|
||||
goog.require('Blockly.IDraggable');
|
||||
goog.require('Blockly.internalConstants');
|
||||
goog.require('Blockly.Msg');
|
||||
goog.require('Blockly.RenderedConnection');
|
||||
goog.require('Blockly.TabNavigateCursor');
|
||||
@@ -688,7 +688,7 @@ Blockly.BlockSvg.prototype.updateCollapsed_ = function() {
|
||||
icon.setVisible(false);
|
||||
}
|
||||
|
||||
var text = this.toString(Blockly.COLLAPSE_CHARS);
|
||||
var text = this.toString(Blockly.internalConstants.COLLAPSE_CHARS);
|
||||
var field = this.getField(collapsedFieldName);
|
||||
if (field) {
|
||||
field.setValue(text);
|
||||
@@ -1550,7 +1550,8 @@ Blockly.BlockSvg.prototype.bumpNeighbours = function() {
|
||||
connection.targetBlock().bumpNeighbours();
|
||||
}
|
||||
|
||||
var neighbours = connection.neighbours(Blockly.SNAP_RADIUS);
|
||||
var neighbours =
|
||||
connection.neighbours(Blockly.internalConstants.SNAP_RADIUS);
|
||||
for (var j = 0, otherConnection; (otherConnection = neighbours[j]); j++) {
|
||||
|
||||
// If both connections are connected, that's probably fine. But if
|
||||
@@ -1585,13 +1586,13 @@ Blockly.BlockSvg.prototype.scheduleSnapAndBump = function() {
|
||||
Blockly.Events.setGroup(group);
|
||||
block.snapToGrid();
|
||||
Blockly.Events.setGroup(false);
|
||||
}, Blockly.BUMP_DELAY / 2);
|
||||
}, Blockly.internalConstants.BUMP_DELAY / 2);
|
||||
|
||||
setTimeout(function() {
|
||||
Blockly.Events.setGroup(group);
|
||||
block.bumpNeighbours();
|
||||
Blockly.Events.setGroup(false);
|
||||
}, Blockly.BUMP_DELAY);
|
||||
}, Blockly.internalConstants.BUMP_DELAY);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,6 +35,7 @@ goog.require('Blockly.Events.VarCreate');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.inject');
|
||||
goog.require('Blockly.inputTypes');
|
||||
goog.require('Blockly.internalConstants');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Procedures');
|
||||
goog.require('Blockly.ShortcutRegistry');
|
||||
@@ -424,8 +425,9 @@ Blockly.isNumber = function(str) {
|
||||
* @return {string} RGB code, e.g. '#5ba65b'.
|
||||
*/
|
||||
Blockly.hueToHex = function(hue) {
|
||||
return Blockly.utils.colour.hsvToHex(hue, Blockly.HSV_SATURATION,
|
||||
Blockly.HSV_VALUE * 255);
|
||||
return Blockly.utils.colour.hsvToHex(
|
||||
hue, Blockly.internalConstants.HSV_SATURATION,
|
||||
Blockly.internalConstants.HSV_VALUE * 255);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -596,3 +598,38 @@ Blockly.TOOLBOX_AT_LEFT = Blockly.utils.toolbox.Position.LEFT;
|
||||
* @see Blockly.utils.toolbox.Position.RIGHT
|
||||
*/
|
||||
Blockly.TOOLBOX_AT_RIGHT = Blockly.utils.toolbox.Position.RIGHT;
|
||||
|
||||
// Aliases to allow external code to access these values for legacy reasons.
|
||||
Blockly.LINE_MODE_MULTIPLIER = Blockly.internalConstants.LINE_MODE_MULTIPLIER;
|
||||
Blockly.PAGE_MODE_MULTIPLIER = Blockly.internalConstants.PAGE_MODE_MULTIPLIER;
|
||||
Blockly.DRAG_RADIUS = Blockly.internalConstants.DRAG_RADIUS;
|
||||
Blockly.FLYOUT_DRAG_RADIUS = Blockly.internalConstants.FLYOUT_DRAG_RADIUS;
|
||||
Blockly.SNAP_RADIUS = Blockly.internalConstants.SNAP_RADIUS;
|
||||
Blockly.CONNECTING_SNAP_RADIUS =
|
||||
Blockly.internalConstants.CONNECTING_SNAP_RADIUS;
|
||||
Blockly.CURRENT_CONNECTION_PREFERENCE =
|
||||
Blockly.internalConstants.CURRENT_CONNECTION_PREFERENCE;
|
||||
Blockly.BUMP_DELAY = Blockly.internalConstants.BUMP_DELAY;
|
||||
Blockly.BUMP_RANDOMNESS = Blockly.internalConstants.BUMP_RANDOMNESS;
|
||||
Blockly.COLLAPSE_CHARS = Blockly.internalConstants.COLLAPSE_CHARS;
|
||||
Blockly.LONGPRESS = Blockly.internalConstants.LONGPRESS;
|
||||
Blockly.SOUND_LIMIT = Blockly.internalConstants.SOUND_LIMIT;
|
||||
Blockly.DRAG_STACK = Blockly.internalConstants.DRAG_STACK;
|
||||
Blockly.HSV_SATURATION = Blockly.internalConstants.HSV_SATURATION;
|
||||
Blockly.HSV_VALUE = Blockly.internalConstants.HSV_VALUE;
|
||||
Blockly.SPRITE = Blockly.internalConstants.SPRITE;
|
||||
Blockly.DRAG_NONE = Blockly.internalConstants.DRAG_NONE;
|
||||
Blockly.DRAG_STICKY = Blockly.internalConstants.DRAG_STICKY;
|
||||
Blockly.DRAG_BEGIN = Blockly.internalConstants.DRAG_BEGIN;
|
||||
Blockly.DRAG_FREE = Blockly.internalConstants.DRAG_FREE;
|
||||
Blockly.OPPOSITE_TYPE = Blockly.internalConstants.OPPOSITE_TYPE;
|
||||
Blockly.VARIABLE_CATEGORY_NAME =
|
||||
Blockly.internalConstants.VARIABLE_CATEGORY_NAME;
|
||||
Blockly.VARIABLE_DYNAMIC_CATEGORY_NAME =
|
||||
Blockly.internalConstants.VARIABLE_DYNAMIC_CATEGORY_NAME;
|
||||
Blockly.PROCEDURE_CATEGORY_NAME =
|
||||
Blockly.internalConstants.PROCEDURE_CATEGORY_NAME;
|
||||
Blockly.RENAME_VARIABLE_ID = Blockly.internalConstants.RENAME_VARIABLE_ID;
|
||||
Blockly.DELETE_VARIABLE_ID = Blockly.internalConstants.DELETE_VARIABLE_ID;
|
||||
Blockly.COLLAPSED_INPUT_NAME = Blockly.constants.COLLAPSED_INPUT_NAME;
|
||||
Blockly.COLLAPSED_FIELD_NAME = Blockly.constants.COLLAPSED_FIELD_NAME;
|
||||
|
||||
@@ -14,10 +14,13 @@
|
||||
* A mapping of block type names to block prototype objects.
|
||||
* @name Blockly.Blocks
|
||||
*/
|
||||
goog.provide('Blockly.Blocks');
|
||||
goog.module('Blockly.Blocks');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/**
|
||||
* A mapping of block type names to block prototype objects.
|
||||
* @type {!Object<string,Object>}
|
||||
* @type {!Object<string,!Object>}
|
||||
*/
|
||||
Blockly.Blocks = Object.create(null);
|
||||
const Blocks = Object.create(null);
|
||||
|
||||
exports = Blocks;
|
||||
|
||||
@@ -10,50 +10,57 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.BubbleDragger');
|
||||
goog.module('Blockly.BubbleDragger');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockDragSurfaceSvg = goog.requireType('Blockly.BlockDragSurfaceSvg');
|
||||
const ComponentManager = goog.require('Blockly.ComponentManager');
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IBubble = goog.requireType('Blockly.IBubble');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDeleteArea = goog.requireType('Blockly.IDeleteArea');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDragTarget = goog.requireType('Blockly.IDragTarget');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Bubble');
|
||||
goog.require('Blockly.ComponentManager');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.Events');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.CommentMove');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
|
||||
goog.requireType('Blockly.BlockDragSurfaceSvg');
|
||||
goog.requireType('Blockly.IBubble');
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a bubble dragger. It moves things on the bubble canvas around the
|
||||
* workspace when they are being dragged by a mouse or touch. These can be
|
||||
* block comments, mutators, warnings, or workspace comments.
|
||||
* @param {!Blockly.IBubble} bubble The item on the bubble canvas to drag.
|
||||
* @param {!Blockly.WorkspaceSvg} workspace The workspace to drag on.
|
||||
* @param {!IBubble} bubble The item on the bubble canvas to drag.
|
||||
* @param {!WorkspaceSvg} workspace The workspace to drag on.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.BubbleDragger = function(bubble, workspace) {
|
||||
const BubbleDragger = function(bubble, workspace) {
|
||||
/**
|
||||
* The item on the bubble canvas that is being dragged.
|
||||
* @type {!Blockly.IBubble}
|
||||
* @type {!IBubble}
|
||||
* @private
|
||||
*/
|
||||
this.draggingBubble_ = bubble;
|
||||
|
||||
/**
|
||||
* The workspace on which the bubble is being dragged.
|
||||
* @type {!Blockly.WorkspaceSvg}
|
||||
* @type {!WorkspaceSvg}
|
||||
* @private
|
||||
*/
|
||||
this.workspace_ = workspace;
|
||||
|
||||
/**
|
||||
* Which drag target the mouse pointer is over, if any.
|
||||
* @type {?Blockly.IDragTarget}
|
||||
* @type {?IDragTarget}
|
||||
* @private
|
||||
*/
|
||||
this.dragTarget_ = null;
|
||||
@@ -68,7 +75,7 @@ Blockly.BubbleDragger = function(bubble, workspace) {
|
||||
/**
|
||||
* The location of the top left corner of the dragging bubble's body at the
|
||||
* beginning of the drag, in workspace coordinates.
|
||||
* @type {!Blockly.utils.Coordinate}
|
||||
* @type {!Coordinate}
|
||||
* @private
|
||||
*/
|
||||
this.startXY_ = this.draggingBubble_.getRelativeToSurfaceXY();
|
||||
@@ -76,11 +83,11 @@ Blockly.BubbleDragger = function(bubble, workspace) {
|
||||
/**
|
||||
* The drag surface to move bubbles to during a drag, or null if none should
|
||||
* be used. Block dragging and bubble dragging use the same surface.
|
||||
* @type {Blockly.BlockDragSurfaceSvg}
|
||||
* @type {BlockDragSurfaceSvg}
|
||||
* @private
|
||||
*/
|
||||
this.dragSurface_ =
|
||||
Blockly.utils.is3dSupported() && !!workspace.getBlockDragSurface() ?
|
||||
utils.is3dSupported() && !!workspace.getBlockDragSurface() ?
|
||||
workspace.getBlockDragSurface() :
|
||||
null;
|
||||
};
|
||||
@@ -90,7 +97,7 @@ Blockly.BubbleDragger = function(bubble, workspace) {
|
||||
* @package
|
||||
* @suppress {checkTypes}
|
||||
*/
|
||||
Blockly.BubbleDragger.prototype.dispose = function() {
|
||||
BubbleDragger.prototype.dispose = function() {
|
||||
this.draggingBubble_ = null;
|
||||
this.workspace_ = null;
|
||||
this.dragSurface_ = null;
|
||||
@@ -100,9 +107,9 @@ Blockly.BubbleDragger.prototype.dispose = function() {
|
||||
* Start dragging a bubble. This includes moving it to the drag surface.
|
||||
* @package
|
||||
*/
|
||||
Blockly.BubbleDragger.prototype.startBubbleDrag = function() {
|
||||
if (!Blockly.Events.getGroup()) {
|
||||
Blockly.Events.setGroup(true);
|
||||
BubbleDragger.prototype.startBubbleDrag = function() {
|
||||
if (!Events.getGroup()) {
|
||||
Events.setGroup(true);
|
||||
}
|
||||
|
||||
this.workspace_.setResizesEnabled(false);
|
||||
@@ -118,19 +125,19 @@ Blockly.BubbleDragger.prototype.startBubbleDrag = function() {
|
||||
* Execute a step of bubble dragging, based on the given event. Update the
|
||||
* display accordingly.
|
||||
* @param {!Event} e The most recent move event.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the position at the start of the drag, in pixel units.
|
||||
* @package
|
||||
*/
|
||||
Blockly.BubbleDragger.prototype.dragBubble = function(e, currentDragDeltaXY) {
|
||||
var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
|
||||
var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta);
|
||||
BubbleDragger.prototype.dragBubble = function(e, currentDragDeltaXY) {
|
||||
const delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
|
||||
const newLoc = Coordinate.sum(this.startXY_, delta);
|
||||
this.draggingBubble_.moveDuringDrag(this.dragSurface_, newLoc);
|
||||
|
||||
var oldDragTarget = this.dragTarget_;
|
||||
const oldDragTarget = this.dragTarget_;
|
||||
this.dragTarget_ = this.workspace_.getDragTarget(e);
|
||||
|
||||
var oldWouldDeleteBubble = this.wouldDeleteBubble_;
|
||||
const oldWouldDeleteBubble = this.wouldDeleteBubble_;
|
||||
this.wouldDeleteBubble_ = this.shouldDelete_(this.dragTarget_);
|
||||
if (oldWouldDeleteBubble != this.wouldDeleteBubble_) {
|
||||
// Prevent unnecessary add/remove class calls.
|
||||
@@ -147,19 +154,19 @@ Blockly.BubbleDragger.prototype.dragBubble = function(e, currentDragDeltaXY) {
|
||||
|
||||
/**
|
||||
* Whether ending the drag would delete the bubble.
|
||||
* @param {?Blockly.IDragTarget} dragTarget The drag target that the bubblee is
|
||||
* @param {?IDragTarget} dragTarget The drag target that the bubblee is
|
||||
* currently over.
|
||||
* @return {boolean} Whether dropping the bubble immediately would delete the
|
||||
* block.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BubbleDragger.prototype.shouldDelete_ = function(dragTarget) {
|
||||
BubbleDragger.prototype.shouldDelete_ = function(dragTarget) {
|
||||
if (dragTarget) {
|
||||
var componentManager = this.workspace_.getComponentManager();
|
||||
var isDeleteArea = componentManager.hasCapability(dragTarget.id,
|
||||
Blockly.ComponentManager.Capability.DELETE_AREA);
|
||||
const componentManager = this.workspace_.getComponentManager();
|
||||
const isDeleteArea = componentManager.hasCapability(
|
||||
dragTarget.id, ComponentManager.Capability.DELETE_AREA);
|
||||
if (isDeleteArea) {
|
||||
return (/** @type {!Blockly.IDeleteArea} */ (dragTarget))
|
||||
return (/** @type {!IDeleteArea} */ (dragTarget))
|
||||
.wouldDelete(this.draggingBubble_, false);
|
||||
}
|
||||
}
|
||||
@@ -171,29 +178,29 @@ Blockly.BubbleDragger.prototype.shouldDelete_ = function(dragTarget) {
|
||||
* dragging bubble would be deleted if released immediately.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BubbleDragger.prototype.updateCursorDuringBubbleDrag_ = function() {
|
||||
BubbleDragger.prototype.updateCursorDuringBubbleDrag_ = function() {
|
||||
this.draggingBubble_.setDeleteStyle(this.wouldDeleteBubble_);
|
||||
};
|
||||
|
||||
/**
|
||||
* Finish a bubble drag and put the bubble back on the workspace.
|
||||
* @param {!Event} e The mouseup/touchend event.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the position at the start of the drag, in pixel units.
|
||||
* @package
|
||||
*/
|
||||
Blockly.BubbleDragger.prototype.endBubbleDrag = function(
|
||||
e, currentDragDeltaXY) {
|
||||
BubbleDragger.prototype.endBubbleDrag = function(e, currentDragDeltaXY) {
|
||||
// Make sure internal state is fresh.
|
||||
this.dragBubble(e, currentDragDeltaXY);
|
||||
|
||||
var preventMove = this.dragTarget_ &&
|
||||
const preventMove = this.dragTarget_ &&
|
||||
this.dragTarget_.shouldPreventMove(this.draggingBubble_);
|
||||
let newLoc;
|
||||
if (preventMove) {
|
||||
var newLoc = this.startXY_;
|
||||
newLoc = this.startXY_;
|
||||
} else {
|
||||
var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
|
||||
var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta);
|
||||
const delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
|
||||
newLoc = Coordinate.sum(this.startXY_, delta);
|
||||
}
|
||||
// Move the bubble to its final location.
|
||||
this.draggingBubble_.moveTo(newLoc.x, newLoc.y);
|
||||
@@ -218,20 +225,21 @@ Blockly.BubbleDragger.prototype.endBubbleDrag = function(
|
||||
}
|
||||
this.workspace_.setResizesEnabled(true);
|
||||
|
||||
Blockly.Events.setGroup(false);
|
||||
Events.setGroup(false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Fire a move event at the end of a bubble drag.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BubbleDragger.prototype.fireMoveEvent_ = function() {
|
||||
BubbleDragger.prototype.fireMoveEvent_ = function() {
|
||||
if (this.draggingBubble_.isComment) {
|
||||
var event = new (Blockly.Events.get(Blockly.Events.COMMENT_MOVE))(
|
||||
// TODO (adodson): Resolve build errors when requiring WorkspaceCommentSvg.
|
||||
const event = new (Events.get(Events.COMMENT_MOVE))(
|
||||
/** @type {!Blockly.WorkspaceCommentSvg} */ (this.draggingBubble_));
|
||||
event.setOldCoordinate(this.startXY_);
|
||||
event.recordNew();
|
||||
Blockly.Events.fire(event);
|
||||
Events.fire(event);
|
||||
}
|
||||
// TODO (fenichel): move events for comments.
|
||||
return;
|
||||
@@ -242,14 +250,14 @@ Blockly.BubbleDragger.prototype.fireMoveEvent_ = function() {
|
||||
* correction for mutator workspaces.
|
||||
* This function does not consider differing origins. It simply scales the
|
||||
* input's x and y values.
|
||||
* @param {!Blockly.utils.Coordinate} pixelCoord A coordinate with x and y
|
||||
* @param {!Coordinate} pixelCoord A coordinate with x and y
|
||||
* values in CSS pixel units.
|
||||
* @return {!Blockly.utils.Coordinate} The input coordinate divided by the
|
||||
* @return {!Coordinate} The input coordinate divided by the
|
||||
* workspace scale.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BubbleDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) {
|
||||
var result = new Blockly.utils.Coordinate(
|
||||
BubbleDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) {
|
||||
const result = new Coordinate(
|
||||
pixelCoord.x / this.workspace_.scale,
|
||||
pixelCoord.y / this.workspace_.scale);
|
||||
if (this.workspace_.isMutator) {
|
||||
@@ -257,7 +265,7 @@ Blockly.BubbleDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) {
|
||||
// oddities in our rendering optimizations. The actual scale is the same as
|
||||
// the scale on the parent workspace.
|
||||
// Fix that for dragging.
|
||||
var mainScale = this.workspace_.options.parentWorkspace.scale;
|
||||
const mainScale = this.workspace_.options.parentWorkspace.scale;
|
||||
result.scale(1 / mainScale);
|
||||
}
|
||||
return result;
|
||||
@@ -268,9 +276,11 @@ Blockly.BubbleDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) {
|
||||
* drag surface to preserve the apparent location of the bubble.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BubbleDragger.prototype.moveToDragSurface_ = function() {
|
||||
BubbleDragger.prototype.moveToDragSurface_ = function() {
|
||||
this.draggingBubble_.moveTo(0, 0);
|
||||
this.dragSurface_.translateSurface(this.startXY_.x, this.startXY_.y);
|
||||
// Execute the move on the top-level SVG component.
|
||||
this.dragSurface_.setBlocksAndShow(this.draggingBubble_.getSvgRoot());
|
||||
};
|
||||
|
||||
exports = BubbleDragger;
|
||||
|
||||
212
core/comment.js
212
core/comment.js
@@ -10,43 +10,49 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Comment');
|
||||
goog.module('Blockly.Comment');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.browserEvents');
|
||||
goog.require('Blockly.Bubble');
|
||||
goog.require('Blockly.Css');
|
||||
goog.require('Blockly.Events');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
const Bubble = goog.require('Blockly.Bubble');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Coordinate = goog.requireType('Blockly.utils.Coordinate');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const Icon = goog.require('Blockly.Icon');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Size = goog.requireType('Blockly.utils.Size');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const userAgent = goog.require('Blockly.utils.userAgent');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const {conditionalBind, Data, unbind} = goog.require('Blockly.browserEvents');
|
||||
const {createSvgElement, HTML_NS} = goog.require('Blockly.utils.dom');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
const {register} = goog.require('Blockly.Css');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockChange');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BubbleOpen');
|
||||
goog.require('Blockly.Icon');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
goog.require('Blockly.utils.userAgent');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Warning');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.utils.Coordinate');
|
||||
goog.requireType('Blockly.utils.Size');
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a comment.
|
||||
* @param {!Blockly.Block} block The block associated with this comment.
|
||||
* @extends {Blockly.Icon}
|
||||
* @param {!Block} block The block associated with this comment.
|
||||
* @extends {Icon}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Comment = function(block) {
|
||||
Blockly.Comment.superClass_.constructor.call(this, block);
|
||||
const Comment = function(block) {
|
||||
Comment.superClass_.constructor.call(this, block);
|
||||
|
||||
/**
|
||||
* The model for this comment.
|
||||
* @type {!Blockly.Block.CommentModel}
|
||||
* @type {!Block.CommentModel}
|
||||
* @private
|
||||
*/
|
||||
this.model_ = block.commentModel;
|
||||
@@ -64,62 +70,60 @@ Blockly.Comment = function(block) {
|
||||
|
||||
/**
|
||||
* Mouse up event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?Data}
|
||||
* @private
|
||||
*/
|
||||
this.onMouseUpWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Wheel event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?Data}
|
||||
* @private
|
||||
*/
|
||||
this.onWheelWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Change event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?Data}
|
||||
* @private
|
||||
*/
|
||||
this.onChangeWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Input event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?Data}
|
||||
* @private
|
||||
*/
|
||||
this.onInputWrapper_ = null;
|
||||
|
||||
this.createIcon();
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Comment, Blockly.Icon);
|
||||
inherits(Comment, Icon);
|
||||
|
||||
/**
|
||||
* Draw the comment icon.
|
||||
* @param {!Element} group The icon group.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Comment.prototype.drawIcon_ = function(group) {
|
||||
Comment.prototype.drawIcon_ = function(group) {
|
||||
// Circle.
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.CIRCLE,
|
||||
{'class': 'blocklyIconShape', 'r': '8', 'cx': '8', 'cy': '8'},
|
||||
createSvgElement(
|
||||
Svg.CIRCLE, {'class': 'blocklyIconShape', 'r': '8', 'cx': '8', 'cy': '8'},
|
||||
group);
|
||||
// Can't use a real '?' text character since different browsers and operating
|
||||
// systems render it differently.
|
||||
// Body of question mark.
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.PATH,
|
||||
{
|
||||
createSvgElement(
|
||||
Svg.PATH, {
|
||||
'class': 'blocklyIconSymbol',
|
||||
'd': 'm6.8,10h2c0.003,-0.617 0.271,-0.962 0.633,-1.266 2.875,-2.405' +
|
||||
'0.607,-5.534 -3.765,-3.874v1.7c3.12,-1.657 3.698,0.118 2.336,1.25' +
|
||||
'-1.201,0.998 -1.201,1.528 -1.204,2.19z'},
|
||||
'0.607,-5.534 -3.765,-3.874v1.7c3.12,-1.657 3.698,0.118 2.336,1.25' +
|
||||
'-1.201,0.998 -1.201,1.528 -1.204,2.19z'
|
||||
},
|
||||
group);
|
||||
// Dot of question mark.
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.RECT,
|
||||
{
|
||||
createSvgElement(
|
||||
Svg.RECT, {
|
||||
'class': 'blocklyIconSymbol',
|
||||
'x': '6.8',
|
||||
'y': '10.78',
|
||||
@@ -134,7 +138,7 @@ Blockly.Comment.prototype.drawIcon_ = function(group) {
|
||||
* @return {!SVGElement} The top-level node of the editor.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Comment.prototype.createEditor_ = function() {
|
||||
Comment.prototype.createEditor_ = function() {
|
||||
/* Create the editor. Here's the markup that will be generated in
|
||||
* editable mode:
|
||||
<foreignObject x="8" y="8" width="164" height="164">
|
||||
@@ -147,18 +151,16 @@ Blockly.Comment.prototype.createEditor_ = function() {
|
||||
* For non-editable mode see Warning.textToDom_.
|
||||
*/
|
||||
|
||||
this.foreignObject_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.FOREIGNOBJECT,
|
||||
{'x': Blockly.Bubble.BORDER_WIDTH, 'y': Blockly.Bubble.BORDER_WIDTH},
|
||||
this.foreignObject_ = createSvgElement(
|
||||
Svg.FOREIGNOBJECT, {'x': Bubble.BORDER_WIDTH, 'y': Bubble.BORDER_WIDTH},
|
||||
null);
|
||||
|
||||
var body = document.createElementNS(Blockly.utils.dom.HTML_NS, 'body');
|
||||
body.setAttribute('xmlns', Blockly.utils.dom.HTML_NS);
|
||||
const body = document.createElementNS(HTML_NS, 'body');
|
||||
body.setAttribute('xmlns', HTML_NS);
|
||||
body.className = 'blocklyMinimalBody';
|
||||
|
||||
this.textarea_ = document.createElementNS(
|
||||
Blockly.utils.dom.HTML_NS, 'textarea');
|
||||
var textarea = this.textarea_;
|
||||
this.textarea_ = document.createElementNS(HTML_NS, 'textarea');
|
||||
const textarea = this.textarea_;
|
||||
textarea.className = 'blocklyCommentTextarea';
|
||||
textarea.setAttribute('dir', this.block_.RTL ? 'RTL' : 'LTR');
|
||||
textarea.value = this.model_.text;
|
||||
@@ -170,26 +172,23 @@ Blockly.Comment.prototype.createEditor_ = function() {
|
||||
// Ideally this would be hooked to the focus event for the comment.
|
||||
// However doing so in Firefox swallows the cursor for unknown reasons.
|
||||
// So this is hooked to mouseup instead. No big deal.
|
||||
this.onMouseUpWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
textarea, 'mouseup', this, this.startEdit_, true, true);
|
||||
this.onMouseUpWrapper_ =
|
||||
conditionalBind(textarea, 'mouseup', this, this.startEdit_, true, true);
|
||||
// Don't zoom with mousewheel.
|
||||
this.onWheelWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
textarea, 'wheel', this, function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
this.onChangeWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
textarea, 'change', this, function(_e) {
|
||||
this.onWheelWrapper_ = conditionalBind(textarea, 'wheel', this, function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
this.onChangeWrapper_ =
|
||||
conditionalBind(textarea, 'change', this, function(_e) {
|
||||
if (this.cachedText_ != this.model_.text) {
|
||||
Blockly.Events.fire(
|
||||
new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))(
|
||||
this.block_, 'comment', null, this.cachedText_,
|
||||
this.model_.text));
|
||||
Events.fire(new (Events.get(Events.BLOCK_CHANGE))(
|
||||
this.block_, 'comment', null, this.cachedText_,
|
||||
this.model_.text));
|
||||
}
|
||||
});
|
||||
this.onInputWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
textarea, 'input', this, function(_e) {
|
||||
this.model_.text = textarea.value;
|
||||
});
|
||||
this.onInputWrapper_ = conditionalBind(textarea, 'input', this, function(_e) {
|
||||
this.model_.text = textarea.value;
|
||||
});
|
||||
|
||||
setTimeout(textarea.focus.bind(textarea), 0);
|
||||
|
||||
@@ -200,8 +199,8 @@ Blockly.Comment.prototype.createEditor_ = function() {
|
||||
* Add or remove editability of the comment.
|
||||
* @override
|
||||
*/
|
||||
Blockly.Comment.prototype.updateEditable = function() {
|
||||
Blockly.Comment.superClass_.updateEditable.call(this);
|
||||
Comment.prototype.updateEditable = function() {
|
||||
Comment.superClass_.updateEditable.call(this);
|
||||
if (this.isVisible()) {
|
||||
// Recreate the bubble with the correct UI.
|
||||
this.disposeBubble_();
|
||||
@@ -214,7 +213,7 @@ Blockly.Comment.prototype.updateEditable = function() {
|
||||
* Resize the text area accordingly.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Comment.prototype.onBubbleResize_ = function() {
|
||||
Comment.prototype.onBubbleResize_ = function() {
|
||||
if (!this.isVisible()) {
|
||||
return;
|
||||
}
|
||||
@@ -227,11 +226,11 @@ Blockly.Comment.prototype.onBubbleResize_ = function() {
|
||||
* the size of the bubble).
|
||||
* @private
|
||||
*/
|
||||
Blockly.Comment.prototype.resizeTextarea_ = function() {
|
||||
var size = this.model_.size;
|
||||
var doubleBorderWidth = 2 * Blockly.Bubble.BORDER_WIDTH;
|
||||
var widthMinusBorder = size.width - doubleBorderWidth;
|
||||
var heightMinusBorder = size.height - doubleBorderWidth;
|
||||
Comment.prototype.resizeTextarea_ = function() {
|
||||
const size = this.model_.size;
|
||||
const doubleBorderWidth = 2 * Bubble.BORDER_WIDTH;
|
||||
const widthMinusBorder = size.width - doubleBorderWidth;
|
||||
const heightMinusBorder = size.height - doubleBorderWidth;
|
||||
this.foreignObject_.setAttribute('width', widthMinusBorder);
|
||||
this.foreignObject_.setAttribute('height', heightMinusBorder);
|
||||
this.textarea_.style.width = (widthMinusBorder - 4) + 'px';
|
||||
@@ -242,12 +241,12 @@ Blockly.Comment.prototype.resizeTextarea_ = function() {
|
||||
* Show or hide the comment bubble.
|
||||
* @param {boolean} visible True if the bubble should be visible.
|
||||
*/
|
||||
Blockly.Comment.prototype.setVisible = function(visible) {
|
||||
Comment.prototype.setVisible = function(visible) {
|
||||
if (visible == this.isVisible()) {
|
||||
return;
|
||||
}
|
||||
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BUBBLE_OPEN))(
|
||||
this.block_, visible, 'comment'));
|
||||
Events.fire(
|
||||
new (Events.get(Events.BUBBLE_OPEN))(this.block_, visible, 'comment'));
|
||||
this.model_.pinned = visible;
|
||||
if (visible) {
|
||||
this.createBubble_();
|
||||
@@ -260,8 +259,8 @@ Blockly.Comment.prototype.setVisible = function(visible) {
|
||||
* Show the bubble. Handles deciding if it should be editable or not.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Comment.prototype.createBubble_ = function() {
|
||||
if (!this.block_.isEditable() || Blockly.utils.userAgent.IE) {
|
||||
Comment.prototype.createBubble_ = function() {
|
||||
if (!this.block_.isEditable() || userAgent.IE) {
|
||||
// MSIE does not support foreignobject; textareas are impossible.
|
||||
// https://docs.microsoft.com/en-us/openspecs/ie_standards/ms-svg/56e6e04c-7c8c-44dd-8100-bd745ee42034
|
||||
// Always treat comments in IE as uneditable.
|
||||
@@ -275,12 +274,12 @@ Blockly.Comment.prototype.createBubble_ = function() {
|
||||
* Show an editable bubble.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Comment.prototype.createEditableBubble_ = function() {
|
||||
this.bubble_ = new Blockly.Bubble(
|
||||
/** @type {!Blockly.WorkspaceSvg} */ (this.block_.workspace),
|
||||
Comment.prototype.createEditableBubble_ = function() {
|
||||
this.bubble_ = new Bubble(
|
||||
/** @type {!WorkspaceSvg} */ (this.block_.workspace),
|
||||
this.createEditor_(), this.block_.pathObject.svgPath,
|
||||
/** @type {!Blockly.utils.Coordinate} */ (this.iconXY_),
|
||||
this.model_.size.width, this.model_.size.height);
|
||||
/** @type {!Coordinate} */ (this.iconXY_), this.model_.size.width,
|
||||
this.model_.size.height);
|
||||
// Expose this comment's block's ID on its top-level SVG group.
|
||||
this.bubble_.setSvgId(this.block_.id);
|
||||
this.bubble_.registerResizeEvent(this.onBubbleResize_.bind(this));
|
||||
@@ -292,12 +291,12 @@ Blockly.Comment.prototype.createEditableBubble_ = function() {
|
||||
* @private
|
||||
* @suppress {checkTypes} Suppress `this` type mismatch.
|
||||
*/
|
||||
Blockly.Comment.prototype.createNonEditableBubble_ = function() {
|
||||
Comment.prototype.createNonEditableBubble_ = function() {
|
||||
// TODO (#2917): It would be great if the comment could support line breaks.
|
||||
this.paragraphElement_ = Blockly.Bubble.textToDom(this.block_.getCommentText());
|
||||
this.bubble_ = Blockly.Bubble.createNonEditableBubble(
|
||||
this.paragraphElement_, /** @type {!Blockly.BlockSvg} */ (this.block_),
|
||||
/** @type {!Blockly.utils.Coordinate} */ (this.iconXY_));
|
||||
this.paragraphElement_ = Bubble.textToDom(this.block_.getCommentText());
|
||||
this.bubble_ = Bubble.createNonEditableBubble(
|
||||
this.paragraphElement_, /** @type {!BlockSvg} */ (this.block_),
|
||||
/** @type {!Coordinate} */ (this.iconXY_));
|
||||
this.applyColour();
|
||||
};
|
||||
|
||||
@@ -306,21 +305,21 @@ Blockly.Comment.prototype.createNonEditableBubble_ = function() {
|
||||
* @private
|
||||
* @suppress {checkTypes} Suppress `this` type mismatch.
|
||||
*/
|
||||
Blockly.Comment.prototype.disposeBubble_ = function() {
|
||||
Comment.prototype.disposeBubble_ = function() {
|
||||
if (this.onMouseUpWrapper_) {
|
||||
Blockly.browserEvents.unbind(this.onMouseUpWrapper_);
|
||||
unbind(this.onMouseUpWrapper_);
|
||||
this.onMouseUpWrapper_ = null;
|
||||
}
|
||||
if (this.onWheelWrapper_) {
|
||||
Blockly.browserEvents.unbind(this.onWheelWrapper_);
|
||||
unbind(this.onWheelWrapper_);
|
||||
this.onWheelWrapper_ = null;
|
||||
}
|
||||
if (this.onChangeWrapper_) {
|
||||
Blockly.browserEvents.unbind(this.onChangeWrapper_);
|
||||
unbind(this.onChangeWrapper_);
|
||||
this.onChangeWrapper_ = null;
|
||||
}
|
||||
if (this.onInputWrapper_) {
|
||||
Blockly.browserEvents.unbind(this.onInputWrapper_);
|
||||
unbind(this.onInputWrapper_);
|
||||
this.onInputWrapper_ = null;
|
||||
}
|
||||
this.bubble_.dispose();
|
||||
@@ -338,7 +337,7 @@ Blockly.Comment.prototype.disposeBubble_ = function() {
|
||||
* @param {!Event} _e Mouse up event.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Comment.prototype.startEdit_ = function(_e) {
|
||||
Comment.prototype.startEdit_ = function(_e) {
|
||||
if (this.bubble_.promote()) {
|
||||
// Since the act of moving this node within the DOM causes a loss of focus,
|
||||
// we need to reapply the focus.
|
||||
@@ -350,9 +349,9 @@ Blockly.Comment.prototype.startEdit_ = function(_e) {
|
||||
|
||||
/**
|
||||
* Get the dimensions of this comment's bubble.
|
||||
* @return {Blockly.utils.Size} Object with width and height properties.
|
||||
* @return {Size} Object with width and height properties.
|
||||
*/
|
||||
Blockly.Comment.prototype.getBubbleSize = function() {
|
||||
Comment.prototype.getBubbleSize = function() {
|
||||
return this.model_.size;
|
||||
};
|
||||
|
||||
@@ -361,7 +360,7 @@ Blockly.Comment.prototype.getBubbleSize = function() {
|
||||
* @param {number} width Width of the bubble.
|
||||
* @param {number} height Height of the bubble.
|
||||
*/
|
||||
Blockly.Comment.prototype.setBubbleSize = function(width, height) {
|
||||
Comment.prototype.setBubbleSize = function(width, height) {
|
||||
if (this.bubble_) {
|
||||
this.bubble_.setBubbleSize(width, height);
|
||||
} else {
|
||||
@@ -374,7 +373,7 @@ Blockly.Comment.prototype.setBubbleSize = function(width, height) {
|
||||
* Update the comment's view to match the model.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Comment.prototype.updateText = function() {
|
||||
Comment.prototype.updateText = function() {
|
||||
if (this.textarea_) {
|
||||
this.textarea_.value = this.model_.text;
|
||||
} else if (this.paragraphElement_) {
|
||||
@@ -390,25 +389,20 @@ Blockly.Comment.prototype.updateText = function() {
|
||||
* If you want to receive a comment "delete" event (newValue: null), then this
|
||||
* should not be called directly. Instead call block.setCommentText(null);
|
||||
*/
|
||||
Blockly.Comment.prototype.dispose = function() {
|
||||
Comment.prototype.dispose = function() {
|
||||
this.block_.comment = null;
|
||||
Blockly.Icon.prototype.dispose.call(this);
|
||||
Icon.prototype.dispose.call(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* CSS for block comment. See css.js for use.
|
||||
*/
|
||||
Blockly.Css.register([
|
||||
register([
|
||||
/* eslint-disable indent */
|
||||
'.blocklyCommentTextarea {',
|
||||
'background-color: #fef49c;',
|
||||
'border: 0;',
|
||||
'outline: 0;',
|
||||
'margin: 0;',
|
||||
'padding: 3px;',
|
||||
'resize: none;',
|
||||
'display: block;',
|
||||
'text-overflow: hidden;',
|
||||
'}'
|
||||
'.blocklyCommentTextarea {', 'background-color: #fef49c;', 'border: 0;',
|
||||
'outline: 0;', 'margin: 0;', 'padding: 3px;', 'resize: none;',
|
||||
'display: block;', 'text-overflow: hidden;', '}'
|
||||
/* eslint-enable indent */
|
||||
]);
|
||||
|
||||
exports = Comment;
|
||||
|
||||
@@ -11,23 +11,29 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.ComponentManager');
|
||||
goog.module('Blockly.ComponentManager');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.requireType('Blockly.IAutoHideable');
|
||||
goog.requireType('Blockly.IComponent');
|
||||
goog.requireType('Blockly.IDeleteArea');
|
||||
goog.requireType('Blockly.IDragTarget');
|
||||
goog.requireType('Blockly.IPositionable');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IAutoHideable = goog.requireType('Blockly.IAutoHideable');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IComponent = goog.requireType('Blockly.IComponent');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDeleteArea = goog.requireType('Blockly.IDeleteArea');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDragTarget = goog.requireType('Blockly.IDragTarget');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IPositionable = goog.requireType('Blockly.IPositionable');
|
||||
|
||||
|
||||
/**
|
||||
* Manager for all items registered with the workspace.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.ComponentManager = function() {
|
||||
const ComponentManager = function() {
|
||||
/**
|
||||
* A map of the components registered with the workspace, mapped to id.
|
||||
* @type {!Object<string, !Blockly.ComponentManager.ComponentDatum>}
|
||||
* @type {!Object<string, !ComponentManager.ComponentDatum>}
|
||||
* @private
|
||||
*/
|
||||
this.componentData_ = Object.create(null);
|
||||
@@ -43,35 +49,35 @@ Blockly.ComponentManager = function() {
|
||||
/**
|
||||
* An object storing component information.
|
||||
* @typedef {{
|
||||
* component: !Blockly.IComponent,
|
||||
* component: !IComponent,
|
||||
* capabilities: (
|
||||
* !Array<string|!Blockly.ComponentManager.Capability<!Blockly.IComponent>>
|
||||
* !Array<string|!ComponentManager.Capability<!IComponent>>
|
||||
* ),
|
||||
* weight: number
|
||||
* }}
|
||||
*/
|
||||
Blockly.ComponentManager.ComponentDatum;
|
||||
ComponentManager.ComponentDatum;
|
||||
|
||||
/**
|
||||
* Adds a component.
|
||||
* @param {!Blockly.ComponentManager.ComponentDatum} componentInfo The data for
|
||||
* @param {!ComponentManager.ComponentDatum} componentInfo The data for
|
||||
* the component to register.
|
||||
* @param {boolean=} opt_allowOverrides True to prevent an error when overriding
|
||||
* an already registered item.
|
||||
*/
|
||||
Blockly.ComponentManager.prototype.addComponent = function(
|
||||
ComponentManager.prototype.addComponent = function(
|
||||
componentInfo, opt_allowOverrides) {
|
||||
// Don't throw an error if opt_allowOverrides is true.
|
||||
var id = componentInfo.component.id;
|
||||
const id = componentInfo.component.id;
|
||||
if (!opt_allowOverrides && this.componentData_[id]) {
|
||||
throw Error(
|
||||
'Plugin "' + id + '" with capabilities "' +
|
||||
this.componentData_[id].capabilities + '" already added.');
|
||||
}
|
||||
this.componentData_[id] = componentInfo;
|
||||
var stringCapabilities = [];
|
||||
for (var i = 0; i < componentInfo.capabilities.length; i++) {
|
||||
var capability = String(componentInfo.capabilities[i]).toLowerCase();
|
||||
const stringCapabilities = [];
|
||||
for (let i = 0; i < componentInfo.capabilities.length; i++) {
|
||||
const capability = String(componentInfo.capabilities[i]).toLowerCase();
|
||||
stringCapabilities.push(capability);
|
||||
if (this.capabilityToComponentIds_[capability] === undefined) {
|
||||
this.capabilityToComponentIds_[capability] = [id];
|
||||
@@ -86,13 +92,13 @@ Blockly.ComponentManager.prototype.addComponent = function(
|
||||
* Removes a component.
|
||||
* @param {string} id The ID of the component to remove.
|
||||
*/
|
||||
Blockly.ComponentManager.prototype.removeComponent = function(id) {
|
||||
var componentInfo = this.componentData_[id];
|
||||
ComponentManager.prototype.removeComponent = function(id) {
|
||||
const componentInfo = this.componentData_[id];
|
||||
if (!componentInfo) {
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < componentInfo.capabilities.length; i++) {
|
||||
var capability = String(componentInfo.capabilities[i]).toLowerCase();
|
||||
for (let i = 0; i < componentInfo.capabilities.length; i++) {
|
||||
const capability = String(componentInfo.capabilities[i]).toLowerCase();
|
||||
this.capabilityToComponentIds_[capability].splice(
|
||||
this.capabilityToComponentIds_[capability].indexOf(id), 1);
|
||||
}
|
||||
@@ -102,18 +108,19 @@ Blockly.ComponentManager.prototype.removeComponent = function(id) {
|
||||
/**
|
||||
* Adds a capability to a existing registered component.
|
||||
* @param {string} id The ID of the component to add the capability to.
|
||||
* @param {string|!Blockly.ComponentManager.Capability<T>} capability The
|
||||
* @param {string|!ComponentManager.Capability<T>} capability The
|
||||
* capability to add.
|
||||
* @template T
|
||||
*/
|
||||
Blockly.ComponentManager.prototype.addCapability = function(id, capability) {
|
||||
ComponentManager.prototype.addCapability = function(id, capability) {
|
||||
if (!this.getComponent(id)) {
|
||||
throw Error('Cannot add capability, "' + capability + '". Plugin "' +
|
||||
id + '" has not been added to the ComponentManager');
|
||||
throw Error(
|
||||
'Cannot add capability, "' + capability + '". Plugin "' + id +
|
||||
'" has not been added to the ComponentManager');
|
||||
}
|
||||
if (this.hasCapability(id, capability)) {
|
||||
console.warn('Plugin "' + id + 'already has capability "' +
|
||||
capability + '"');
|
||||
console.warn(
|
||||
'Plugin "' + id + 'already has capability "' + capability + '"');
|
||||
return;
|
||||
}
|
||||
capability = String(capability).toLowerCase();
|
||||
@@ -124,18 +131,20 @@ Blockly.ComponentManager.prototype.addCapability = function(id, capability) {
|
||||
/**
|
||||
* Removes a capability from an existing registered component.
|
||||
* @param {string} id The ID of the component to remove the capability from.
|
||||
* @param {string|!Blockly.ComponentManager.Capability<T>} capability The
|
||||
* @param {string|!ComponentManager.Capability<T>} capability The
|
||||
* capability to remove.
|
||||
* @template T
|
||||
*/
|
||||
Blockly.ComponentManager.prototype.removeCapability = function(id, capability) {
|
||||
ComponentManager.prototype.removeCapability = function(id, capability) {
|
||||
if (!this.getComponent(id)) {
|
||||
throw Error('Cannot remove capability, "' + capability + '". Plugin "' +
|
||||
id + '" has not been added to the ComponentManager');
|
||||
throw Error(
|
||||
'Cannot remove capability, "' + capability + '". Plugin "' + id +
|
||||
'" has not been added to the ComponentManager');
|
||||
}
|
||||
if (!this.hasCapability(id, capability)) {
|
||||
console.warn('Plugin "' + id + 'doesn\'t have capability "' +
|
||||
capability + '" to remove');
|
||||
console.warn(
|
||||
'Plugin "' + id + 'doesn\'t have capability "' + capability +
|
||||
'" to remove');
|
||||
return;
|
||||
}
|
||||
capability = String(capability).toLowerCase();
|
||||
@@ -148,12 +157,12 @@ Blockly.ComponentManager.prototype.removeCapability = function(id, capability) {
|
||||
/**
|
||||
* Returns whether the component with this id has the specified capability.
|
||||
* @param {string} id The ID of the component to check.
|
||||
* @param {string|!Blockly.ComponentManager.Capability<T>} capability The
|
||||
* @param {string|!ComponentManager.Capability<T>} capability The
|
||||
* capability to check for.
|
||||
* @return {boolean} Whether the component has the capability.
|
||||
* @template T
|
||||
*/
|
||||
Blockly.ComponentManager.prototype.hasCapability = function(id, capability) {
|
||||
ComponentManager.prototype.hasCapability = function(id, capability) {
|
||||
capability = String(capability).toLowerCase();
|
||||
return this.componentData_[id].capabilities.indexOf(capability) !== -1;
|
||||
};
|
||||
@@ -161,31 +170,31 @@ Blockly.ComponentManager.prototype.hasCapability = function(id, capability) {
|
||||
/**
|
||||
* Gets the component with the given ID.
|
||||
* @param {string} id The ID of the component to get.
|
||||
* @return {!Blockly.IComponent|undefined} The component with the given name
|
||||
* @return {!IComponent|undefined} The component with the given name
|
||||
* or undefined if not found.
|
||||
*/
|
||||
Blockly.ComponentManager.prototype.getComponent = function(id) {
|
||||
ComponentManager.prototype.getComponent = function(id) {
|
||||
return this.componentData_[id] && this.componentData_[id].component;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets all the components with the specified capability.
|
||||
* @param {string|!Blockly.ComponentManager.Capability<T>
|
||||
* @param {string|!ComponentManager.Capability<T>
|
||||
* } capability The capability of the component.
|
||||
* @param {boolean} sorted Whether to return list ordered by weights.
|
||||
* @return {!Array<T>} The components that match the specified capability.
|
||||
* @template T
|
||||
*/
|
||||
Blockly.ComponentManager.prototype.getComponents = function(capability, sorted) {
|
||||
ComponentManager.prototype.getComponents = function(capability, sorted) {
|
||||
capability = String(capability).toLowerCase();
|
||||
var componentIds = this.capabilityToComponentIds_[capability];
|
||||
const componentIds = this.capabilityToComponentIds_[capability];
|
||||
if (!componentIds) {
|
||||
return [];
|
||||
}
|
||||
var components = [];
|
||||
const components = [];
|
||||
if (sorted) {
|
||||
var componentDataList = [];
|
||||
var componentData = this.componentData_;
|
||||
const componentDataList = [];
|
||||
const componentData = this.componentData_;
|
||||
componentIds.forEach(function(id) {
|
||||
componentDataList.push(componentData[id]);
|
||||
});
|
||||
@@ -196,7 +205,7 @@ Blockly.ComponentManager.prototype.getComponents = function(capability, sorted)
|
||||
components.push(ComponentDatum.component);
|
||||
});
|
||||
} else {
|
||||
var componentData = this.componentData_;
|
||||
const componentData = this.componentData_;
|
||||
componentIds.forEach(function(id) {
|
||||
components.push(componentData[id].component);
|
||||
});
|
||||
@@ -210,7 +219,7 @@ Blockly.ComponentManager.prototype.getComponents = function(capability, sorted)
|
||||
* @constructor
|
||||
* @template T
|
||||
*/
|
||||
Blockly.ComponentManager.Capability = function(name) {
|
||||
ComponentManager.Capability = function(name) {
|
||||
/**
|
||||
* @type {string}
|
||||
* @private
|
||||
@@ -223,22 +232,24 @@ Blockly.ComponentManager.Capability = function(name) {
|
||||
* @return {string} The name.
|
||||
* @override
|
||||
*/
|
||||
Blockly.ComponentManager.Capability.prototype.toString = function() {
|
||||
ComponentManager.Capability.prototype.toString = function() {
|
||||
return this.name_;
|
||||
};
|
||||
|
||||
/** @type {!Blockly.ComponentManager.Capability<!Blockly.IPositionable>} */
|
||||
Blockly.ComponentManager.Capability.POSITIONABLE =
|
||||
new Blockly.ComponentManager.Capability('positionable');
|
||||
/** @type {!ComponentManager.Capability<!IPositionable>} */
|
||||
ComponentManager.Capability.POSITIONABLE =
|
||||
new ComponentManager.Capability('positionable');
|
||||
|
||||
/** @type {!Blockly.ComponentManager.Capability<!Blockly.IDragTarget>} */
|
||||
Blockly.ComponentManager.Capability.DRAG_TARGET =
|
||||
new Blockly.ComponentManager.Capability('drag_target');
|
||||
/** @type {!ComponentManager.Capability<!IDragTarget>} */
|
||||
ComponentManager.Capability.DRAG_TARGET =
|
||||
new ComponentManager.Capability('drag_target');
|
||||
|
||||
/** @type {!Blockly.ComponentManager.Capability<!Blockly.IDeleteArea>} */
|
||||
Blockly.ComponentManager.Capability.DELETE_AREA =
|
||||
new Blockly.ComponentManager.Capability('delete_area');
|
||||
/** @type {!ComponentManager.Capability<!IDeleteArea>} */
|
||||
ComponentManager.Capability.DELETE_AREA =
|
||||
new ComponentManager.Capability('delete_area');
|
||||
|
||||
/** @type {!Blockly.ComponentManager.Capability<!Blockly.IAutoHideable>} */
|
||||
Blockly.ComponentManager.Capability.AUTOHIDEABLE =
|
||||
new Blockly.ComponentManager.Capability('autohideable');
|
||||
/** @type {!ComponentManager.Capability<!IAutoHideable>} */
|
||||
ComponentManager.Capability.AUTOHIDEABLE =
|
||||
new ComponentManager.Capability('autohideable');
|
||||
|
||||
exports = ComponentManager;
|
||||
|
||||
@@ -10,33 +10,37 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Connection');
|
||||
goog.module('Blockly.Connection');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.connectionTypes');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IASTNodeLocationWithBlock = goog.require('Blockly.IASTNodeLocationWithBlock');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IConnectionChecker = goog.requireType('Blockly.IConnectionChecker');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Input = goog.requireType('Blockly.Input');
|
||||
const Xml = goog.require('Blockly.Xml');
|
||||
const connectionTypes = goog.require('Blockly.connectionTypes');
|
||||
const deprecation = goog.require('Blockly.utils.deprecation');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.Events');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockMove');
|
||||
goog.require('Blockly.IASTNodeLocationWithBlock');
|
||||
goog.require('Blockly.utils.deprecation');
|
||||
goog.require('Blockly.Xml');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
goog.requireType('Blockly.IConnectionChecker');
|
||||
goog.requireType('Blockly.Input');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a connection between blocks.
|
||||
* @param {!Blockly.Block} source The block establishing this connection.
|
||||
* @param {!Block} source The block establishing this connection.
|
||||
* @param {number} type The type of the connection.
|
||||
* @constructor
|
||||
* @implements {Blockly.IASTNodeLocationWithBlock}
|
||||
* @implements {IASTNodeLocationWithBlock}
|
||||
*/
|
||||
Blockly.Connection = function(source, type) {
|
||||
const Connection = function(source, type) {
|
||||
/**
|
||||
* @type {!Blockly.Block}
|
||||
* @type {!Block}
|
||||
* @protected
|
||||
*/
|
||||
this.sourceBlock_ = source;
|
||||
@@ -47,67 +51,67 @@ Blockly.Connection = function(source, type) {
|
||||
/**
|
||||
* Constants for checking whether two connections are compatible.
|
||||
*/
|
||||
Blockly.Connection.CAN_CONNECT = 0;
|
||||
Blockly.Connection.REASON_SELF_CONNECTION = 1;
|
||||
Blockly.Connection.REASON_WRONG_TYPE = 2;
|
||||
Blockly.Connection.REASON_TARGET_NULL = 3;
|
||||
Blockly.Connection.REASON_CHECKS_FAILED = 4;
|
||||
Blockly.Connection.REASON_DIFFERENT_WORKSPACES = 5;
|
||||
Blockly.Connection.REASON_SHADOW_PARENT = 6;
|
||||
Blockly.Connection.REASON_DRAG_CHECKS_FAILED = 7;
|
||||
Connection.CAN_CONNECT = 0;
|
||||
Connection.REASON_SELF_CONNECTION = 1;
|
||||
Connection.REASON_WRONG_TYPE = 2;
|
||||
Connection.REASON_TARGET_NULL = 3;
|
||||
Connection.REASON_CHECKS_FAILED = 4;
|
||||
Connection.REASON_DIFFERENT_WORKSPACES = 5;
|
||||
Connection.REASON_SHADOW_PARENT = 6;
|
||||
Connection.REASON_DRAG_CHECKS_FAILED = 7;
|
||||
|
||||
/**
|
||||
* Connection this connection connects to. Null if not connected.
|
||||
* @type {Blockly.Connection}
|
||||
* @type {Connection}
|
||||
*/
|
||||
Blockly.Connection.prototype.targetConnection = null;
|
||||
Connection.prototype.targetConnection = null;
|
||||
|
||||
/**
|
||||
* Has this connection been disposed of?
|
||||
* @type {boolean}
|
||||
* @package
|
||||
*/
|
||||
Blockly.Connection.prototype.disposed = false;
|
||||
Connection.prototype.disposed = false;
|
||||
|
||||
/**
|
||||
* List of compatible value types. Null if all types are compatible.
|
||||
* @type {Array}
|
||||
* @private
|
||||
*/
|
||||
Blockly.Connection.prototype.check_ = null;
|
||||
Connection.prototype.check_ = null;
|
||||
|
||||
/**
|
||||
* DOM representation of a shadow block, or null if none.
|
||||
* @type {Element}
|
||||
* @private
|
||||
*/
|
||||
Blockly.Connection.prototype.shadowDom_ = null;
|
||||
Connection.prototype.shadowDom_ = null;
|
||||
|
||||
/**
|
||||
* Horizontal location of this connection.
|
||||
* @type {number}
|
||||
* @package
|
||||
*/
|
||||
Blockly.Connection.prototype.x = 0;
|
||||
Connection.prototype.x = 0;
|
||||
|
||||
/**
|
||||
* Vertical location of this connection.
|
||||
* @type {number}
|
||||
* @package
|
||||
*/
|
||||
Blockly.Connection.prototype.y = 0;
|
||||
Connection.prototype.y = 0;
|
||||
|
||||
/**
|
||||
* Connect two connections together. This is the connection on the superior
|
||||
* block.
|
||||
* @param {!Blockly.Connection} childConnection Connection on inferior block.
|
||||
* @param {!Connection} childConnection Connection on inferior block.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Connection.prototype.connect_ = function(childConnection) {
|
||||
var INPUT = Blockly.connectionTypes.INPUT_VALUE;
|
||||
var parentConnection = this;
|
||||
var parentBlock = parentConnection.getSourceBlock();
|
||||
var childBlock = childConnection.getSourceBlock();
|
||||
Connection.prototype.connect_ = function(childConnection) {
|
||||
const INPUT = connectionTypes.INPUT_VALUE;
|
||||
const parentConnection = this;
|
||||
const parentBlock = parentConnection.getSourceBlock();
|
||||
const childBlock = childConnection.getSourceBlock();
|
||||
|
||||
// Make sure the childConnection is available.
|
||||
if (childConnection.isConnected()) {
|
||||
@@ -115,11 +119,11 @@ Blockly.Connection.prototype.connect_ = function(childConnection) {
|
||||
}
|
||||
|
||||
// Make sure the parentConnection is available.
|
||||
var orphan;
|
||||
let orphan;
|
||||
if (parentConnection.isConnected()) {
|
||||
var shadowDom = parentConnection.getShadowDom(true);
|
||||
const shadowDom = parentConnection.getShadowDom(true);
|
||||
parentConnection.shadowDom_ = null; // Set to null so it doesn't respawn.
|
||||
var target = parentConnection.targetBlock();
|
||||
const target = parentConnection.targetBlock();
|
||||
if (target.isShadow()) {
|
||||
target.dispose(false);
|
||||
} else {
|
||||
@@ -130,23 +134,24 @@ Blockly.Connection.prototype.connect_ = function(childConnection) {
|
||||
}
|
||||
|
||||
// Connect the new connection to the parent.
|
||||
var event;
|
||||
if (Blockly.Events.isEnabled()) {
|
||||
event = new (Blockly.Events.get(Blockly.Events.BLOCK_MOVE))(childBlock);
|
||||
let event;
|
||||
if (Events.isEnabled()) {
|
||||
event = new (Events.get(Events.BLOCK_MOVE))(childBlock);
|
||||
}
|
||||
Blockly.Connection.connectReciprocally_(parentConnection, childConnection);
|
||||
connectReciprocally(parentConnection, childConnection);
|
||||
childBlock.setParent(parentBlock);
|
||||
if (event) {
|
||||
event.recordNew();
|
||||
Blockly.Events.fire(event);
|
||||
Events.fire(event);
|
||||
}
|
||||
|
||||
// Deal with the orphan if it exists.
|
||||
if (orphan) {
|
||||
var orphanConnection = parentConnection.type === INPUT ?
|
||||
orphan.outputConnection : orphan.previousConnection;
|
||||
var connection = Blockly.Connection.getConnectionForOrphanedConnection(
|
||||
childBlock, /** @type {!Blockly.Connection} */ (orphanConnection));
|
||||
const orphanConnection = parentConnection.type === INPUT ?
|
||||
orphan.outputConnection :
|
||||
orphan.previousConnection;
|
||||
const connection = Connection.getConnectionForOrphanedConnection(
|
||||
childBlock, /** @type {!Connection} */ (orphanConnection));
|
||||
if (connection) {
|
||||
orphanConnection.connect(connection);
|
||||
} else {
|
||||
@@ -160,14 +165,13 @@ Blockly.Connection.prototype.connect_ = function(childConnection) {
|
||||
* Dispose of this connection and deal with connected blocks.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Connection.prototype.dispose = function() {
|
||||
|
||||
Connection.prototype.dispose = function() {
|
||||
// isConnected returns true for shadows and non-shadows.
|
||||
if (this.isConnected()) {
|
||||
// Destroy the attached shadow block & its children (if it exists).
|
||||
this.setShadowDom(null);
|
||||
|
||||
var targetBlock = this.targetBlock();
|
||||
const targetBlock = this.targetBlock();
|
||||
if (targetBlock) {
|
||||
// Disconnect the attached normal block.
|
||||
targetBlock.unplug();
|
||||
@@ -179,9 +183,9 @@ Blockly.Connection.prototype.dispose = function() {
|
||||
|
||||
/**
|
||||
* Get the source block for this connection.
|
||||
* @return {!Blockly.Block} The source block.
|
||||
* @return {!Block} The source block.
|
||||
*/
|
||||
Blockly.Connection.prototype.getSourceBlock = function() {
|
||||
Connection.prototype.getSourceBlock = function() {
|
||||
return this.sourceBlock_;
|
||||
};
|
||||
|
||||
@@ -189,82 +193,75 @@ Blockly.Connection.prototype.getSourceBlock = function() {
|
||||
* Does the connection belong to a superior block (higher in the source stack)?
|
||||
* @return {boolean} True if connection faces down or right.
|
||||
*/
|
||||
Blockly.Connection.prototype.isSuperior = function() {
|
||||
return this.type == Blockly.connectionTypes.INPUT_VALUE ||
|
||||
this.type == Blockly.connectionTypes.NEXT_STATEMENT;
|
||||
Connection.prototype.isSuperior = function() {
|
||||
return this.type == connectionTypes.INPUT_VALUE ||
|
||||
this.type == connectionTypes.NEXT_STATEMENT;
|
||||
};
|
||||
|
||||
/**
|
||||
* Is the connection connected?
|
||||
* @return {boolean} True if connection is connected to another connection.
|
||||
*/
|
||||
Blockly.Connection.prototype.isConnected = function() {
|
||||
Connection.prototype.isConnected = function() {
|
||||
return !!this.targetConnection;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether the current connection can connect with the target
|
||||
* connection.
|
||||
* @param {Blockly.Connection} target Connection to check compatibility with.
|
||||
* @return {number} Blockly.Connection.CAN_CONNECT if the connection is legal,
|
||||
* @param {Connection} target Connection to check compatibility with.
|
||||
* @return {number} Connection.CAN_CONNECT if the connection is legal,
|
||||
* an error code otherwise.
|
||||
* @deprecated July 2020. Will be deleted July 2021. Use the workspace's
|
||||
* connectionChecker instead.
|
||||
*/
|
||||
Blockly.Connection.prototype.canConnectWithReason = function(target) {
|
||||
Blockly.utils.deprecation.warn(
|
||||
'Connection.prototype.canConnectWithReason',
|
||||
'July 2020',
|
||||
'July 2021',
|
||||
Connection.prototype.canConnectWithReason = function(target) {
|
||||
deprecation.warn(
|
||||
'Connection.prototype.canConnectWithReason', 'July 2020', 'July 2021',
|
||||
'the workspace\'s connection checker');
|
||||
return this.getConnectionChecker().canConnectWithReason(
|
||||
this, target, false);
|
||||
return this.getConnectionChecker().canConnectWithReason(this, target, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether the current connection and target connection are compatible
|
||||
* and throws an exception if they are not.
|
||||
* @param {Blockly.Connection} target The connection to check compatibility
|
||||
* @param {Connection} target The connection to check compatibility
|
||||
* with.
|
||||
* @package
|
||||
* @deprecated July 2020. Will be deleted July 2021. Use the workspace's
|
||||
* connectionChecker instead.
|
||||
*/
|
||||
Blockly.Connection.prototype.checkConnection = function(target) {
|
||||
Blockly.utils.deprecation.warn(
|
||||
'Connection.prototype.checkConnection',
|
||||
'July 2020',
|
||||
'July 2021',
|
||||
Connection.prototype.checkConnection = function(target) {
|
||||
deprecation.warn(
|
||||
'Connection.prototype.checkConnection', 'July 2020', 'July 2021',
|
||||
'the workspace\'s connection checker');
|
||||
var checker = this.getConnectionChecker();
|
||||
var reason = checker.canConnectWithReason(this, target, false);
|
||||
if (reason != Blockly.Connection.CAN_CONNECT) {
|
||||
const checker = this.getConnectionChecker();
|
||||
const reason = checker.canConnectWithReason(this, target, false);
|
||||
if (reason != Connection.CAN_CONNECT) {
|
||||
throw new Error(checker.getErrorMessage(reason, this, target));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the workspace's connection type checker object.
|
||||
* @return {!Blockly.IConnectionChecker} The connection type checker for the
|
||||
* @return {!IConnectionChecker} The connection type checker for the
|
||||
* source block's workspace.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Connection.prototype.getConnectionChecker = function() {
|
||||
Connection.prototype.getConnectionChecker = function() {
|
||||
return this.sourceBlock_.workspace.connectionChecker;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the two connections can be dragged to connect to each other.
|
||||
* @param {!Blockly.Connection} candidate A nearby connection to check.
|
||||
* @param {!Connection} candidate A nearby connection to check.
|
||||
* @return {boolean} True if the connection is allowed, false otherwise.
|
||||
* @deprecated July 2020. Will be deleted July 2021. Use the workspace's
|
||||
* connectionChecker instead.
|
||||
*/
|
||||
Blockly.Connection.prototype.isConnectionAllowed = function(candidate) {
|
||||
Blockly.utils.deprecation.warn(
|
||||
'Connection.prototype.isConnectionAllowed',
|
||||
'July 2020',
|
||||
'July 2021',
|
||||
Connection.prototype.isConnectionAllowed = function(candidate) {
|
||||
deprecation.warn(
|
||||
'Connection.prototype.isConnectionAllowed', 'July 2020', 'July 2021',
|
||||
'the workspace\'s connection checker');
|
||||
return this.getConnectionChecker().canConnect(this, candidate, true);
|
||||
};
|
||||
@@ -272,29 +269,29 @@ Blockly.Connection.prototype.isConnectionAllowed = function(candidate) {
|
||||
/**
|
||||
* Called when an attempted connection fails. NOP by default (i.e. for headless
|
||||
* workspaces).
|
||||
* @param {!Blockly.Connection} _otherConnection Connection that this connection
|
||||
* @param {!Connection} _otherConnection Connection that this connection
|
||||
* failed to connect to.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Connection.prototype.onFailedConnect = function(_otherConnection) {
|
||||
Connection.prototype.onFailedConnect = function(_otherConnection) {
|
||||
// NOP
|
||||
};
|
||||
|
||||
/**
|
||||
* Connect this connection to another connection.
|
||||
* @param {!Blockly.Connection} otherConnection Connection to connect to.
|
||||
* @param {!Connection} otherConnection Connection to connect to.
|
||||
*/
|
||||
Blockly.Connection.prototype.connect = function(otherConnection) {
|
||||
Connection.prototype.connect = function(otherConnection) {
|
||||
if (this.targetConnection == otherConnection) {
|
||||
// Already connected together. NOP.
|
||||
return;
|
||||
}
|
||||
|
||||
var checker = this.getConnectionChecker();
|
||||
const checker = this.getConnectionChecker();
|
||||
if (checker.canConnect(this, otherConnection, false)) {
|
||||
var eventGroup = Blockly.Events.getGroup();
|
||||
const eventGroup = Events.getGroup();
|
||||
if (!eventGroup) {
|
||||
Blockly.Events.setGroup(true);
|
||||
Events.setGroup(true);
|
||||
}
|
||||
// Determine which block is superior (higher in the source stack).
|
||||
if (this.isSuperior()) {
|
||||
@@ -305,18 +302,17 @@ Blockly.Connection.prototype.connect = function(otherConnection) {
|
||||
otherConnection.connect_(this);
|
||||
}
|
||||
if (!eventGroup) {
|
||||
Blockly.Events.setGroup(false);
|
||||
Events.setGroup(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update two connections to target each other.
|
||||
* @param {Blockly.Connection} first The first connection to update.
|
||||
* @param {Blockly.Connection} second The second connection to update.
|
||||
* @private
|
||||
* @param {Connection} first The first connection to update.
|
||||
* @param {Connection} second The second connection to update.
|
||||
*/
|
||||
Blockly.Connection.connectReciprocally_ = function(first, second) {
|
||||
const connectReciprocally = function(first, second) {
|
||||
if (!first || !second) {
|
||||
throw Error('Cannot connect null connections.');
|
||||
}
|
||||
@@ -329,19 +325,18 @@ Blockly.Connection.connectReciprocally_ = function(first, second) {
|
||||
* block, if one can be found. If the block has multiple compatible connections
|
||||
* (even if they are filled) this returns null. If the block has no compatible
|
||||
* connections, this returns null.
|
||||
* @param {!Blockly.Block} block The superior block.
|
||||
* @param {!Blockly.Block} orphanBlock The inferior block.
|
||||
* @return {?Blockly.Connection} The suitable connection point on 'block',
|
||||
* @param {!Block} block The superior block.
|
||||
* @param {!Block} orphanBlock The inferior block.
|
||||
* @return {?Connection} The suitable connection point on 'block',
|
||||
* or null.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Connection.getSingleConnection_ = function(block, orphanBlock) {
|
||||
var foundConnection = null;
|
||||
var output = orphanBlock.outputConnection;
|
||||
var typeChecker = output.getConnectionChecker();
|
||||
const getSingleConnection = function(block, orphanBlock) {
|
||||
let foundConnection = null;
|
||||
const output = orphanBlock.outputConnection;
|
||||
const typeChecker = output.getConnectionChecker();
|
||||
|
||||
for (var i = 0, input; (input = block.inputList[i]); i++) {
|
||||
var connection = input.connection;
|
||||
for (let i = 0, input; (input = block.inputList[i]); i++) {
|
||||
const connection = input.connection;
|
||||
if (connection && typeChecker.canConnect(output, connection, false)) {
|
||||
if (foundConnection) {
|
||||
return null; // More than one connection.
|
||||
@@ -358,64 +353,62 @@ Blockly.Connection.getSingleConnection_ = function(block, orphanBlock) {
|
||||
* are zero or multiple eligible connections, returns null. Otherwise
|
||||
* returns the only input on the last block in the chain.
|
||||
* Terminates early for shadow blocks.
|
||||
* @param {!Blockly.Block} startBlock The block on which to start the search.
|
||||
* @param {!Blockly.Block} orphanBlock The block that is looking for a home.
|
||||
* @return {?Blockly.Connection} The suitable connection point on the chain
|
||||
* @param {!Block} startBlock The block on which to start the search.
|
||||
* @param {!Block} orphanBlock The block that is looking for a home.
|
||||
* @return {?Connection} The suitable connection point on the chain
|
||||
* of blocks, or null.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Connection.getConnectionForOrphanedOutput_ =
|
||||
function(startBlock, orphanBlock) {
|
||||
var newBlock = startBlock;
|
||||
var connection;
|
||||
while ((connection = Blockly.Connection.getSingleConnection_(
|
||||
/** @type {!Blockly.Block} */ (newBlock), orphanBlock))) {
|
||||
newBlock = connection.targetBlock();
|
||||
if (!newBlock || newBlock.isShadow()) {
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
const getConnectionForOrphanedOutput = function(startBlock, orphanBlock) {
|
||||
let newBlock = startBlock;
|
||||
let connection;
|
||||
while (
|
||||
(connection = getSingleConnection(
|
||||
/** @type {!Block} */ (newBlock), orphanBlock))) {
|
||||
newBlock = connection.targetBlock();
|
||||
if (!newBlock || newBlock.isShadow()) {
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the connection (starting at the startBlock) which will accept
|
||||
* the given connection. This includes compatible connection types and
|
||||
* connection checks.
|
||||
* @param {!Blockly.Block} startBlock The block on which to start the search.
|
||||
* @param {!Blockly.Connection} orphanConnection The connection that is looking
|
||||
* @param {!Block} startBlock The block on which to start the search.
|
||||
* @param {!Connection} orphanConnection The connection that is looking
|
||||
* for a home.
|
||||
* @return {?Blockly.Connection} The suitable connection point on the chain of
|
||||
* @return {?Connection} The suitable connection point on the chain of
|
||||
* blocks, or null.
|
||||
*/
|
||||
Blockly.Connection.getConnectionForOrphanedConnection =
|
||||
function(startBlock, orphanConnection) {
|
||||
if (orphanConnection.type === Blockly.connectionTypes.OUTPUT_VALUE) {
|
||||
return Blockly.Connection.getConnectionForOrphanedOutput_(
|
||||
startBlock, orphanConnection.getSourceBlock());
|
||||
}
|
||||
// Otherwise we're dealing with a stack.
|
||||
var connection = startBlock.lastConnectionInStack(true);
|
||||
var checker = orphanConnection.getConnectionChecker();
|
||||
if (connection &&
|
||||
checker.canConnect(orphanConnection, connection, false)) {
|
||||
return connection;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
Connection.getConnectionForOrphanedConnection = function(
|
||||
startBlock, orphanConnection) {
|
||||
if (orphanConnection.type === connectionTypes.OUTPUT_VALUE) {
|
||||
return getConnectionForOrphanedOutput(
|
||||
startBlock, orphanConnection.getSourceBlock());
|
||||
}
|
||||
// Otherwise we're dealing with a stack.
|
||||
const connection = startBlock.lastConnectionInStack(true);
|
||||
const checker = orphanConnection.getConnectionChecker();
|
||||
if (connection && checker.canConnect(orphanConnection, connection, false)) {
|
||||
return connection;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Disconnect this connection.
|
||||
*/
|
||||
Blockly.Connection.prototype.disconnect = function() {
|
||||
var otherConnection = this.targetConnection;
|
||||
Connection.prototype.disconnect = function() {
|
||||
const otherConnection = this.targetConnection;
|
||||
if (!otherConnection) {
|
||||
throw Error('Source connection not connected.');
|
||||
}
|
||||
if (otherConnection.targetConnection != this) {
|
||||
throw Error('Target connection not connected to source connection.');
|
||||
}
|
||||
var parentBlock, childBlock, parentConnection;
|
||||
let parentBlock, childBlock, parentConnection;
|
||||
if (this.isSuperior()) {
|
||||
// Superior block.
|
||||
parentBlock = this.sourceBlock_;
|
||||
@@ -428,9 +421,9 @@ Blockly.Connection.prototype.disconnect = function() {
|
||||
parentConnection = otherConnection;
|
||||
}
|
||||
|
||||
var eventGroup = Blockly.Events.getGroup();
|
||||
const eventGroup = Events.getGroup();
|
||||
if (!eventGroup) {
|
||||
Blockly.Events.setGroup(true);
|
||||
Events.setGroup(true);
|
||||
}
|
||||
this.disconnectInternal_(parentBlock, childBlock);
|
||||
if (!childBlock.isShadow()) {
|
||||
@@ -438,29 +431,28 @@ Blockly.Connection.prototype.disconnect = function() {
|
||||
parentConnection.respawnShadow_();
|
||||
}
|
||||
if (!eventGroup) {
|
||||
Blockly.Events.setGroup(false);
|
||||
Events.setGroup(false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Disconnect two blocks that are connected by this connection.
|
||||
* @param {!Blockly.Block} parentBlock The superior block.
|
||||
* @param {!Blockly.Block} childBlock The inferior block.
|
||||
* @param {!Block} parentBlock The superior block.
|
||||
* @param {!Block} childBlock The inferior block.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Connection.prototype.disconnectInternal_ = function(parentBlock,
|
||||
childBlock) {
|
||||
var event;
|
||||
if (Blockly.Events.isEnabled()) {
|
||||
event = new (Blockly.Events.get(Blockly.Events.BLOCK_MOVE))(childBlock);
|
||||
Connection.prototype.disconnectInternal_ = function(parentBlock, childBlock) {
|
||||
let event;
|
||||
if (Events.isEnabled()) {
|
||||
event = new (Events.get(Events.BLOCK_MOVE))(childBlock);
|
||||
}
|
||||
var otherConnection = this.targetConnection;
|
||||
const otherConnection = this.targetConnection;
|
||||
otherConnection.targetConnection = null;
|
||||
this.targetConnection = null;
|
||||
childBlock.setParent(null);
|
||||
if (event) {
|
||||
event.recordNew();
|
||||
Blockly.Events.fire(event);
|
||||
Events.fire(event);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -468,11 +460,11 @@ Blockly.Connection.prototype.disconnectInternal_ = function(parentBlock,
|
||||
* Respawn the shadow block if there was one connected to the this connection.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Connection.prototype.respawnShadow_ = function() {
|
||||
var parentBlock = this.getSourceBlock();
|
||||
var shadow = this.getShadowDom();
|
||||
Connection.prototype.respawnShadow_ = function() {
|
||||
const parentBlock = this.getSourceBlock();
|
||||
const shadow = this.getShadowDom();
|
||||
if (parentBlock.workspace && shadow) {
|
||||
var blockShadow = Blockly.Xml.domToBlock(shadow, parentBlock.workspace);
|
||||
const blockShadow = Xml.domToBlock(shadow, parentBlock.workspace);
|
||||
if (blockShadow.outputConnection) {
|
||||
this.connect(blockShadow.outputConnection);
|
||||
} else if (blockShadow.previousConnection) {
|
||||
@@ -485,9 +477,9 @@ Blockly.Connection.prototype.respawnShadow_ = function() {
|
||||
|
||||
/**
|
||||
* Returns the block that this connection connects to.
|
||||
* @return {?Blockly.Block} The connected block or null if none is connected.
|
||||
* @return {?Block} The connected block or null if none is connected.
|
||||
*/
|
||||
Blockly.Connection.prototype.targetBlock = function() {
|
||||
Connection.prototype.targetBlock = function() {
|
||||
if (this.isConnected()) {
|
||||
return this.targetConnection.getSourceBlock();
|
||||
}
|
||||
@@ -497,36 +489,31 @@ Blockly.Connection.prototype.targetBlock = function() {
|
||||
/**
|
||||
* Is this connection compatible with another connection with respect to the
|
||||
* value type system. E.g. square_root("Hello") is not compatible.
|
||||
* @param {!Blockly.Connection} otherConnection Connection to compare against.
|
||||
* @param {!Connection} otherConnection Connection to compare against.
|
||||
* @return {boolean} True if the connections share a type.
|
||||
* @deprecated July 2020. Will be deleted July 2021. Use the workspace's
|
||||
* connectionChecker instead.
|
||||
*/
|
||||
Blockly.Connection.prototype.checkType = function(otherConnection) {
|
||||
Blockly.utils.deprecation.warn(
|
||||
'Connection.prototype.checkType',
|
||||
'October 2019',
|
||||
'January 2021',
|
||||
Connection.prototype.checkType = function(otherConnection) {
|
||||
deprecation.warn(
|
||||
'Connection.prototype.checkType', 'October 2019', 'January 2021',
|
||||
'the workspace\'s connection checker');
|
||||
return this.getConnectionChecker().canConnect(this, otherConnection,
|
||||
false);
|
||||
return this.getConnectionChecker().canConnect(this, otherConnection, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Is this connection compatible with another connection with respect to the
|
||||
* value type system. E.g. square_root("Hello") is not compatible.
|
||||
* @param {!Blockly.Connection} otherConnection Connection to compare against.
|
||||
* @param {!Connection} otherConnection Connection to compare against.
|
||||
* @return {boolean} True if the connections share a type.
|
||||
* @private
|
||||
* @deprecated October 2019. Will be deleted January 2021. Use the workspace's
|
||||
* connectionChecker instead.
|
||||
* @suppress {unusedPrivateMembers}
|
||||
*/
|
||||
Blockly.Connection.prototype.checkType_ = function(otherConnection) {
|
||||
Blockly.utils.deprecation.warn(
|
||||
'Connection.prototype.checkType_',
|
||||
'October 2019',
|
||||
'January 2021',
|
||||
Connection.prototype.checkType_ = function(otherConnection) {
|
||||
deprecation.warn(
|
||||
'Connection.prototype.checkType_', 'October 2019', 'January 2021',
|
||||
'the workspace\'s connection checker');
|
||||
return this.checkType(otherConnection);
|
||||
};
|
||||
@@ -535,12 +522,13 @@ Blockly.Connection.prototype.checkType_ = function(otherConnection) {
|
||||
* Function to be called when this connection's compatible types have changed.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Connection.prototype.onCheckChanged_ = function() {
|
||||
Connection.prototype.onCheckChanged_ = function() {
|
||||
// The new value type may not be compatible with the existing connection.
|
||||
if (this.isConnected() && (!this.targetConnection ||
|
||||
!this.getConnectionChecker().canConnect(
|
||||
this, this.targetConnection, false))) {
|
||||
var child = this.isSuperior() ? this.targetBlock() : this.sourceBlock_;
|
||||
if (this.isConnected() &&
|
||||
(!this.targetConnection ||
|
||||
!this.getConnectionChecker().canConnect(
|
||||
this, this.targetConnection, false))) {
|
||||
const child = this.isSuperior() ? this.targetBlock() : this.sourceBlock_;
|
||||
child.unplug();
|
||||
}
|
||||
};
|
||||
@@ -549,10 +537,10 @@ Blockly.Connection.prototype.onCheckChanged_ = function() {
|
||||
* Change a connection's compatibility.
|
||||
* @param {?(string|!Array<string>)} check Compatible value type or list of
|
||||
* value types. Null if all types are compatible.
|
||||
* @return {!Blockly.Connection} The connection being modified
|
||||
* @return {!Connection} The connection being modified
|
||||
* (to allow chaining).
|
||||
*/
|
||||
Blockly.Connection.prototype.setCheck = function(check) {
|
||||
Connection.prototype.setCheck = function(check) {
|
||||
if (check) {
|
||||
// Ensure that check is in an array.
|
||||
if (!Array.isArray(check)) {
|
||||
@@ -572,7 +560,7 @@ Blockly.Connection.prototype.setCheck = function(check) {
|
||||
* Null if all types are compatible.
|
||||
* @public
|
||||
*/
|
||||
Blockly.Connection.prototype.getCheck = function() {
|
||||
Connection.prototype.getCheck = function() {
|
||||
return this.check_;
|
||||
};
|
||||
|
||||
@@ -580,9 +568,9 @@ Blockly.Connection.prototype.getCheck = function() {
|
||||
* Changes the connection's shadow block.
|
||||
* @param {?Element} shadow DOM representation of a block or null.
|
||||
*/
|
||||
Blockly.Connection.prototype.setShadowDom = function(shadow) {
|
||||
Connection.prototype.setShadowDom = function(shadow) {
|
||||
this.shadowDom_ = shadow;
|
||||
var target = this.targetBlock();
|
||||
const target = this.targetBlock();
|
||||
if (!target) {
|
||||
this.respawnShadow_();
|
||||
} else if (target.isShadow()) {
|
||||
@@ -600,10 +588,10 @@ Blockly.Connection.prototype.setShadowDom = function(shadow) {
|
||||
* shadowDom is just returned.
|
||||
* @return {?Element} Shadow DOM representation of a block or null.
|
||||
*/
|
||||
Blockly.Connection.prototype.getShadowDom = function(returnCurrent) {
|
||||
Connection.prototype.getShadowDom = function(returnCurrent) {
|
||||
return (returnCurrent && this.targetBlock().isShadow()) ?
|
||||
/** @type {!Element} */ (Blockly.Xml.blockToDom(
|
||||
/** @type {!Blockly.Block} */ (this.targetBlock()))) :
|
||||
/** @type {!Element} */ (Xml.blockToDom(
|
||||
/** @type {!Block} */ (this.targetBlock()))) :
|
||||
this.shadowDom_;
|
||||
};
|
||||
|
||||
@@ -616,23 +604,23 @@ Blockly.Connection.prototype.getShadowDom = function(returnCurrent) {
|
||||
* {@link Blockly.RenderedConnection} overrides this behavior with a list
|
||||
* computed from the rendered positioning.
|
||||
* @param {number} _maxLimit The maximum radius to another connection.
|
||||
* @return {!Array<!Blockly.Connection>} List of connections.
|
||||
* @return {!Array<!Connection>} List of connections.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Connection.prototype.neighbours = function(_maxLimit) {
|
||||
Connection.prototype.neighbours = function(_maxLimit) {
|
||||
return [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the parent input of a connection.
|
||||
* @return {?Blockly.Input} The input that the connection belongs to or null if
|
||||
* @return {?Input} The input that the connection belongs to or null if
|
||||
* no parent exists.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Connection.prototype.getParentInput = function() {
|
||||
var parentInput = null;
|
||||
var inputs = this.sourceBlock_.inputList;
|
||||
for (var i = 0; i < inputs.length; i++) {
|
||||
Connection.prototype.getParentInput = function() {
|
||||
let parentInput = null;
|
||||
const inputs = this.sourceBlock_.inputList;
|
||||
for (let i = 0; i < inputs.length; i++) {
|
||||
if (inputs[i].connection === this) {
|
||||
parentInput = inputs[i];
|
||||
break;
|
||||
@@ -646,12 +634,12 @@ Blockly.Connection.prototype.getParentInput = function() {
|
||||
* (English only). Intended to on be used in console logs and errors.
|
||||
* @return {string} The description.
|
||||
*/
|
||||
Blockly.Connection.prototype.toString = function() {
|
||||
var block = this.sourceBlock_;
|
||||
Connection.prototype.toString = function() {
|
||||
const block = this.sourceBlock_;
|
||||
if (!block) {
|
||||
return 'Orphan Connection';
|
||||
}
|
||||
var msg;
|
||||
let msg;
|
||||
if (block.outputConnection == this) {
|
||||
msg = 'Output Connection of ';
|
||||
} else if (block.previousConnection == this) {
|
||||
@@ -659,8 +647,8 @@ Blockly.Connection.prototype.toString = function() {
|
||||
} else if (block.nextConnection == this) {
|
||||
msg = 'Next Connection of ';
|
||||
} else {
|
||||
var parentInput = null;
|
||||
for (var i = 0, input; (input = block.inputList[i]); i++) {
|
||||
let parentInput = null;
|
||||
for (let i = 0, input; (input = block.inputList[i]); i++) {
|
||||
if (input.connection == this) {
|
||||
parentInput = input;
|
||||
break;
|
||||
@@ -675,3 +663,5 @@ Blockly.Connection.prototype.toString = function() {
|
||||
}
|
||||
return msg + block.toDevString();
|
||||
};
|
||||
|
||||
exports = Connection;
|
||||
|
||||
@@ -5,37 +5,37 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview An object that encapsulates logic for checking whether a potential
|
||||
* connection is safe and valid.
|
||||
* @fileoverview An object that encapsulates logic for checking whether a
|
||||
* potential connection is safe and valid.
|
||||
* @author fenichel@google.com (Rachel Fenichel)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.ConnectionChecker');
|
||||
goog.module('Blockly.ConnectionChecker');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Connection');
|
||||
goog.require('Blockly.connectionTypes');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.IConnectionChecker');
|
||||
goog.require('Blockly.registry');
|
||||
|
||||
goog.requireType('Blockly.RenderedConnection');
|
||||
const Connection = goog.require('Blockly.Connection');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IConnectionChecker = goog.require('Blockly.IConnectionChecker');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const RenderedConnection = goog.requireType('Blockly.RenderedConnection');
|
||||
const connectionTypes = goog.require('Blockly.connectionTypes');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
const {OPPOSITE_TYPE} = goog.require('Blockly.internalConstants');
|
||||
|
||||
|
||||
/**
|
||||
* Class for connection type checking logic.
|
||||
* @implements {Blockly.IConnectionChecker}
|
||||
* @implements {IConnectionChecker}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.ConnectionChecker = function() {
|
||||
};
|
||||
const ConnectionChecker = function() {};
|
||||
|
||||
/**
|
||||
* Check whether the current connection can connect with the target
|
||||
* connection.
|
||||
* @param {Blockly.Connection} a Connection to check compatibility with.
|
||||
* @param {Blockly.Connection} b Connection to check compatibility with.
|
||||
* @param {Connection} a Connection to check compatibility with.
|
||||
* @param {Connection} b Connection to check compatibility with.
|
||||
* @param {boolean} isDragging True if the connection is being made by dragging
|
||||
* a block.
|
||||
* @param {number=} opt_distance The max allowable distance between the
|
||||
@@ -43,80 +43,80 @@ Blockly.ConnectionChecker = function() {
|
||||
* @return {boolean} Whether the connection is legal.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ConnectionChecker.prototype.canConnect = function(a, b,
|
||||
isDragging, opt_distance) {
|
||||
ConnectionChecker.prototype.canConnect = function(
|
||||
a, b, isDragging, opt_distance) {
|
||||
return this.canConnectWithReason(a, b, isDragging, opt_distance) ==
|
||||
Blockly.Connection.CAN_CONNECT;
|
||||
Connection.CAN_CONNECT;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether the current connection can connect with the target
|
||||
* connection, and return an error code if there are problems.
|
||||
* @param {Blockly.Connection} a Connection to check compatibility with.
|
||||
* @param {Blockly.Connection} b Connection to check compatibility with.
|
||||
* @param {Connection} a Connection to check compatibility with.
|
||||
* @param {Connection} b Connection to check compatibility with.
|
||||
* @param {boolean} isDragging True if the connection is being made by dragging
|
||||
* a block.
|
||||
* @param {number=} opt_distance The max allowable distance between the
|
||||
* connections for drag checks.
|
||||
* @return {number} Blockly.Connection.CAN_CONNECT if the connection is legal,
|
||||
* @return {number} Connection.CAN_CONNECT if the connection is legal,
|
||||
* an error code otherwise.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ConnectionChecker.prototype.canConnectWithReason = function(
|
||||
ConnectionChecker.prototype.canConnectWithReason = function(
|
||||
a, b, isDragging, opt_distance) {
|
||||
var safety = this.doSafetyChecks(a, b);
|
||||
if (safety != Blockly.Connection.CAN_CONNECT) {
|
||||
const safety = this.doSafetyChecks(a, b);
|
||||
if (safety != Connection.CAN_CONNECT) {
|
||||
return safety;
|
||||
}
|
||||
|
||||
// If the safety checks passed, both connections are non-null.
|
||||
var connOne = /** @type {!Blockly.Connection} **/ (a);
|
||||
var connTwo = /** @type {!Blockly.Connection} **/ (b);
|
||||
const connOne = /** @type {!Connection} **/ (a);
|
||||
const connTwo = /** @type {!Connection} **/ (b);
|
||||
if (!this.doTypeChecks(connOne, connTwo)) {
|
||||
return Blockly.Connection.REASON_CHECKS_FAILED;
|
||||
return Connection.REASON_CHECKS_FAILED;
|
||||
}
|
||||
|
||||
if (isDragging &&
|
||||
!this.doDragChecks(
|
||||
/** @type {!Blockly.RenderedConnection} **/ (a),
|
||||
/** @type {!Blockly.RenderedConnection} **/ (b),
|
||||
opt_distance || 0)) {
|
||||
return Blockly.Connection.REASON_DRAG_CHECKS_FAILED;
|
||||
/** @type {!RenderedConnection} **/ (a),
|
||||
/** @type {!RenderedConnection} **/ (b), opt_distance || 0)) {
|
||||
return Connection.REASON_DRAG_CHECKS_FAILED;
|
||||
}
|
||||
|
||||
return Blockly.Connection.CAN_CONNECT;
|
||||
return Connection.CAN_CONNECT;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper method that translates a connection error code into a string.
|
||||
* @param {number} errorCode The error code.
|
||||
* @param {Blockly.Connection} a One of the two connections being checked.
|
||||
* @param {Blockly.Connection} b The second of the two connections being
|
||||
* @param {Connection} a One of the two connections being checked.
|
||||
* @param {Connection} b The second of the two connections being
|
||||
* checked.
|
||||
* @return {string} A developer-readable error string.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ConnectionChecker.prototype.getErrorMessage = function(errorCode,
|
||||
a, b) {
|
||||
ConnectionChecker.prototype.getErrorMessage = function(errorCode, a, b) {
|
||||
switch (errorCode) {
|
||||
case Blockly.Connection.REASON_SELF_CONNECTION:
|
||||
case Connection.REASON_SELF_CONNECTION:
|
||||
return 'Attempted to connect a block to itself.';
|
||||
case Blockly.Connection.REASON_DIFFERENT_WORKSPACES:
|
||||
case Connection.REASON_DIFFERENT_WORKSPACES:
|
||||
// Usually this means one block has been deleted.
|
||||
return 'Blocks not on same workspace.';
|
||||
case Blockly.Connection.REASON_WRONG_TYPE:
|
||||
case Connection.REASON_WRONG_TYPE:
|
||||
return 'Attempt to connect incompatible types.';
|
||||
case Blockly.Connection.REASON_TARGET_NULL:
|
||||
case Connection.REASON_TARGET_NULL:
|
||||
return 'Target connection is null.';
|
||||
case Blockly.Connection.REASON_CHECKS_FAILED:
|
||||
var connOne = /** @type {!Blockly.Connection} **/ (a);
|
||||
var connTwo = /** @type {!Blockly.Connection} **/ (b);
|
||||
var msg = 'Connection checks failed. ';
|
||||
msg += connOne + ' expected ' + connOne.getCheck() + ', found ' + connTwo.getCheck();
|
||||
case Connection.REASON_CHECKS_FAILED: {
|
||||
const connOne = /** @type {!Connection} **/ (a);
|
||||
const connTwo = /** @type {!Connection} **/ (b);
|
||||
let msg = 'Connection checks failed. ';
|
||||
msg += connOne + ' expected ' + connOne.getCheck() + ', found ' +
|
||||
connTwo.getCheck();
|
||||
return msg;
|
||||
case Blockly.Connection.REASON_SHADOW_PARENT:
|
||||
}
|
||||
case Connection.REASON_SHADOW_PARENT:
|
||||
return 'Connecting non-shadow to shadow block.';
|
||||
case Blockly.Connection.REASON_DRAG_CHECKS_FAILED:
|
||||
case Connection.REASON_DRAG_CHECKS_FAILED:
|
||||
return 'Drag checks failed.';
|
||||
default:
|
||||
return 'Unknown connection failure: this should never happen!';
|
||||
@@ -126,53 +126,54 @@ Blockly.ConnectionChecker.prototype.getErrorMessage = function(errorCode,
|
||||
/**
|
||||
* Check that connecting the given connections is safe, meaning that it would
|
||||
* not break any of Blockly's basic assumptions (e.g. no self connections).
|
||||
* @param {Blockly.Connection} a The first of the connections to check.
|
||||
* @param {Blockly.Connection} b The second of the connections to check.
|
||||
* @param {Connection} a The first of the connections to check.
|
||||
* @param {Connection} b The second of the connections to check.
|
||||
* @return {number} An enum with the reason this connection is safe or unsafe.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ConnectionChecker.prototype.doSafetyChecks = function(a, b) {
|
||||
ConnectionChecker.prototype.doSafetyChecks = function(a, b) {
|
||||
if (!a || !b) {
|
||||
return Blockly.Connection.REASON_TARGET_NULL;
|
||||
return Connection.REASON_TARGET_NULL;
|
||||
}
|
||||
let blockA, blockB;
|
||||
if (a.isSuperior()) {
|
||||
var blockA = a.getSourceBlock();
|
||||
var blockB = b.getSourceBlock();
|
||||
blockA = a.getSourceBlock();
|
||||
blockB = b.getSourceBlock();
|
||||
} else {
|
||||
var blockB = a.getSourceBlock();
|
||||
var blockA = b.getSourceBlock();
|
||||
blockB = a.getSourceBlock();
|
||||
blockA = b.getSourceBlock();
|
||||
}
|
||||
if (blockA == blockB) {
|
||||
return Blockly.Connection.REASON_SELF_CONNECTION;
|
||||
} else if (b.type != Blockly.OPPOSITE_TYPE[a.type]) {
|
||||
return Blockly.Connection.REASON_WRONG_TYPE;
|
||||
return Connection.REASON_SELF_CONNECTION;
|
||||
} else if (b.type != OPPOSITE_TYPE[a.type]) {
|
||||
return Connection.REASON_WRONG_TYPE;
|
||||
} else if (blockA.workspace !== blockB.workspace) {
|
||||
return Blockly.Connection.REASON_DIFFERENT_WORKSPACES;
|
||||
return Connection.REASON_DIFFERENT_WORKSPACES;
|
||||
} else if (blockA.isShadow() && !blockB.isShadow()) {
|
||||
return Blockly.Connection.REASON_SHADOW_PARENT;
|
||||
return Connection.REASON_SHADOW_PARENT;
|
||||
}
|
||||
return Blockly.Connection.CAN_CONNECT;
|
||||
return Connection.CAN_CONNECT;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check whether this connection is compatible with another connection with
|
||||
* respect to the value type system. E.g. square_root("Hello") is not
|
||||
* compatible.
|
||||
* @param {!Blockly.Connection} a Connection to compare.
|
||||
* @param {!Blockly.Connection} b Connection to compare against.
|
||||
* @param {!Connection} a Connection to compare.
|
||||
* @param {!Connection} b Connection to compare against.
|
||||
* @return {boolean} True if the connections share a type.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ConnectionChecker.prototype.doTypeChecks = function(a, b) {
|
||||
var checkArrayOne = a.getCheck();
|
||||
var checkArrayTwo = b.getCheck();
|
||||
ConnectionChecker.prototype.doTypeChecks = function(a, b) {
|
||||
const checkArrayOne = a.getCheck();
|
||||
const checkArrayTwo = b.getCheck();
|
||||
|
||||
if (!checkArrayOne || !checkArrayTwo) {
|
||||
// One or both sides are promiscuous enough that anything will fit.
|
||||
return true;
|
||||
}
|
||||
// Find any intersection in the check lists.
|
||||
for (var i = 0; i < checkArrayOne.length; i++) {
|
||||
for (let i = 0; i < checkArrayOne.length; i++) {
|
||||
if (checkArrayTwo.indexOf(checkArrayOne[i]) != -1) {
|
||||
return true;
|
||||
}
|
||||
@@ -183,13 +184,13 @@ Blockly.ConnectionChecker.prototype.doTypeChecks = function(a, b) {
|
||||
|
||||
/**
|
||||
* Check whether this connection can be made by dragging.
|
||||
* @param {!Blockly.RenderedConnection} a Connection to compare.
|
||||
* @param {!Blockly.RenderedConnection} b Connection to compare against.
|
||||
* @param {!RenderedConnection} a Connection to compare.
|
||||
* @param {!RenderedConnection} b Connection to compare against.
|
||||
* @param {number} distance The maximum allowable distance between connections.
|
||||
* @return {boolean} True if the connection is allowed during a drag.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ConnectionChecker.prototype.doDragChecks = function(a, b, distance) {
|
||||
ConnectionChecker.prototype.doDragChecks = function(a, b, distance) {
|
||||
if (a.distanceFrom(b) > distance) {
|
||||
return false;
|
||||
}
|
||||
@@ -200,38 +201,34 @@ Blockly.ConnectionChecker.prototype.doDragChecks = function(a, b, distance) {
|
||||
}
|
||||
|
||||
switch (b.type) {
|
||||
case Blockly.connectionTypes.PREVIOUS_STATEMENT:
|
||||
case connectionTypes.PREVIOUS_STATEMENT:
|
||||
return this.canConnectToPrevious_(a, b);
|
||||
case Blockly.connectionTypes.OUTPUT_VALUE: {
|
||||
case connectionTypes.OUTPUT_VALUE: {
|
||||
// Don't offer to connect an already connected left (male) value plug to
|
||||
// an available right (female) value plug.
|
||||
if ((b.isConnected() &&
|
||||
!b.targetBlock().isInsertionMarker()) ||
|
||||
if ((b.isConnected() && !b.targetBlock().isInsertionMarker()) ||
|
||||
a.isConnected()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Blockly.connectionTypes.INPUT_VALUE: {
|
||||
case connectionTypes.INPUT_VALUE: {
|
||||
// Offering to connect the left (male) of a value block to an already
|
||||
// connected value pair is ok, we'll splice it in.
|
||||
// However, don't offer to splice into an immovable block.
|
||||
if (b.isConnected() &&
|
||||
!b.targetBlock().isMovable() &&
|
||||
if (b.isConnected() && !b.targetBlock().isMovable() &&
|
||||
!b.targetBlock().isShadow()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Blockly.connectionTypes.NEXT_STATEMENT: {
|
||||
case connectionTypes.NEXT_STATEMENT: {
|
||||
// Don't let a block with no next connection bump other blocks out of the
|
||||
// stack. But covering up a shadow block or stack of shadow blocks is
|
||||
// fine. Similarly, replacing a terminal statement with another terminal
|
||||
// statement is allowed.
|
||||
if (b.isConnected() &&
|
||||
!a.getSourceBlock().nextConnection &&
|
||||
!b.targetBlock().isShadow() &&
|
||||
b.targetBlock().nextConnection) {
|
||||
if (b.isConnected() && !a.getSourceBlock().nextConnection &&
|
||||
!b.targetBlock().isShadow() && b.targetBlock().nextConnection) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@@ -251,14 +248,14 @@ Blockly.ConnectionChecker.prototype.doDragChecks = function(a, b, distance) {
|
||||
|
||||
/**
|
||||
* Helper function for drag checking.
|
||||
* @param {!Blockly.Connection} a The connection to check, which must be a
|
||||
* @param {!Connection} a The connection to check, which must be a
|
||||
* statement input or next connection.
|
||||
* @param {!Blockly.Connection} b A nearby connection to check, which
|
||||
* @param {!Connection} b A nearby connection to check, which
|
||||
* must be a previous connection.
|
||||
* @return {boolean} True if the connection is allowed, false otherwise.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.ConnectionChecker.prototype.canConnectToPrevious_ = function(a, b) {
|
||||
ConnectionChecker.prototype.canConnectToPrevious_ = function(a, b) {
|
||||
if (a.targetConnection) {
|
||||
// This connection is already occupied.
|
||||
// A next connection will never disconnect itself mid-drag.
|
||||
@@ -274,7 +271,7 @@ Blockly.ConnectionChecker.prototype.canConnectToPrevious_ = function(a, b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var targetBlock = b.targetBlock();
|
||||
const targetBlock = b.targetBlock();
|
||||
// If it is connected to a real block, game over.
|
||||
if (!targetBlock.isInsertionMarker()) {
|
||||
return false;
|
||||
@@ -285,5 +282,7 @@ Blockly.ConnectionChecker.prototype.canConnectToPrevious_ = function(a, b) {
|
||||
return !targetBlock.getPreviousBlock();
|
||||
};
|
||||
|
||||
Blockly.registry.register(Blockly.registry.Type.CONNECTION_CHECKER,
|
||||
Blockly.registry.DEFAULT, Blockly.ConnectionChecker);
|
||||
registry.register(
|
||||
registry.Type.CONNECTION_CHECKER, registry.DEFAULT, ConnectionChecker);
|
||||
|
||||
exports = ConnectionChecker;
|
||||
|
||||
@@ -12,37 +12,40 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.ConnectionDB');
|
||||
goog.module('Blockly.ConnectionDB');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.connectionTypes');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Coordinate = goog.requireType('Blockly.utils.Coordinate');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IConnectionChecker = goog.requireType('Blockly.IConnectionChecker');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const RenderedConnection = goog.require('Blockly.RenderedConnection');
|
||||
const connectionTypes = goog.require('Blockly.connectionTypes');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.RenderedConnection');
|
||||
|
||||
goog.requireType('Blockly.IConnectionChecker');
|
||||
goog.requireType('Blockly.utils.Coordinate');
|
||||
|
||||
|
||||
/**
|
||||
* Database of connections.
|
||||
* Connections are stored in order of their vertical component. This way
|
||||
* connections in an area may be looked up quickly using a binary search.
|
||||
* @param {!Blockly.IConnectionChecker} checker The workspace's
|
||||
* @param {!IConnectionChecker} checker The workspace's
|
||||
* connection type checker, used to decide if connections are valid during a
|
||||
* drag.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.ConnectionDB = function(checker) {
|
||||
const ConnectionDB = function(checker) {
|
||||
/**
|
||||
* Array of connections sorted by y position in workspace units.
|
||||
* @type {!Array<!Blockly.RenderedConnection>}
|
||||
* @type {!Array<!RenderedConnection>}
|
||||
* @private
|
||||
*/
|
||||
this.connections_ = [];
|
||||
/**
|
||||
* The workspace's connection type checker, used to decide if connections are
|
||||
* valid during a drag.
|
||||
* @type {!Blockly.IConnectionChecker}
|
||||
* @type {!IConnectionChecker}
|
||||
* @private
|
||||
*/
|
||||
this.connectionChecker_ = checker;
|
||||
@@ -50,13 +53,13 @@ Blockly.ConnectionDB = function(checker) {
|
||||
|
||||
/**
|
||||
* Add a connection to the database. Should not already exist in the database.
|
||||
* @param {!Blockly.RenderedConnection} connection The connection to be added.
|
||||
* @param {!RenderedConnection} connection The connection to be added.
|
||||
* @param {number} yPos The y position used to decide where to insert the
|
||||
* connection.
|
||||
* @package
|
||||
*/
|
||||
Blockly.ConnectionDB.prototype.addConnection = function(connection, yPos) {
|
||||
var index = this.calculateIndexForYPos_(yPos);
|
||||
ConnectionDB.prototype.addConnection = function(connection, yPos) {
|
||||
const index = this.calculateIndexForYPos_(yPos);
|
||||
this.connections_.splice(index, 0, connection);
|
||||
};
|
||||
|
||||
@@ -65,18 +68,18 @@ Blockly.ConnectionDB.prototype.addConnection = function(connection, yPos) {
|
||||
*
|
||||
* Starts by doing a binary search to find the approximate location, then
|
||||
* linearly searches nearby for the exact connection.
|
||||
* @param {!Blockly.RenderedConnection} conn The connection to find.
|
||||
* @param {!RenderedConnection} conn The connection to find.
|
||||
* @param {number} yPos The y position used to find the index of the connection.
|
||||
* @return {number} The index of the connection, or -1 if the connection was
|
||||
* not found.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ConnectionDB.prototype.findIndexOfConnection_ = function(conn, yPos) {
|
||||
ConnectionDB.prototype.findIndexOfConnection_ = function(conn, yPos) {
|
||||
if (!this.connections_.length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
var bestGuess = this.calculateIndexForYPos_(yPos);
|
||||
const bestGuess = this.calculateIndexForYPos_(yPos);
|
||||
if (bestGuess >= this.connections_.length) {
|
||||
// Not in list
|
||||
return -1;
|
||||
@@ -84,7 +87,7 @@ Blockly.ConnectionDB.prototype.findIndexOfConnection_ = function(conn, yPos) {
|
||||
|
||||
yPos = conn.y;
|
||||
// Walk forward and back on the y axis looking for the connection.
|
||||
var pointer = bestGuess;
|
||||
let pointer = bestGuess;
|
||||
while (pointer >= 0 && this.connections_[pointer].y == yPos) {
|
||||
if (this.connections_[pointer] == conn) {
|
||||
return pointer;
|
||||
@@ -110,14 +113,14 @@ Blockly.ConnectionDB.prototype.findIndexOfConnection_ = function(conn, yPos) {
|
||||
* @return {number} The candidate index.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ConnectionDB.prototype.calculateIndexForYPos_ = function(yPos) {
|
||||
ConnectionDB.prototype.calculateIndexForYPos_ = function(yPos) {
|
||||
if (!this.connections_.length) {
|
||||
return 0;
|
||||
}
|
||||
var pointerMin = 0;
|
||||
var pointerMax = this.connections_.length;
|
||||
let pointerMin = 0;
|
||||
let pointerMax = this.connections_.length;
|
||||
while (pointerMin < pointerMax) {
|
||||
var pointerMid = Math.floor((pointerMin + pointerMax) / 2);
|
||||
const pointerMid = Math.floor((pointerMin + pointerMax) / 2);
|
||||
if (this.connections_[pointerMid].y < yPos) {
|
||||
pointerMin = pointerMid + 1;
|
||||
} else if (this.connections_[pointerMid].y > yPos) {
|
||||
@@ -132,12 +135,12 @@ Blockly.ConnectionDB.prototype.calculateIndexForYPos_ = function(yPos) {
|
||||
|
||||
/**
|
||||
* Remove a connection from the database. Must already exist in DB.
|
||||
* @param {!Blockly.RenderedConnection} connection The connection to be removed.
|
||||
* @param {!RenderedConnection} connection The connection to be removed.
|
||||
* @param {number} yPos The y position used to find the index of the connection.
|
||||
* @throws {Error} If the connection cannot be found in the database.
|
||||
*/
|
||||
Blockly.ConnectionDB.prototype.removeConnection = function(connection, yPos) {
|
||||
var index = this.findIndexOfConnection_(connection, yPos);
|
||||
ConnectionDB.prototype.removeConnection = function(connection, yPos) {
|
||||
const index = this.findIndexOfConnection_(connection, yPos);
|
||||
if (index == -1) {
|
||||
throw Error('Unable to find connection in connectionDB.');
|
||||
}
|
||||
@@ -147,20 +150,20 @@ Blockly.ConnectionDB.prototype.removeConnection = function(connection, yPos) {
|
||||
/**
|
||||
* Find all nearby connections to the given connection.
|
||||
* Type checking does not apply, since this function is used for bumping.
|
||||
* @param {!Blockly.RenderedConnection} connection The connection whose
|
||||
* @param {!RenderedConnection} connection The connection whose
|
||||
* neighbours should be returned.
|
||||
* @param {number} maxRadius The maximum radius to another connection.
|
||||
* @return {!Array<!Blockly.RenderedConnection>} List of connections.
|
||||
* @return {!Array<!RenderedConnection>} List of connections.
|
||||
*/
|
||||
Blockly.ConnectionDB.prototype.getNeighbours = function(connection, maxRadius) {
|
||||
var db = this.connections_;
|
||||
var currentX = connection.x;
|
||||
var currentY = connection.y;
|
||||
ConnectionDB.prototype.getNeighbours = function(connection, maxRadius) {
|
||||
const db = this.connections_;
|
||||
const currentX = connection.x;
|
||||
const currentY = connection.y;
|
||||
|
||||
// Binary search to find the closest y location.
|
||||
var pointerMin = 0;
|
||||
var pointerMax = db.length - 2;
|
||||
var pointerMid = pointerMax;
|
||||
let pointerMin = 0;
|
||||
let pointerMax = db.length - 2;
|
||||
let pointerMid = pointerMax;
|
||||
while (pointerMin < pointerMid) {
|
||||
if (db[pointerMid].y < currentY) {
|
||||
pointerMin = pointerMid;
|
||||
@@ -170,7 +173,7 @@ Blockly.ConnectionDB.prototype.getNeighbours = function(connection, maxRadius) {
|
||||
pointerMid = Math.floor((pointerMin + pointerMax) / 2);
|
||||
}
|
||||
|
||||
var neighbours = [];
|
||||
const neighbours = [];
|
||||
/**
|
||||
* Computes if the current connection is within the allowed radius of another
|
||||
* connection.
|
||||
@@ -180,9 +183,9 @@ Blockly.ConnectionDB.prototype.getNeighbours = function(connection, maxRadius) {
|
||||
* the other connection is less than the allowed radius.
|
||||
*/
|
||||
function checkConnection_(yIndex) {
|
||||
var dx = currentX - db[yIndex].x;
|
||||
var dy = currentY - db[yIndex].y;
|
||||
var r = Math.sqrt(dx * dx + dy * dy);
|
||||
const dx = currentX - db[yIndex].x;
|
||||
const dy = currentY - db[yIndex].y;
|
||||
const r = Math.sqrt(dx * dx + dy * dy);
|
||||
if (r <= maxRadius) {
|
||||
neighbours.push(db[yIndex]);
|
||||
}
|
||||
@@ -213,32 +216,31 @@ Blockly.ConnectionDB.prototype.getNeighbours = function(connection, maxRadius) {
|
||||
* @return {boolean} True if connection is in range.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ConnectionDB.prototype.isInYRange_ = function(index, baseY, maxRadius) {
|
||||
ConnectionDB.prototype.isInYRange_ = function(index, baseY, maxRadius) {
|
||||
return (Math.abs(this.connections_[index].y - baseY) <= maxRadius);
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the closest compatible connection to this connection.
|
||||
* @param {!Blockly.RenderedConnection} conn The connection searching for a compatible
|
||||
* @param {!RenderedConnection} conn The connection searching for a compatible
|
||||
* mate.
|
||||
* @param {number} maxRadius The maximum radius to another connection.
|
||||
* @param {!Blockly.utils.Coordinate} dxy Offset between this connection's
|
||||
* @param {!Coordinate} dxy Offset between this connection's
|
||||
* location in the database and the current location (as a result of
|
||||
* dragging).
|
||||
* @return {!{connection: Blockly.RenderedConnection, radius: number}}
|
||||
* @return {!{connection: RenderedConnection, radius: number}}
|
||||
* Contains two properties: 'connection' which is either another
|
||||
* connection or null, and 'radius' which is the distance.
|
||||
*/
|
||||
Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius,
|
||||
dxy) {
|
||||
ConnectionDB.prototype.searchForClosest = function(conn, maxRadius, dxy) {
|
||||
if (!this.connections_.length) {
|
||||
// Don't bother.
|
||||
return {connection: null, radius: maxRadius};
|
||||
}
|
||||
|
||||
// Stash the values of x and y from before the drag.
|
||||
var baseY = conn.y;
|
||||
var baseX = conn.x;
|
||||
const baseY = conn.y;
|
||||
const baseX = conn.x;
|
||||
|
||||
conn.x = baseX + dxy.x;
|
||||
conn.y = baseY + dxy.y;
|
||||
@@ -246,14 +248,14 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius,
|
||||
// calculateIndexForYPos_ finds an index for insertion, which is always
|
||||
// after any block with the same y index. We want to search both forward
|
||||
// and back, so search on both sides of the index.
|
||||
var closestIndex = this.calculateIndexForYPos_(conn.y);
|
||||
const closestIndex = this.calculateIndexForYPos_(conn.y);
|
||||
|
||||
var bestConnection = null;
|
||||
var bestRadius = maxRadius;
|
||||
var temp;
|
||||
let bestConnection = null;
|
||||
let bestRadius = maxRadius;
|
||||
let temp;
|
||||
|
||||
// Walk forward and back on the y axis looking for the closest x,y point.
|
||||
var pointerMin = closestIndex - 1;
|
||||
let pointerMin = closestIndex - 1;
|
||||
while (pointerMin >= 0 && this.isInYRange_(pointerMin, conn.y, maxRadius)) {
|
||||
temp = this.connections_[pointerMin];
|
||||
if (this.connectionChecker_.canConnect(conn, temp, true, bestRadius)) {
|
||||
@@ -263,9 +265,9 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius,
|
||||
pointerMin--;
|
||||
}
|
||||
|
||||
var pointerMax = closestIndex;
|
||||
let pointerMax = closestIndex;
|
||||
while (pointerMax < this.connections_.length &&
|
||||
this.isInYRange_(pointerMax, conn.y, maxRadius)) {
|
||||
this.isInYRange_(pointerMax, conn.y, maxRadius)) {
|
||||
temp = this.connections_[pointerMax];
|
||||
if (this.connectionChecker_.canConnect(conn, temp, true, bestRadius)) {
|
||||
bestConnection = temp;
|
||||
@@ -284,20 +286,19 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius,
|
||||
|
||||
/**
|
||||
* Initialize a set of connection DBs for a workspace.
|
||||
* @param {!Blockly.IConnectionChecker} checker The workspace's
|
||||
* connection checker, used to decide if connections are valid during a drag.
|
||||
* @return {!Array<!Blockly.ConnectionDB>} Array of databases.
|
||||
* @param {!IConnectionChecker} checker The workspace's
|
||||
* connection checker, used to decide if connections are valid during a
|
||||
* drag.
|
||||
* @return {!Array<!ConnectionDB>} Array of databases.
|
||||
*/
|
||||
Blockly.ConnectionDB.init = function(checker) {
|
||||
ConnectionDB.init = function(checker) {
|
||||
// Create four databases, one for each connection type.
|
||||
var dbList = [];
|
||||
dbList[Blockly.connectionTypes.INPUT_VALUE] =
|
||||
new Blockly.ConnectionDB(checker);
|
||||
dbList[Blockly.connectionTypes.OUTPUT_VALUE] =
|
||||
new Blockly.ConnectionDB(checker);
|
||||
dbList[Blockly.connectionTypes.NEXT_STATEMENT] =
|
||||
new Blockly.ConnectionDB(checker);
|
||||
dbList[Blockly.connectionTypes.PREVIOUS_STATEMENT] =
|
||||
new Blockly.ConnectionDB(checker);
|
||||
const dbList = [];
|
||||
dbList[connectionTypes.INPUT_VALUE] = new ConnectionDB(checker);
|
||||
dbList[connectionTypes.OUTPUT_VALUE] = new ConnectionDB(checker);
|
||||
dbList[connectionTypes.NEXT_STATEMENT] = new ConnectionDB(checker);
|
||||
dbList[connectionTypes.PREVIOUS_STATEMENT] = new ConnectionDB(checker);
|
||||
return dbList;
|
||||
};
|
||||
|
||||
exports = ConnectionDB;
|
||||
|
||||
@@ -11,13 +11,14 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.connectionTypes');
|
||||
goog.module('Blockly.connectionTypes');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/**
|
||||
* Enum for the type of a connection or input.
|
||||
* @enum {number}
|
||||
*/
|
||||
Blockly.connectionTypes = {
|
||||
const connectionTypes = {
|
||||
// A right-facing value input. E.g. 'set item to' or 'return'.
|
||||
INPUT_VALUE: 1,
|
||||
// A left-facing value output. E.g. 'random fraction'.
|
||||
@@ -27,3 +28,5 @@ Blockly.connectionTypes = {
|
||||
// An up-facing block stack. E.g. 'break out of loop'.
|
||||
PREVIOUS_STATEMENT: 4
|
||||
};
|
||||
|
||||
exports = connectionTypes;
|
||||
|
||||
@@ -10,204 +10,31 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.constants');
|
||||
goog.module('Blockly.constants');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.connectionTypes');
|
||||
|
||||
|
||||
/**
|
||||
* The multiplier for scroll wheel deltas using the line delta mode.
|
||||
* @type {number}
|
||||
*/
|
||||
Blockly.LINE_MODE_MULTIPLIER = 40;
|
||||
|
||||
/**
|
||||
* The multiplier for scroll wheel deltas using the page delta mode.
|
||||
* @type {number}
|
||||
*/
|
||||
Blockly.PAGE_MODE_MULTIPLIER = 125;
|
||||
|
||||
/**
|
||||
* Number of pixels the mouse must move before a drag starts.
|
||||
*/
|
||||
Blockly.DRAG_RADIUS = 5;
|
||||
|
||||
/**
|
||||
* Number of pixels the mouse must move before a drag/scroll starts from the
|
||||
* flyout. Because the drag-intention is determined when this is reached, it is
|
||||
* larger than Blockly.DRAG_RADIUS so that the drag-direction is clearer.
|
||||
*/
|
||||
Blockly.FLYOUT_DRAG_RADIUS = 10;
|
||||
|
||||
/**
|
||||
* Maximum misalignment between connections for them to snap together.
|
||||
*/
|
||||
Blockly.SNAP_RADIUS = 28;
|
||||
|
||||
/**
|
||||
* Maximum misalignment between connections for them to snap together,
|
||||
* when a connection is already highlighted.
|
||||
*/
|
||||
Blockly.CONNECTING_SNAP_RADIUS = Blockly.SNAP_RADIUS;
|
||||
|
||||
/**
|
||||
* How much to prefer staying connected to the current connection over moving to
|
||||
* a new connection. The current previewed connection is considered to be this
|
||||
* much closer to the matching connection on the block than it actually is.
|
||||
*/
|
||||
Blockly.CURRENT_CONNECTION_PREFERENCE = 8;
|
||||
|
||||
/**
|
||||
* Delay in ms between trigger and bumping unconnected block out of alignment.
|
||||
*/
|
||||
Blockly.BUMP_DELAY = 250;
|
||||
|
||||
/**
|
||||
* Maximum randomness in workspace units for bumping a block.
|
||||
*/
|
||||
Blockly.BUMP_RANDOMNESS = 10;
|
||||
|
||||
/**
|
||||
* Number of characters to truncate a collapsed block to.
|
||||
*/
|
||||
Blockly.COLLAPSE_CHARS = 30;
|
||||
|
||||
/**
|
||||
* Length in ms for a touch to become a long press.
|
||||
*/
|
||||
Blockly.LONGPRESS = 750;
|
||||
|
||||
/**
|
||||
* Prevent a sound from playing if another sound preceded it within this many
|
||||
* milliseconds.
|
||||
*/
|
||||
Blockly.SOUND_LIMIT = 100;
|
||||
|
||||
/**
|
||||
* When dragging a block out of a stack, split the stack in two (true), or drag
|
||||
* out the block healing the stack (false).
|
||||
*/
|
||||
Blockly.DRAG_STACK = true;
|
||||
|
||||
/**
|
||||
* The richness of block colours, regardless of the hue.
|
||||
* Must be in the range of 0 (inclusive) to 1 (exclusive).
|
||||
*/
|
||||
Blockly.HSV_SATURATION = 0.45;
|
||||
|
||||
/**
|
||||
* The intensity of block colours, regardless of the hue.
|
||||
* Must be in the range of 0 (inclusive) to 1 (exclusive).
|
||||
*/
|
||||
Blockly.HSV_VALUE = 0.65;
|
||||
|
||||
/**
|
||||
* Sprited icons and images.
|
||||
*/
|
||||
Blockly.SPRITE = {
|
||||
width: 96,
|
||||
height: 124,
|
||||
url: 'sprites.png'
|
||||
};
|
||||
|
||||
// Constants below this point are not intended to be changed.
|
||||
|
||||
/**
|
||||
* Enum for alignment of inputs.
|
||||
* @enum {number}
|
||||
*/
|
||||
Blockly.constants.ALIGN = {
|
||||
const ALIGN = {
|
||||
LEFT: -1,
|
||||
CENTRE: 0,
|
||||
RIGHT: 1
|
||||
};
|
||||
|
||||
/**
|
||||
* ENUM for no drag operation.
|
||||
* @const
|
||||
*/
|
||||
Blockly.DRAG_NONE = 0;
|
||||
|
||||
/**
|
||||
* ENUM for inside the sticky DRAG_RADIUS.
|
||||
* @const
|
||||
*/
|
||||
Blockly.DRAG_STICKY = 1;
|
||||
|
||||
/**
|
||||
* ENUM for inside the non-sticky DRAG_RADIUS, for differentiating between
|
||||
* clicks and drags.
|
||||
* @const
|
||||
*/
|
||||
Blockly.DRAG_BEGIN = 1;
|
||||
|
||||
/**
|
||||
* ENUM for freely draggable (outside the DRAG_RADIUS, if one applies).
|
||||
* @const
|
||||
*/
|
||||
Blockly.DRAG_FREE = 2;
|
||||
|
||||
/**
|
||||
* Lookup table for determining the opposite type of a connection.
|
||||
* @const
|
||||
*/
|
||||
Blockly.OPPOSITE_TYPE = [];
|
||||
Blockly.OPPOSITE_TYPE[Blockly.connectionTypes.INPUT_VALUE] =
|
||||
Blockly.connectionTypes.OUTPUT_VALUE;
|
||||
Blockly.OPPOSITE_TYPE[Blockly.connectionTypes.OUTPUT_VALUE] =
|
||||
Blockly.connectionTypes.INPUT_VALUE;
|
||||
Blockly.OPPOSITE_TYPE[Blockly.connectionTypes.NEXT_STATEMENT] =
|
||||
Blockly.connectionTypes.PREVIOUS_STATEMENT;
|
||||
Blockly.OPPOSITE_TYPE[Blockly.connectionTypes.PREVIOUS_STATEMENT] =
|
||||
Blockly.connectionTypes.NEXT_STATEMENT;
|
||||
|
||||
/**
|
||||
* String for use in the "custom" attribute of a category in toolbox XML.
|
||||
* This string indicates that the category should be dynamically populated with
|
||||
* variable blocks.
|
||||
* @const {string}
|
||||
*/
|
||||
Blockly.VARIABLE_CATEGORY_NAME = 'VARIABLE';
|
||||
/**
|
||||
* String for use in the "custom" attribute of a category in toolbox XML.
|
||||
* This string indicates that the category should be dynamically populated with
|
||||
* variable blocks.
|
||||
* @const {string}
|
||||
*/
|
||||
Blockly.VARIABLE_DYNAMIC_CATEGORY_NAME = 'VARIABLE_DYNAMIC';
|
||||
|
||||
/**
|
||||
* String for use in the "custom" attribute of a category in toolbox XML.
|
||||
* This string indicates that the category should be dynamically populated with
|
||||
* procedure blocks.
|
||||
* @const {string}
|
||||
*/
|
||||
Blockly.PROCEDURE_CATEGORY_NAME = 'PROCEDURE';
|
||||
|
||||
/**
|
||||
* String for use in the dropdown created in field_variable.
|
||||
* This string indicates that this option in the dropdown is 'Rename
|
||||
* variable...' and if selected, should trigger the prompt to rename a variable.
|
||||
* @const {string}
|
||||
*/
|
||||
Blockly.RENAME_VARIABLE_ID = 'RENAME_VARIABLE_ID';
|
||||
|
||||
/**
|
||||
* String for use in the dropdown created in field_variable.
|
||||
* This string indicates that this option in the dropdown is 'Delete the "%1"
|
||||
* variable' and if selected, should trigger the prompt to delete a variable.
|
||||
* @const {string}
|
||||
*/
|
||||
Blockly.DELETE_VARIABLE_ID = 'DELETE_VARIABLE_ID';
|
||||
exports.ALIGN = ALIGN;
|
||||
|
||||
/**
|
||||
* The language-neutral ID given to the collapsed input.
|
||||
* @const {string}
|
||||
*/
|
||||
Blockly.constants.COLLAPSED_INPUT_NAME = '_TEMP_COLLAPSED_INPUT';
|
||||
const COLLAPSED_INPUT_NAME = '_TEMP_COLLAPSED_INPUT';
|
||||
exports.COLLAPSED_INPUT_NAME = COLLAPSED_INPUT_NAME;
|
||||
|
||||
/**
|
||||
* The language-neutral ID given to the collapsed field.
|
||||
* @const {string}
|
||||
*/
|
||||
Blockly.constants.COLLAPSED_FIELD_NAME = '_TEMP_COLLAPSED_FIELD';
|
||||
const COLLAPSED_FIELD_NAME = '_TEMP_COLLAPSED_FIELD';
|
||||
exports.COLLAPSED_FIELD_NAME = COLLAPSED_FIELD_NAME;
|
||||
|
||||
@@ -17,11 +17,10 @@
|
||||
goog.provide('Blockly.ContextMenu');
|
||||
|
||||
goog.require('Blockly.browserEvents');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.Events');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockCreate');
|
||||
goog.require('Blockly.internalConstants');
|
||||
goog.require('Blockly.Menu');
|
||||
goog.require('Blockly.MenuItem');
|
||||
goog.require('Blockly.Msg');
|
||||
@@ -195,11 +194,11 @@ Blockly.ContextMenu.callbackFactory = function(block, xml) {
|
||||
// Move the new block next to the old block.
|
||||
var xy = block.getRelativeToSurfaceXY();
|
||||
if (block.RTL) {
|
||||
xy.x -= Blockly.SNAP_RADIUS;
|
||||
xy.x -= Blockly.internalConstants.SNAP_RADIUS;
|
||||
} else {
|
||||
xy.x += Blockly.SNAP_RADIUS;
|
||||
xy.x += Blockly.internalConstants.SNAP_RADIUS;
|
||||
}
|
||||
xy.y += Blockly.SNAP_RADIUS * 2;
|
||||
xy.y += Blockly.internalConstants.SNAP_RADIUS * 2;
|
||||
newBlock.moveBy(xy.x, xy.y);
|
||||
} finally {
|
||||
Blockly.Events.enable();
|
||||
|
||||
800
core/css.js
800
core/css.js
@@ -14,7 +14,8 @@
|
||||
* @name Blockly.Css
|
||||
* @namespace
|
||||
*/
|
||||
goog.provide('Blockly.Css');
|
||||
goog.module('Blockly.Css');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
|
||||
/**
|
||||
@@ -22,7 +23,7 @@ goog.provide('Blockly.Css');
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
Blockly.Css.injected_ = false;
|
||||
let injected = false;
|
||||
|
||||
/**
|
||||
* Add some CSS to the blob that will be injected later. Allows optional
|
||||
@@ -30,14 +31,15 @@ Blockly.Css.injected_ = false;
|
||||
* The provided array of CSS will be destroyed by this function.
|
||||
* @param {!Array<string>} cssArray Array of CSS strings.
|
||||
*/
|
||||
Blockly.Css.register = function(cssArray) {
|
||||
if (Blockly.Css.injected_) {
|
||||
const register = function(cssArray) {
|
||||
if (injected) {
|
||||
throw Error('CSS already injected');
|
||||
}
|
||||
// Concatenate cssArray onto Blockly.Css.CONTENT.
|
||||
Array.prototype.push.apply(Blockly.Css.CONTENT, cssArray);
|
||||
// Concatenate cssArray onto CONTENT.
|
||||
Array.prototype.push.apply(CONTENT, cssArray);
|
||||
cssArray.length = 0; // Garbage collect provided CSS content.
|
||||
};
|
||||
exports.register = register;
|
||||
|
||||
/**
|
||||
* Inject the CSS into the DOM. This is preferable over using a regular CSS
|
||||
@@ -49,504 +51,508 @@ Blockly.Css.register = function(cssArray) {
|
||||
* (providing CSS becomes the document's responsibility).
|
||||
* @param {string} pathToMedia Path from page to the Blockly media directory.
|
||||
*/
|
||||
Blockly.Css.inject = function(hasCss, pathToMedia) {
|
||||
const inject = function(hasCss, pathToMedia) {
|
||||
// Only inject the CSS once.
|
||||
if (Blockly.Css.injected_) {
|
||||
if (injected) {
|
||||
return;
|
||||
}
|
||||
Blockly.Css.injected_ = true;
|
||||
var text = Blockly.Css.CONTENT.join('\n');
|
||||
Blockly.Css.CONTENT.length = 0; // Garbage collect CSS content.
|
||||
injected = true;
|
||||
let text = CONTENT.join('\n');
|
||||
CONTENT.length = 0; // Garbage collect CSS content.
|
||||
if (!hasCss) {
|
||||
return;
|
||||
}
|
||||
// Strip off any trailing slash (either Unix or Windows).
|
||||
var mediaPath = pathToMedia.replace(/[\\/]$/, '');
|
||||
const mediaPath = pathToMedia.replace(/[\\/]$/, '');
|
||||
text = text.replace(/<<<PATH>>>/g, mediaPath);
|
||||
|
||||
// Inject CSS tag at start of head.
|
||||
var cssNode = document.createElement('style');
|
||||
const cssNode = document.createElement('style');
|
||||
cssNode.id = 'blockly-common-style';
|
||||
var cssTextNode = document.createTextNode(text);
|
||||
const cssTextNode = document.createTextNode(text);
|
||||
cssNode.appendChild(cssTextNode);
|
||||
document.head.insertBefore(cssNode, document.head.firstChild);
|
||||
};
|
||||
exports.inject = inject;
|
||||
|
||||
/**
|
||||
* Array making up the CSS content for Blockly.
|
||||
*/
|
||||
Blockly.Css.CONTENT = [
|
||||
/* eslint-disable indent */
|
||||
'.blocklySvg {',
|
||||
'background-color: #fff;',
|
||||
'outline: none;',
|
||||
'overflow: hidden;', /* IE overflows by default. */
|
||||
'position: absolute;',
|
||||
'display: block;',
|
||||
'}',
|
||||
const CONTENT = [
|
||||
`.blocklySvg {
|
||||
background-color: #fff;
|
||||
outline: none;
|
||||
overflow: hidden; /* IE overflows by default. */
|
||||
position: absolute;
|
||||
display: block;
|
||||
}`,
|
||||
|
||||
'.blocklyWidgetDiv {',
|
||||
'display: none;',
|
||||
'position: absolute;',
|
||||
'z-index: 99999;', /* big value for bootstrap3 compatibility */
|
||||
'}',
|
||||
`.blocklyWidgetDiv {
|
||||
display: none;
|
||||
position: absolute;
|
||||
z-index: 99999; /* big value for bootstrap3 compatibility */
|
||||
}`,
|
||||
|
||||
'.injectionDiv {',
|
||||
'height: 100%;',
|
||||
'position: relative;',
|
||||
'overflow: hidden;', /* So blocks in drag surface disappear at edges */
|
||||
'touch-action: none;',
|
||||
'}',
|
||||
`.injectionDiv {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: hidden; /* So blocks in drag surface disappear at edges */
|
||||
touch-action: none;
|
||||
}`,
|
||||
|
||||
'.blocklyNonSelectable {',
|
||||
'user-select: none;',
|
||||
'-ms-user-select: none;',
|
||||
'-webkit-user-select: none;',
|
||||
'}',
|
||||
`.blocklyNonSelectable {
|
||||
user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}`,
|
||||
|
||||
`.blocklyWsDragSurface {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}`,
|
||||
|
||||
'.blocklyWsDragSurface {',
|
||||
'display: none;',
|
||||
'position: absolute;',
|
||||
'top: 0;',
|
||||
'left: 0;',
|
||||
'}',
|
||||
/* Added as a separate rule with multiple classes to make it more specific
|
||||
than a bootstrap rule that selects svg:root. See issue #1275 for context.
|
||||
*/
|
||||
'.blocklyWsDragSurface.blocklyOverflowVisible {',
|
||||
'overflow: visible;',
|
||||
'}',
|
||||
`.blocklyWsDragSurface.blocklyOverflowVisible {
|
||||
overflow: visible;
|
||||
}`,
|
||||
|
||||
'.blocklyBlockDragSurface {',
|
||||
'display: none;',
|
||||
'position: absolute;',
|
||||
'top: 0;',
|
||||
'left: 0;',
|
||||
'right: 0;',
|
||||
'bottom: 0;',
|
||||
'overflow: visible !important;',
|
||||
'z-index: 50;', /* Display below toolbox, but above everything else. */
|
||||
'}',
|
||||
`.blocklyBlockDragSurface {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow: visible !important;
|
||||
z-index: 50;', /* Display below toolbox, but above everything else. */
|
||||
}`,
|
||||
|
||||
'.blocklyBlockCanvas.blocklyCanvasTransitioning,',
|
||||
'.blocklyBubbleCanvas.blocklyCanvasTransitioning {',
|
||||
'transition: transform .5s;',
|
||||
'}',
|
||||
`.blocklyBlockCanvas.blocklyCanvasTransitioning,
|
||||
.blocklyBubbleCanvas.blocklyCanvasTransitioning {
|
||||
transition: transform .5s;
|
||||
}`,
|
||||
|
||||
'.blocklyTooltipDiv {',
|
||||
'background-color: #ffffc7;',
|
||||
'border: 1px solid #ddc;',
|
||||
'box-shadow: 4px 4px 20px 1px rgba(0,0,0,.15);',
|
||||
'color: #000;',
|
||||
'display: none;',
|
||||
'font: 9pt sans-serif;',
|
||||
'opacity: .9;',
|
||||
'padding: 2px;',
|
||||
'position: absolute;',
|
||||
'z-index: 100000;', /* big value for bootstrap3 compatibility */
|
||||
'}',
|
||||
`.blocklyTooltipDiv {
|
||||
background-color: #ffffc7;
|
||||
border: 1px solid #ddc;
|
||||
box-shadow: 4px 4px 20px 1px rgba(0,0,0,.15);
|
||||
color: #000;
|
||||
display: none;
|
||||
font: 9pt sans-serif;
|
||||
opacity: .9;
|
||||
padding: 2px;
|
||||
position: absolute;
|
||||
z-index: 100000;', /* big value for bootstrap3 compatibility */
|
||||
}`,
|
||||
|
||||
'.blocklyDropDownDiv {',
|
||||
'position: absolute;',
|
||||
'left: 0;',
|
||||
'top: 0;',
|
||||
'z-index: 1000;',
|
||||
'display: none;',
|
||||
'border: 1px solid;',
|
||||
'border-color: #dadce0;',
|
||||
'background-color: #fff;',
|
||||
'border-radius: 2px;',
|
||||
'padding: 4px;',
|
||||
'box-shadow: 0 0 3px 1px rgba(0,0,0,.3);',
|
||||
'}',
|
||||
`.blocklyDropDownDiv {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
border: 1px solid;
|
||||
border-color: #dadce0;
|
||||
background-color: #fff;
|
||||
border-radius: 2px;
|
||||
padding: 4px;
|
||||
box-shadow: 0 0 3px 1px rgba(0,0,0,.3);
|
||||
}`,
|
||||
|
||||
'.blocklyDropDownDiv.blocklyFocused {',
|
||||
'box-shadow: 0 0 6px 1px rgba(0,0,0,.3);',
|
||||
'}',
|
||||
`.blocklyDropDownDiv.blocklyFocused {
|
||||
box-shadow: 0 0 6px 1px rgba(0,0,0,.3);
|
||||
}`,
|
||||
|
||||
'.blocklyDropDownContent {',
|
||||
'max-height: 300px;', // @todo: spec for maximum height.
|
||||
'overflow: auto;',
|
||||
'overflow-x: hidden;',
|
||||
'position: relative;',
|
||||
'}',
|
||||
`.blocklyDropDownContent {
|
||||
max-height: 300px;', // @todo: spec for maximum height.
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
position: relative;
|
||||
}`,
|
||||
|
||||
'.blocklyDropDownArrow {',
|
||||
'position: absolute;',
|
||||
'left: 0;',
|
||||
'top: 0;',
|
||||
'width: 16px;',
|
||||
'height: 16px;',
|
||||
'z-index: -1;',
|
||||
'background-color: inherit;',
|
||||
'border-color: inherit;',
|
||||
'}',
|
||||
`.blocklyDropDownArrow {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
z-index: -1;
|
||||
background-color: inherit;
|
||||
border-color: inherit;
|
||||
}`,
|
||||
|
||||
'.blocklyDropDownButton {',
|
||||
'display: inline-block;',
|
||||
'float: left;',
|
||||
'padding: 0;',
|
||||
'margin: 4px;',
|
||||
'border-radius: 4px;',
|
||||
'outline: none;',
|
||||
'border: 1px solid;',
|
||||
'transition: box-shadow .1s;',
|
||||
'cursor: pointer;',
|
||||
'}',
|
||||
`.blocklyDropDownButton {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
padding: 0;
|
||||
margin: 4px;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
border: 1px solid;
|
||||
transition: box-shadow .1s;
|
||||
cursor: pointer;
|
||||
}`,
|
||||
|
||||
'.blocklyArrowTop {',
|
||||
'border-top: 1px solid;',
|
||||
'border-left: 1px solid;',
|
||||
'border-top-left-radius: 4px;',
|
||||
'border-color: inherit;',
|
||||
'}',
|
||||
`.blocklyArrowTop {
|
||||
border-top: 1px solid;
|
||||
border-left: 1px solid;
|
||||
border-top-left-radius: 4px;
|
||||
border-color: inherit;
|
||||
}`,
|
||||
|
||||
'.blocklyArrowBottom {',
|
||||
'border-bottom: 1px solid;',
|
||||
'border-right: 1px solid;',
|
||||
'border-bottom-right-radius: 4px;',
|
||||
'border-color: inherit;',
|
||||
'}',
|
||||
`.blocklyArrowBottom {
|
||||
border-bottom: 1px solid;
|
||||
border-right: 1px solid;
|
||||
border-bottom-right-radius: 4px;
|
||||
border-color: inherit;
|
||||
}`,
|
||||
|
||||
'.blocklyResizeSE {',
|
||||
'cursor: se-resize;',
|
||||
'fill: #aaa;',
|
||||
'}',
|
||||
`.blocklyResizeSE {
|
||||
cursor: se-resize;
|
||||
fill: #aaa;
|
||||
}`,
|
||||
|
||||
'.blocklyResizeSW {',
|
||||
'cursor: sw-resize;',
|
||||
'fill: #aaa;',
|
||||
'}',
|
||||
`.blocklyResizeSW {
|
||||
cursor: sw-resize;
|
||||
fill: #aaa;
|
||||
}`,
|
||||
|
||||
'.blocklyResizeLine {',
|
||||
'stroke: #515A5A;',
|
||||
'stroke-width: 1;',
|
||||
'}',
|
||||
`.blocklyResizeLine {
|
||||
stroke: #515A5A;
|
||||
stroke-width: 1;
|
||||
}`,
|
||||
|
||||
'.blocklyHighlightedConnectionPath {',
|
||||
'fill: none;',
|
||||
'stroke: #fc3;',
|
||||
'stroke-width: 4px;',
|
||||
'}',
|
||||
`.blocklyHighlightedConnectionPath {
|
||||
fill: none;
|
||||
stroke: #fc3;
|
||||
stroke-width: 4px;
|
||||
}`,
|
||||
|
||||
'.blocklyPathLight {',
|
||||
'fill: none;',
|
||||
'stroke-linecap: round;',
|
||||
'stroke-width: 1;',
|
||||
'}',
|
||||
`.blocklyPathLight {
|
||||
fill: none;
|
||||
stroke-linecap: round;
|
||||
stroke-width: 1;
|
||||
}`,
|
||||
|
||||
'.blocklySelected>.blocklyPathLight {',
|
||||
'display: none;',
|
||||
'}',
|
||||
`.blocklySelected>.blocklyPathLight {
|
||||
display: none;
|
||||
}`,
|
||||
|
||||
'.blocklyDraggable {',
|
||||
/* backup for browsers (e.g. IE11) that don't support grab */
|
||||
'cursor: url("<<<PATH>>>/handopen.cur"), auto;',
|
||||
'cursor: grab;',
|
||||
'cursor: -webkit-grab;',
|
||||
'}',
|
||||
`.blocklyDraggable {
|
||||
/* backup for browsers (e.g. IE11) that don't support grab */
|
||||
cursor: url("<<<PATH>>>/handopen.cur"), auto;
|
||||
cursor: grab;
|
||||
cursor: -webkit-grab;
|
||||
}`,
|
||||
|
||||
/* backup for browsers (e.g. IE11) that don't support grabbing */
|
||||
`.blocklyDragging {
|
||||
/* backup for browsers (e.g. IE11) that don't support grabbing */
|
||||
cursor: url("<<<PATH>>>/handclosed.cur"), auto;
|
||||
cursor: grabbing;
|
||||
cursor: -webkit-grabbing;
|
||||
}`,
|
||||
|
||||
'.blocklyDragging {',
|
||||
/* backup for browsers (e.g. IE11) that don't support grabbing */
|
||||
'cursor: url("<<<PATH>>>/handclosed.cur"), auto;',
|
||||
'cursor: grabbing;',
|
||||
'cursor: -webkit-grabbing;',
|
||||
'}',
|
||||
/* Changes cursor on mouse down. Not effective in Firefox because of
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=771241 */
|
||||
'.blocklyDraggable:active {',
|
||||
/* backup for browsers (e.g. IE11) that don't support grabbing */
|
||||
'cursor: url("<<<PATH>>>/handclosed.cur"), auto;',
|
||||
'cursor: grabbing;',
|
||||
'cursor: -webkit-grabbing;',
|
||||
'}',
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=771241 */
|
||||
`.blocklyDraggable:active {
|
||||
/* backup for browsers (e.g. IE11) that don't support grabbing */
|
||||
cursor: url("<<<PATH>>>/handclosed.cur"), auto;
|
||||
cursor: grabbing;
|
||||
cursor: -webkit-grabbing;
|
||||
}`,
|
||||
|
||||
/* Change the cursor on the whole drag surface in case the mouse gets
|
||||
ahead of block during a drag. This way the cursor is still a closed hand.
|
||||
*/
|
||||
'.blocklyBlockDragSurface .blocklyDraggable {',
|
||||
/* backup for browsers (e.g. IE11) that don't support grabbing */
|
||||
'cursor: url("<<<PATH>>>/handclosed.cur"), auto;',
|
||||
'cursor: grabbing;',
|
||||
'cursor: -webkit-grabbing;',
|
||||
'}',
|
||||
`.blocklyBlockDragSurface .blocklyDraggable {
|
||||
/* backup for browsers (e.g. IE11) that don't support grabbing */
|
||||
cursor: url("<<<PATH>>>/handclosed.cur"), auto;
|
||||
cursor: grabbing;
|
||||
cursor: -webkit-grabbing;
|
||||
}`,
|
||||
|
||||
'.blocklyDragging.blocklyDraggingDelete {',
|
||||
'cursor: url("<<<PATH>>>/handdelete.cur"), auto;',
|
||||
'}',
|
||||
`.blocklyDragging.blocklyDraggingDelete {
|
||||
cursor: url("<<<PATH>>>/handdelete.cur"), auto;
|
||||
}`,
|
||||
|
||||
'.blocklyDragging>.blocklyPath,',
|
||||
'.blocklyDragging>.blocklyPathLight {',
|
||||
'fill-opacity: .8;',
|
||||
'stroke-opacity: .8;',
|
||||
'}',
|
||||
`.blocklyDragging>.blocklyPath,
|
||||
.blocklyDragging>.blocklyPathLight {
|
||||
fill-opacity: .8;
|
||||
stroke-opacity: .8;
|
||||
}`,
|
||||
|
||||
'.blocklyDragging>.blocklyPathDark {',
|
||||
'display: none;',
|
||||
'}',
|
||||
`.blocklyDragging>.blocklyPathDark {
|
||||
display: none;
|
||||
}`,
|
||||
|
||||
'.blocklyDisabled>.blocklyPath {',
|
||||
'fill-opacity: .5;',
|
||||
'stroke-opacity: .5;',
|
||||
'}',
|
||||
`.blocklyDisabled>.blocklyPath {
|
||||
fill-opacity: .5;
|
||||
stroke-opacity: .5;
|
||||
}`,
|
||||
|
||||
'.blocklyDisabled>.blocklyPathLight,',
|
||||
'.blocklyDisabled>.blocklyPathDark {',
|
||||
'display: none;',
|
||||
'}',
|
||||
`.blocklyDisabled>.blocklyPathLight,
|
||||
.blocklyDisabled>.blocklyPathDark {
|
||||
display: none;
|
||||
}`,
|
||||
|
||||
'.blocklyInsertionMarker>.blocklyPath,',
|
||||
'.blocklyInsertionMarker>.blocklyPathLight,',
|
||||
'.blocklyInsertionMarker>.blocklyPathDark {',
|
||||
'fill-opacity: .2;',
|
||||
'stroke: none;',
|
||||
'}',
|
||||
`.blocklyInsertionMarker>.blocklyPath,
|
||||
.blocklyInsertionMarker>.blocklyPathLight,
|
||||
.blocklyInsertionMarker>.blocklyPathDark {
|
||||
fill-opacity: .2;
|
||||
stroke: none;
|
||||
}`,
|
||||
|
||||
'.blocklyMultilineText {',
|
||||
'font-family: monospace;',
|
||||
'}',
|
||||
`.blocklyMultilineText {
|
||||
font-family: monospace;
|
||||
}`,
|
||||
|
||||
'.blocklyNonEditableText>text {',
|
||||
'pointer-events: none;',
|
||||
'}',
|
||||
`.blocklyNonEditableText>text {
|
||||
pointer-events: none;
|
||||
}`,
|
||||
|
||||
'.blocklyFlyout {',
|
||||
'position: absolute;',
|
||||
'z-index: 20;',
|
||||
'}',
|
||||
`.blocklyFlyout {
|
||||
position: absolute;
|
||||
z-index: 20;
|
||||
}`,
|
||||
|
||||
'.blocklyText text {',
|
||||
'cursor: default;',
|
||||
'}',
|
||||
`.blocklyText text {
|
||||
cursor: default;
|
||||
}`,
|
||||
|
||||
/*
|
||||
Don't allow users to select text. It gets annoying when trying to
|
||||
drag a block and selected text moves instead.
|
||||
*/
|
||||
'.blocklySvg text,',
|
||||
'.blocklyBlockDragSurface text {',
|
||||
'user-select: none;',
|
||||
'-ms-user-select: none;',
|
||||
'-webkit-user-select: none;',
|
||||
'cursor: inherit;',
|
||||
'}',
|
||||
`.blocklySvg text,
|
||||
.blocklyBlockDragSurface text {
|
||||
user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
cursor: inherit;
|
||||
}`,
|
||||
|
||||
'.blocklyHidden {',
|
||||
'display: none;',
|
||||
'}',
|
||||
`.blocklyHidden {
|
||||
display: none;
|
||||
}`,
|
||||
|
||||
'.blocklyFieldDropdown:not(.blocklyHidden) {',
|
||||
'display: block;',
|
||||
'}',
|
||||
`.blocklyFieldDropdown:not(.blocklyHidden) {
|
||||
display: block;
|
||||
}`,
|
||||
|
||||
'.blocklyIconGroup {',
|
||||
'cursor: default;',
|
||||
'}',
|
||||
`.blocklyIconGroup {
|
||||
cursor: default;
|
||||
}`,
|
||||
|
||||
'.blocklyIconGroup:not(:hover),',
|
||||
'.blocklyIconGroupReadonly {',
|
||||
'opacity: .6;',
|
||||
'}',
|
||||
`.blocklyIconGroup:not(:hover),
|
||||
.blocklyIconGroupReadonly {
|
||||
opacity: .6;
|
||||
}`,
|
||||
|
||||
'.blocklyIconShape {',
|
||||
'fill: #00f;',
|
||||
'stroke: #fff;',
|
||||
'stroke-width: 1px;',
|
||||
'}',
|
||||
`.blocklyIconShape {
|
||||
fill: #00f;
|
||||
stroke: #fff;
|
||||
stroke-width: 1px;
|
||||
}`,
|
||||
|
||||
'.blocklyIconSymbol {',
|
||||
'fill: #fff;',
|
||||
'}',
|
||||
`.blocklyIconSymbol {
|
||||
fill: #fff;
|
||||
}`,
|
||||
|
||||
'.blocklyMinimalBody {',
|
||||
'margin: 0;',
|
||||
'padding: 0;',
|
||||
'}',
|
||||
`.blocklyMinimalBody {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}`,
|
||||
|
||||
'.blocklyHtmlInput {',
|
||||
'border: none;',
|
||||
'border-radius: 4px;',
|
||||
'height: 100%;',
|
||||
'margin: 0;',
|
||||
'outline: none;',
|
||||
'padding: 0;',
|
||||
'width: 100%;',
|
||||
'text-align: center;',
|
||||
'display: block;',
|
||||
'box-sizing: border-box;',
|
||||
'}',
|
||||
`.blocklyHtmlInput {
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
}`,
|
||||
|
||||
/* Edge and IE introduce a close icon when the input value is longer than a
|
||||
certain length. This affects our sizing calculations of the text input.
|
||||
Hiding the close icon to avoid that. */
|
||||
'.blocklyHtmlInput::-ms-clear {',
|
||||
'display: none;',
|
||||
'}',
|
||||
`.blocklyHtmlInput::-ms-clear {
|
||||
display: none;
|
||||
}`,
|
||||
|
||||
'.blocklyMainBackground {',
|
||||
'stroke-width: 1;',
|
||||
'stroke: #c6c6c6;', /* Equates to #ddd due to border being off-pixel. */
|
||||
'}',
|
||||
`.blocklyMainBackground {
|
||||
stroke-width: 1;
|
||||
stroke: #c6c6c6;', /* Equates to #ddd due to border being off-pixel. */
|
||||
}`,
|
||||
|
||||
'.blocklyMutatorBackground {',
|
||||
'fill: #fff;',
|
||||
'stroke: #ddd;',
|
||||
'stroke-width: 1;',
|
||||
'}',
|
||||
`.blocklyMutatorBackground {
|
||||
fill: #fff;
|
||||
stroke: #ddd;
|
||||
stroke-width: 1;
|
||||
}`,
|
||||
|
||||
'.blocklyFlyoutBackground {',
|
||||
'fill: #ddd;',
|
||||
'fill-opacity: .8;',
|
||||
'}',
|
||||
`.blocklyFlyoutBackground {
|
||||
fill: #ddd;
|
||||
fill-opacity: .8;
|
||||
}`,
|
||||
|
||||
'.blocklyMainWorkspaceScrollbar {',
|
||||
'z-index: 20;',
|
||||
'}',
|
||||
`.blocklyMainWorkspaceScrollbar {
|
||||
z-index: 20;
|
||||
}`,
|
||||
|
||||
'.blocklyFlyoutScrollbar {',
|
||||
'z-index: 30;',
|
||||
'}',
|
||||
`.blocklyFlyoutScrollbar {
|
||||
z-index: 30;
|
||||
}`,
|
||||
|
||||
'.blocklyScrollbarHorizontal,',
|
||||
'.blocklyScrollbarVertical {',
|
||||
'position: absolute;',
|
||||
'outline: none;',
|
||||
'}',
|
||||
`.blocklyScrollbarHorizontal,
|
||||
.blocklyScrollbarVertical {
|
||||
position: absolute;
|
||||
outline: none;
|
||||
}`,
|
||||
|
||||
'.blocklyScrollbarBackground {',
|
||||
'opacity: 0;',
|
||||
'}',
|
||||
`.blocklyScrollbarBackground {
|
||||
opacity: 0;
|
||||
}`,
|
||||
|
||||
'.blocklyScrollbarHandle {',
|
||||
'fill: #ccc;',
|
||||
'}',
|
||||
`.blocklyScrollbarHandle {
|
||||
fill: #ccc;
|
||||
}`,
|
||||
|
||||
'.blocklyScrollbarBackground:hover+.blocklyScrollbarHandle,',
|
||||
'.blocklyScrollbarHandle:hover {',
|
||||
'fill: #bbb;',
|
||||
'}',
|
||||
`.blocklyScrollbarBackground:hover+.blocklyScrollbarHandle,
|
||||
.blocklyScrollbarHandle:hover {
|
||||
fill: #bbb;
|
||||
}`,
|
||||
|
||||
/* Darken flyout scrollbars due to being on a grey background. */
|
||||
/* By contrast, workspace scrollbars are on a white background. */
|
||||
'.blocklyFlyout .blocklyScrollbarHandle {',
|
||||
'fill: #bbb;',
|
||||
'}',
|
||||
`.blocklyFlyout .blocklyScrollbarHandle {
|
||||
fill: #bbb;
|
||||
}`,
|
||||
|
||||
'.blocklyFlyout .blocklyScrollbarBackground:hover+.blocklyScrollbarHandle,',
|
||||
'.blocklyFlyout .blocklyScrollbarHandle:hover {',
|
||||
'fill: #aaa;',
|
||||
'}',
|
||||
`.blocklyFlyout .blocklyScrollbarBackground:hover+.blocklyScrollbarHandle,
|
||||
.blocklyFlyout .blocklyScrollbarHandle:hover {
|
||||
fill: #aaa;
|
||||
}`,
|
||||
|
||||
'.blocklyInvalidInput {',
|
||||
'background: #faa;',
|
||||
'}',
|
||||
`.blocklyInvalidInput {
|
||||
background: #faa;
|
||||
}`,
|
||||
|
||||
'.blocklyVerticalMarker {',
|
||||
'stroke-width: 3px;',
|
||||
'fill: rgba(255,255,255,.5);',
|
||||
'pointer-events: none;',
|
||||
'}',
|
||||
`.blocklyVerticalMarker {
|
||||
stroke-width: 3px;
|
||||
fill: rgba(255,255,255,.5);
|
||||
pointer-events: none;
|
||||
}`,
|
||||
|
||||
'.blocklyComputeCanvas {',
|
||||
'position: absolute;',
|
||||
'width: 0;',
|
||||
'height: 0;',
|
||||
'}',
|
||||
`.blocklyComputeCanvas {
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}`,
|
||||
|
||||
'.blocklyNoPointerEvents {',
|
||||
'pointer-events: none;',
|
||||
'}',
|
||||
`.blocklyNoPointerEvents {
|
||||
pointer-events: none;
|
||||
}`,
|
||||
|
||||
'.blocklyContextMenu {',
|
||||
'border-radius: 4px;',
|
||||
'max-height: 100%;',
|
||||
'}',
|
||||
`.blocklyContextMenu {
|
||||
border-radius: 4px;
|
||||
max-height: 100%;
|
||||
}`,
|
||||
|
||||
'.blocklyDropdownMenu {',
|
||||
'border-radius: 2px;',
|
||||
'padding: 0 !important;',
|
||||
'}',
|
||||
`.blocklyDropdownMenu {
|
||||
border-radius: 2px;
|
||||
padding: 0 !important;
|
||||
}`,
|
||||
|
||||
'.blocklyDropdownMenu .blocklyMenuItem {',
|
||||
/* 28px on the left for icon or checkbox. */
|
||||
'padding-left: 28px;',
|
||||
'}',
|
||||
`.blocklyDropdownMenu .blocklyMenuItem {
|
||||
/* 28px on the left for icon or checkbox. */
|
||||
padding-left: 28px;
|
||||
}`,
|
||||
|
||||
/* BiDi override for the resting state. */
|
||||
'.blocklyDropdownMenu .blocklyMenuItemRtl {',
|
||||
/* Flip left/right padding for BiDi. */
|
||||
'padding-left: 5px;',
|
||||
'padding-right: 28px;',
|
||||
'}',
|
||||
`.blocklyDropdownMenu .blocklyMenuItemRtl {
|
||||
/* Flip left/right padding for BiDi. */
|
||||
padding-left: 5px;
|
||||
padding-right: 28px;
|
||||
}`,
|
||||
|
||||
'.blocklyWidgetDiv .blocklyMenu {',
|
||||
'background: #fff;',
|
||||
'border: 1px solid transparent;',
|
||||
'box-shadow: 0 0 3px 1px rgba(0,0,0,.3);',
|
||||
'font: normal 13px Arial, sans-serif;',
|
||||
'margin: 0;',
|
||||
'outline: none;',
|
||||
'padding: 4px 0;',
|
||||
'position: absolute;',
|
||||
'overflow-y: auto;',
|
||||
'overflow-x: hidden;',
|
||||
'max-height: 100%;',
|
||||
'z-index: 20000;', /* Arbitrary, but some apps depend on it... */
|
||||
'}',
|
||||
`.blocklyWidgetDiv .blocklyMenu {
|
||||
background: #fff;
|
||||
border: 1px solid transparent;
|
||||
box-shadow: 0 0 3px 1px rgba(0,0,0,.3);
|
||||
font: normal 13px Arial, sans-serif;
|
||||
margin: 0;
|
||||
outline: none;
|
||||
padding: 4px 0;
|
||||
position: absolute;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
max-height: 100%;
|
||||
z-index: 20000;', /* Arbitrary, but some apps depend on it... */
|
||||
}`,
|
||||
|
||||
'.blocklyWidgetDiv .blocklyMenu.blocklyFocused {',
|
||||
'box-shadow: 0 0 6px 1px rgba(0,0,0,.3);',
|
||||
'}',
|
||||
`.blocklyWidgetDiv .blocklyMenu.blocklyFocused {
|
||||
box-shadow: 0 0 6px 1px rgba(0,0,0,.3);
|
||||
}`,
|
||||
|
||||
'.blocklyDropDownDiv .blocklyMenu {',
|
||||
'background: inherit;', /* Compatibility with gapi, reset from goog-menu */
|
||||
'border: inherit;', /* Compatibility with gapi, reset from goog-menu */
|
||||
'font: normal 13px "Helvetica Neue", Helvetica, sans-serif;',
|
||||
'outline: none;',
|
||||
'position: relative;', /* Compatibility with gapi, reset from goog-menu */
|
||||
'z-index: 20000;', /* Arbitrary, but some apps depend on it... */
|
||||
'}',
|
||||
`.blocklyDropDownDiv .blocklyMenu {
|
||||
background: inherit;', /* Compatibility with gapi, reset from goog-menu */
|
||||
border: inherit;', /* Compatibility with gapi, reset from goog-menu */
|
||||
font: normal 13px "Helvetica Neue", Helvetica, sans-serif;
|
||||
outline: none;
|
||||
position: relative;', /* Compatibility with gapi, reset from goog-menu */
|
||||
z-index: 20000;', /* Arbitrary, but some apps depend on it... */
|
||||
}`,
|
||||
|
||||
/* State: resting. */
|
||||
'.blocklyMenuItem {',
|
||||
'border: none;',
|
||||
'color: #000;',
|
||||
'cursor: pointer;',
|
||||
'list-style: none;',
|
||||
'margin: 0;',
|
||||
/* 7em on the right for shortcut. */
|
||||
'min-width: 7em;',
|
||||
'padding: 6px 15px;',
|
||||
'white-space: nowrap;',
|
||||
'}',
|
||||
`.blocklyMenuItem {
|
||||
border: none;
|
||||
color: #000;
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
/* 7em on the right for shortcut. */
|
||||
min-width: 7em;
|
||||
padding: 6px 15px;
|
||||
white-space: nowrap;
|
||||
}`,
|
||||
|
||||
/* State: disabled. */
|
||||
'.blocklyMenuItemDisabled {',
|
||||
'color: #ccc;',
|
||||
'cursor: inherit;',
|
||||
'}',
|
||||
`.blocklyMenuItemDisabled {
|
||||
color: #ccc;
|
||||
cursor: inherit;
|
||||
}`,
|
||||
|
||||
/* State: hover. */
|
||||
'.blocklyMenuItemHighlight {',
|
||||
'background-color: rgba(0,0,0,.1);',
|
||||
'}',
|
||||
`.blocklyMenuItemHighlight {
|
||||
background-color: rgba(0,0,0,.1);
|
||||
}`,
|
||||
|
||||
/* State: selected/checked. */
|
||||
'.blocklyMenuItemCheckbox {',
|
||||
'height: 16px;',
|
||||
'position: absolute;',
|
||||
'width: 16px;',
|
||||
'}',
|
||||
`.blocklyMenuItemCheckbox {
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
width: 16px;
|
||||
}`,
|
||||
|
||||
'.blocklyMenuItemSelected .blocklyMenuItemCheckbox {',
|
||||
'background: url(<<<PATH>>>/sprites.png) no-repeat -48px -16px;',
|
||||
'float: left;',
|
||||
'margin-left: -24px;',
|
||||
'position: static;', /* Scroll with the menu. */
|
||||
'}',
|
||||
`.blocklyMenuItemSelected .blocklyMenuItemCheckbox {
|
||||
background: url(<<<PATH>>>/sprites.png) no-repeat -48px -16px;
|
||||
float: left;
|
||||
margin-left: -24px;
|
||||
position: static;', /* Scroll with the menu. */
|
||||
}`,
|
||||
|
||||
'.blocklyMenuItemRtl .blocklyMenuItemCheckbox {',
|
||||
'float: right;',
|
||||
'margin-right: -24px;',
|
||||
'}',
|
||||
/* eslint-enable indent */
|
||||
`.blocklyMenuItemRtl .blocklyMenuItemCheckbox {
|
||||
float: right;
|
||||
margin-right: -24px;
|
||||
}`,
|
||||
];
|
||||
exports.CONTENT = CONTENT;
|
||||
|
||||
@@ -12,23 +12,26 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.DeleteArea');
|
||||
goog.module('Blockly.DeleteArea');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.BlockSvg');
|
||||
goog.require('Blockly.DragTarget');
|
||||
goog.require('Blockly.IDeleteArea');
|
||||
|
||||
goog.requireType('Blockly.IDraggable');
|
||||
const BlockSvg = goog.require('Blockly.BlockSvg');
|
||||
const DragTarget = goog.require('Blockly.DragTarget');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDeleteArea = goog.require('Blockly.IDeleteArea');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDraggable = goog.requireType('Blockly.IDraggable');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
|
||||
/**
|
||||
* Abstract class for a component that can delete a block or bubble that is
|
||||
* dropped on top of it.
|
||||
* @extends {Blockly.DragTarget}
|
||||
* @implements {Blockly.IDeleteArea}
|
||||
* @extends {DragTarget}
|
||||
* @implements {IDeleteArea}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.DeleteArea = function() {
|
||||
Blockly.DeleteArea.superClass_.constructor.call(this);
|
||||
const DeleteArea = function() {
|
||||
DeleteArea.superClass_.constructor.call(this);
|
||||
|
||||
/**
|
||||
* Whether the last block or bubble dragged over this delete area would be
|
||||
@@ -39,24 +42,24 @@ Blockly.DeleteArea = function() {
|
||||
*/
|
||||
this.wouldDelete_ = false;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.DeleteArea, Blockly.DragTarget);
|
||||
inherits(DeleteArea, DragTarget);
|
||||
|
||||
/**
|
||||
* Returns whether the provided block or bubble would be deleted if dropped on
|
||||
* this area.
|
||||
* This method should check if the element is deletable and is always called
|
||||
* before onDragEnter/onDragOver/onDragExit.
|
||||
* @param {!Blockly.IDraggable} element The block or bubble currently being
|
||||
* @param {!IDraggable} element The block or bubble currently being
|
||||
* dragged.
|
||||
* @param {boolean} couldConnect Whether the element could could connect to
|
||||
* another.
|
||||
* @return {boolean} Whether the element provided would be deleted if dropped on
|
||||
* this area.
|
||||
*/
|
||||
Blockly.DeleteArea.prototype.wouldDelete = function(element, couldConnect) {
|
||||
if (element instanceof Blockly.BlockSvg) {
|
||||
var block = /** @type {Blockly.BlockSvg} */ (element);
|
||||
var couldDeleteBlock = !block.getParent() && block.isDeletable();
|
||||
DeleteArea.prototype.wouldDelete = function(element, couldConnect) {
|
||||
if (element instanceof BlockSvg) {
|
||||
const block = /** @type {BlockSvg} */ (element);
|
||||
const couldDeleteBlock = !block.getParent() && block.isDeletable();
|
||||
this.updateWouldDelete_(couldDeleteBlock && !couldConnect);
|
||||
} else {
|
||||
this.updateWouldDelete_(element.isDeletable());
|
||||
@@ -69,6 +72,8 @@ Blockly.DeleteArea.prototype.wouldDelete = function(element, couldConnect) {
|
||||
* @param {boolean} wouldDelete The new value for the wouldDelete state.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.DeleteArea.prototype.updateWouldDelete_ = function(wouldDelete) {
|
||||
DeleteArea.prototype.updateWouldDelete_ = function(wouldDelete) {
|
||||
this.wouldDelete_ = wouldDelete;
|
||||
};
|
||||
|
||||
exports = DeleteArea;
|
||||
|
||||
@@ -12,65 +12,68 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.DragTarget');
|
||||
goog.module('Blockly.DragTarget');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.IDragTarget');
|
||||
|
||||
goog.requireType('Blockly.IDraggable');
|
||||
goog.requireType('Blockly.utils.Rect');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDragTarget = goog.require('Blockly.IDragTarget');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDraggable = goog.requireType('Blockly.IDraggable');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Rect = goog.requireType('Blockly.utils.Rect');
|
||||
|
||||
|
||||
/**
|
||||
* Abstract class for a component with custom behaviour when a block or bubble
|
||||
* is dragged over or dropped on top of it.
|
||||
* @implements {Blockly.IDragTarget}
|
||||
* @implements {IDragTarget}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.DragTarget = function() {};
|
||||
const DragTarget = function() {};
|
||||
|
||||
/**
|
||||
* Returns the bounding rectangle of the drag target area in pixel units
|
||||
* relative to the Blockly injection div.
|
||||
* @return {?Blockly.utils.Rect} The component's bounding box. Null if drag
|
||||
* @return {?Rect} The component's bounding box. Null if drag
|
||||
* target area should be ignored.
|
||||
*/
|
||||
Blockly.DragTarget.prototype.getClientRect;
|
||||
DragTarget.prototype.getClientRect;
|
||||
|
||||
/**
|
||||
* Handles when a cursor with a block or bubble enters this drag target.
|
||||
* @param {!Blockly.IDraggable} _dragElement The block or bubble currently being
|
||||
* @param {!IDraggable} _dragElement The block or bubble currently being
|
||||
* dragged.
|
||||
*/
|
||||
Blockly.DragTarget.prototype.onDragEnter = function(_dragElement) {
|
||||
DragTarget.prototype.onDragEnter = function(_dragElement) {
|
||||
// no-op
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles when a cursor with a block or bubble is dragged over this drag
|
||||
* target.
|
||||
* @param {!Blockly.IDraggable} _dragElement The block or bubble currently being
|
||||
* @param {!IDraggable} _dragElement The block or bubble currently being
|
||||
* dragged.
|
||||
*/
|
||||
Blockly.DragTarget.prototype.onDragOver = function(_dragElement) {
|
||||
DragTarget.prototype.onDragOver = function(_dragElement) {
|
||||
// no-op
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles when a cursor with a block or bubble exits this drag target.
|
||||
* @param {!Blockly.IDraggable} _dragElement The block or bubble currently being
|
||||
* @param {!IDraggable} _dragElement The block or bubble currently being
|
||||
* dragged.
|
||||
*/
|
||||
Blockly.DragTarget.prototype.onDragExit = function(_dragElement) {
|
||||
DragTarget.prototype.onDragExit = function(_dragElement) {
|
||||
// no-op
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles when a block or bubble is dropped on this component.
|
||||
* Should not handle delete here.
|
||||
* @param {!Blockly.IDraggable} _dragElement The block or bubble currently being
|
||||
* @param {!IDraggable} _dragElement The block or bubble currently being
|
||||
* dragged.
|
||||
*/
|
||||
Blockly.DragTarget.prototype.onDrop = function(_dragElement) {
|
||||
DragTarget.prototype.onDrop = function(_dragElement) {
|
||||
// no-op
|
||||
};
|
||||
|
||||
@@ -78,11 +81,13 @@ Blockly.DragTarget.prototype.onDrop = function(_dragElement) {
|
||||
* Returns whether the provided block or bubble should not be moved after being
|
||||
* dropped on this component. If true, the element will return to where it was
|
||||
* when the drag started.
|
||||
* @param {!Blockly.IDraggable} _dragElement The block or bubble currently being
|
||||
* @param {!IDraggable} _dragElement The block or bubble currently being
|
||||
* dragged.
|
||||
* @return {boolean} Whether the block or bubble provided should be returned to
|
||||
* drag start.
|
||||
*/
|
||||
Blockly.DragTarget.prototype.shouldPreventMove = function(_dragElement) {
|
||||
DragTarget.prototype.shouldPreventMove = function(_dragElement) {
|
||||
return false;
|
||||
};
|
||||
|
||||
exports = DragTarget;
|
||||
|
||||
@@ -17,18 +17,20 @@
|
||||
* @name Blockly.Extensions
|
||||
* @namespace
|
||||
*/
|
||||
goog.provide('Blockly.Extensions');
|
||||
goog.module('Blockly.Extensions');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.utils');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
const {checkMessageReferences, replaceMessageReferences, runAfterPageLoad} = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
* The set of all registered extensions, keyed by extension name/id.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Extensions.ALL_ = Object.create(null);
|
||||
const allExtensions = Object.create(null);
|
||||
exports.ALL_ = allExtensions;
|
||||
|
||||
/**
|
||||
* Registers a new extension function. Extensions are functions that help
|
||||
@@ -40,18 +42,19 @@ Blockly.Extensions.ALL_ = Object.create(null);
|
||||
* @throws {Error} if the extension name is empty, the extension is already
|
||||
* registered, or extensionFn is not a function.
|
||||
*/
|
||||
Blockly.Extensions.register = function(name, initFn) {
|
||||
const register = function(name, initFn) {
|
||||
if ((typeof name != 'string') || (name.trim() == '')) {
|
||||
throw Error('Error: Invalid extension name "' + name + '"');
|
||||
}
|
||||
if (Blockly.Extensions.ALL_[name]) {
|
||||
if (allExtensions[name]) {
|
||||
throw Error('Error: Extension "' + name + '" is already registered.');
|
||||
}
|
||||
if (typeof initFn != 'function') {
|
||||
throw Error('Error: Extension "' + name + '" must be a function');
|
||||
}
|
||||
Blockly.Extensions.ALL_[name] = initFn;
|
||||
allExtensions[name] = initFn;
|
||||
};
|
||||
exports.register = register;
|
||||
|
||||
/**
|
||||
* Registers a new extension function that adds all key/value of mixinObj.
|
||||
@@ -60,14 +63,15 @@ Blockly.Extensions.register = function(name, initFn) {
|
||||
* @throws {Error} if the extension name is empty or the extension is already
|
||||
* registered.
|
||||
*/
|
||||
Blockly.Extensions.registerMixin = function(name, mixinObj) {
|
||||
const registerMixin = function(name, mixinObj) {
|
||||
if (!mixinObj || typeof mixinObj != 'object') {
|
||||
throw Error('Error: Mixin "' + name + '" must be a object');
|
||||
}
|
||||
Blockly.Extensions.register(name, function() {
|
||||
register(name, function() {
|
||||
this.mixin(mixinObj);
|
||||
});
|
||||
};
|
||||
exports.registerMixin = registerMixin;
|
||||
|
||||
/**
|
||||
* Registers a new extension function that adds a mutator to the block.
|
||||
@@ -82,25 +86,21 @@ Blockly.Extensions.registerMixin = function(name, mixinObj) {
|
||||
* flyout of the mutator dialog.
|
||||
* @throws {Error} if the mutation is invalid or can't be applied to the block.
|
||||
*/
|
||||
Blockly.Extensions.registerMutator = function(name, mixinObj, opt_helperFn,
|
||||
opt_blockList) {
|
||||
var errorPrefix = 'Error when registering mutator "' + name + '": ';
|
||||
const registerMutator = function(name, mixinObj, opt_helperFn, opt_blockList) {
|
||||
const errorPrefix = 'Error when registering mutator "' + name + '": ';
|
||||
|
||||
// Sanity check the mixin object before registering it.
|
||||
Blockly.Extensions.checkHasFunction_(
|
||||
errorPrefix, mixinObj.domToMutation, 'domToMutation');
|
||||
Blockly.Extensions.checkHasFunction_(
|
||||
errorPrefix, mixinObj.mutationToDom, 'mutationToDom');
|
||||
checkHasFunction(errorPrefix, mixinObj.domToMutation, 'domToMutation');
|
||||
checkHasFunction(errorPrefix, mixinObj.mutationToDom, 'mutationToDom');
|
||||
|
||||
var hasMutatorDialog =
|
||||
Blockly.Extensions.checkMutatorDialog_(mixinObj, errorPrefix);
|
||||
const hasMutatorDialog = checkMutatorDialog(mixinObj, errorPrefix);
|
||||
|
||||
if (opt_helperFn && (typeof opt_helperFn != 'function')) {
|
||||
throw Error('Extension "' + name + '" is not a function');
|
||||
}
|
||||
|
||||
// Sanity checks passed.
|
||||
Blockly.Extensions.register(name, function() {
|
||||
register(name, function() {
|
||||
if (hasMutatorDialog) {
|
||||
if (!Blockly.Mutator) {
|
||||
throw Error(errorPrefix + 'Missing require for Blockly.Mutator');
|
||||
@@ -115,54 +115,59 @@ Blockly.Extensions.registerMutator = function(name, mixinObj, opt_helperFn,
|
||||
}
|
||||
});
|
||||
};
|
||||
exports.registerMutator = registerMutator;
|
||||
|
||||
/**
|
||||
* Unregisters the extension registered with the given name.
|
||||
* @param {string} name The name of the extension to unregister.
|
||||
*/
|
||||
Blockly.Extensions.unregister = function(name) {
|
||||
if (Blockly.Extensions.ALL_[name]) {
|
||||
delete Blockly.Extensions.ALL_[name];
|
||||
const unregister = function(name) {
|
||||
if (allExtensions[name]) {
|
||||
delete allExtensions[name];
|
||||
} else {
|
||||
console.warn('No extension mapping for name "' + name +
|
||||
'" found to unregister');
|
||||
console.warn(
|
||||
'No extension mapping for name "' + name + '" found to unregister');
|
||||
}
|
||||
};
|
||||
exports.unregister = unregister;
|
||||
|
||||
/**
|
||||
* Applies an extension method to a block. This should only be called during
|
||||
* block construction.
|
||||
* @param {string} name The name of the extension.
|
||||
* @param {!Blockly.Block} block The block to apply the named extension to.
|
||||
* @param {!Block} block The block to apply the named extension to.
|
||||
* @param {boolean} isMutator True if this extension defines a mutator.
|
||||
* @throws {Error} if the extension is not found.
|
||||
*/
|
||||
Blockly.Extensions.apply = function(name, block, isMutator) {
|
||||
var extensionFn = Blockly.Extensions.ALL_[name];
|
||||
const apply = function(name, block, isMutator) {
|
||||
const extensionFn = allExtensions[name];
|
||||
if (typeof extensionFn != 'function') {
|
||||
throw Error('Error: Extension "' + name + '" not found.');
|
||||
}
|
||||
let mutatorProperties;
|
||||
if (isMutator) {
|
||||
// Fail early if the block already has mutation properties.
|
||||
Blockly.Extensions.checkNoMutatorProperties_(name, block);
|
||||
checkNoMutatorProperties(name, block);
|
||||
} else {
|
||||
// Record the old properties so we can make sure they don't change after
|
||||
// applying the extension.
|
||||
var mutatorProperties = Blockly.Extensions.getMutatorProperties_(block);
|
||||
mutatorProperties = getMutatorProperties(block);
|
||||
}
|
||||
extensionFn.apply(block);
|
||||
|
||||
if (isMutator) {
|
||||
var errorPrefix = 'Error after applying mutator "' + name + '": ';
|
||||
Blockly.Extensions.checkBlockHasMutatorProperties_(errorPrefix, block);
|
||||
const errorPrefix = 'Error after applying mutator "' + name + '": ';
|
||||
checkBlockHasMutatorProperties(errorPrefix, block);
|
||||
} else {
|
||||
if (!Blockly.Extensions.mutatorPropertiesMatch_(
|
||||
/** @type {!Array<Object>} */ (mutatorProperties), block)) {
|
||||
throw Error('Error when applying extension "' + name + '": ' +
|
||||
if (!mutatorPropertiesMatch(
|
||||
/** @type {!Array<Object>} */ (mutatorProperties), block)) {
|
||||
throw Error(
|
||||
'Error when applying extension "' + name + '": ' +
|
||||
'mutation properties changed when applying a non-mutator extension.');
|
||||
}
|
||||
}
|
||||
};
|
||||
exports.apply = apply;
|
||||
|
||||
/**
|
||||
* Check that the given value is a function.
|
||||
@@ -172,14 +177,14 @@ Blockly.Extensions.apply = function(name, block, isMutator) {
|
||||
* @throws {Error} if the property does not exist or is not a function.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Extensions.checkHasFunction_ = function(errorPrefix, func,
|
||||
propertyName) {
|
||||
const checkHasFunction = function(errorPrefix, func, propertyName) {
|
||||
if (!func) {
|
||||
throw Error(errorPrefix +
|
||||
'missing required property "' + propertyName + '"');
|
||||
throw Error(
|
||||
errorPrefix + 'missing required property "' + propertyName + '"');
|
||||
} else if (typeof func != 'function') {
|
||||
throw Error(errorPrefix +
|
||||
'" required property "' + propertyName + '" must be a function');
|
||||
throw Error(
|
||||
errorPrefix + '" required property "' + propertyName +
|
||||
'" must be a function');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -189,14 +194,15 @@ Blockly.Extensions.checkHasFunction_ = function(errorPrefix, func,
|
||||
* extension to a block, to make sure we are not overwriting properties.
|
||||
* @param {string} mutationName The name of the mutation to reference in error
|
||||
* messages.
|
||||
* @param {!Blockly.Block} block The block to check.
|
||||
* @param {!Block} block The block to check.
|
||||
* @throws {Error} if any of the properties already exist on the block.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Extensions.checkNoMutatorProperties_ = function(mutationName, block) {
|
||||
var properties = Blockly.Extensions.getMutatorProperties_(block);
|
||||
const checkNoMutatorProperties = function(mutationName, block) {
|
||||
const properties = getMutatorProperties(block);
|
||||
if (properties.length) {
|
||||
throw Error('Error: tried to apply mutation "' + mutationName +
|
||||
throw Error(
|
||||
'Error: tried to apply mutation "' + mutationName +
|
||||
'" to a block that already has mutator functions.' +
|
||||
' Block id: ' + block.id);
|
||||
}
|
||||
@@ -214,9 +220,9 @@ Blockly.Extensions.checkNoMutatorProperties_ = function(mutationName, block) {
|
||||
* @throws {Error} if the object has only one of the functions.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Extensions.checkMutatorDialog_ = function(object, errorPrefix) {
|
||||
var hasCompose = object.compose !== undefined;
|
||||
var hasDecompose = object.decompose !== undefined;
|
||||
const checkMutatorDialog = function(object, errorPrefix) {
|
||||
const hasCompose = object.compose !== undefined;
|
||||
const hasDecompose = object.decompose !== undefined;
|
||||
|
||||
if (hasCompose && hasDecompose) {
|
||||
if (typeof object.compose != 'function') {
|
||||
@@ -228,19 +234,18 @@ Blockly.Extensions.checkMutatorDialog_ = function(object, errorPrefix) {
|
||||
} else if (!hasCompose && !hasDecompose) {
|
||||
return false;
|
||||
}
|
||||
throw Error(errorPrefix +
|
||||
'Must have both or neither of "compose" and "decompose"');
|
||||
throw Error(
|
||||
errorPrefix + 'Must have both or neither of "compose" and "decompose"');
|
||||
};
|
||||
|
||||
/**
|
||||
* Check that a block has required mutator properties. This should be called
|
||||
* after applying a mutation extension.
|
||||
* @param {string} errorPrefix The string to prepend to any error message.
|
||||
* @param {!Blockly.Block} block The block to inspect.
|
||||
* @param {!Block} block The block to inspect.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Extensions.checkBlockHasMutatorProperties_ = function(errorPrefix,
|
||||
block) {
|
||||
const checkBlockHasMutatorProperties = function(errorPrefix, block) {
|
||||
if (typeof block.domToMutation != 'function') {
|
||||
throw Error(errorPrefix + 'Applying a mutator didn\'t add "domToMutation"');
|
||||
}
|
||||
@@ -250,18 +255,18 @@ Blockly.Extensions.checkBlockHasMutatorProperties_ = function(errorPrefix,
|
||||
|
||||
// A block with a mutator isn't required to have a mutation dialog, but
|
||||
// it should still have both or neither of compose and decompose.
|
||||
Blockly.Extensions.checkMutatorDialog_(block, errorPrefix);
|
||||
checkMutatorDialog(block, errorPrefix);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a list of values of mutator properties on the given block.
|
||||
* @param {!Blockly.Block} block The block to inspect.
|
||||
* @param {!Block} block The block to inspect.
|
||||
* @return {!Array<Object>} A list with all of the defined properties, which
|
||||
* should be functions, but may be anything other than undefined.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Extensions.getMutatorProperties_ = function(block) {
|
||||
var result = [];
|
||||
const getMutatorProperties = function(block) {
|
||||
const result = [];
|
||||
// List each function explicitly by reference to allow for renaming
|
||||
// during compilation.
|
||||
if (block.domToMutation !== undefined) {
|
||||
@@ -284,16 +289,16 @@ Blockly.Extensions.getMutatorProperties_ = function(block) {
|
||||
* properties. This should be called after applying a non-mutator extension,
|
||||
* to verify that the extension didn't change properties it shouldn't.
|
||||
* @param {!Array<Object>} oldProperties The old values to compare to.
|
||||
* @param {!Blockly.Block} block The block to inspect for new values.
|
||||
* @param {!Block} block The block to inspect for new values.
|
||||
* @return {boolean} True if the property lists match.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Extensions.mutatorPropertiesMatch_ = function(oldProperties, block) {
|
||||
var newProperties = Blockly.Extensions.getMutatorProperties_(block);
|
||||
const mutatorPropertiesMatch = function(oldProperties, block) {
|
||||
const newProperties = getMutatorProperties(block);
|
||||
if (newProperties.length != oldProperties.length) {
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < newProperties.length; i++) {
|
||||
for (let i = 0; i < newProperties.length; i++) {
|
||||
if (oldProperties[i] != newProperties[i]) {
|
||||
return false;
|
||||
}
|
||||
@@ -320,76 +325,75 @@ Blockly.Extensions.mutatorPropertiesMatch_ = function(oldProperties, block) {
|
||||
* tooltip text.
|
||||
* @return {!Function} The extension function.
|
||||
*/
|
||||
Blockly.Extensions.buildTooltipForDropdown = function(dropdownName,
|
||||
lookupTable) {
|
||||
const buildTooltipForDropdown = function(dropdownName, lookupTable) {
|
||||
// List of block types already validated, to minimize duplicate warnings.
|
||||
var blockTypesChecked = [];
|
||||
const blockTypesChecked = [];
|
||||
|
||||
// Check the tooltip string messages for invalid references.
|
||||
// Wait for load, in case Blockly.Msg is not yet populated.
|
||||
// runAfterPageLoad() does not run in a Node.js environment due to lack of
|
||||
// document object, in which case skip the validation.
|
||||
if (typeof document == 'object') { // Relies on document.readyState
|
||||
Blockly.utils.runAfterPageLoad(function() {
|
||||
for (var key in lookupTable) {
|
||||
runAfterPageLoad(function() {
|
||||
for (let key in lookupTable) {
|
||||
// Will print warnings if reference is missing.
|
||||
Blockly.utils.checkMessageReferences(lookupTable[key]);
|
||||
checkMessageReferences(lookupTable[key]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual extension.
|
||||
* @this {Blockly.Block}
|
||||
* @this {Block}
|
||||
*/
|
||||
var extensionFn = function() {
|
||||
const extensionFn = function() {
|
||||
if (this.type && blockTypesChecked.indexOf(this.type) == -1) {
|
||||
Blockly.Extensions.checkDropdownOptionsInTable_(
|
||||
this, dropdownName, lookupTable);
|
||||
checkDropdownOptionsInTable(this, dropdownName, lookupTable);
|
||||
blockTypesChecked.push(this.type);
|
||||
}
|
||||
|
||||
this.setTooltip(function() {
|
||||
var value = String(this.getFieldValue(dropdownName));
|
||||
var tooltip = lookupTable[value];
|
||||
const value = String(this.getFieldValue(dropdownName));
|
||||
let tooltip = lookupTable[value];
|
||||
if (tooltip == null) {
|
||||
if (blockTypesChecked.indexOf(this.type) == -1) {
|
||||
// Warn for missing values on generated tooltips.
|
||||
var warning = 'No tooltip mapping for value ' + value +
|
||||
' of field ' + dropdownName;
|
||||
let warning = 'No tooltip mapping for value ' + value + ' of field ' +
|
||||
dropdownName;
|
||||
if (this.type != null) {
|
||||
warning += (' of block type ' + this.type);
|
||||
}
|
||||
console.warn(warning + '.');
|
||||
}
|
||||
} else {
|
||||
tooltip = Blockly.utils.replaceMessageReferences(tooltip);
|
||||
tooltip = replaceMessageReferences(tooltip);
|
||||
}
|
||||
return tooltip;
|
||||
}.bind(this));
|
||||
};
|
||||
return extensionFn;
|
||||
};
|
||||
exports.buildTooltipForDropdown = buildTooltipForDropdown;
|
||||
|
||||
/**
|
||||
* Checks all options keys are present in the provided string lookup table.
|
||||
* Emits console warnings when they are not.
|
||||
* @param {!Blockly.Block} block The block containing the dropdown
|
||||
* @param {!Block} block The block containing the dropdown
|
||||
* @param {string} dropdownName The name of the dropdown
|
||||
* @param {!Object<string, string>} lookupTable The string lookup table
|
||||
* @private
|
||||
*/
|
||||
Blockly.Extensions.checkDropdownOptionsInTable_ = function(block, dropdownName,
|
||||
lookupTable) {
|
||||
const checkDropdownOptionsInTable = function(block, dropdownName, lookupTable) {
|
||||
// Validate all dropdown options have values.
|
||||
var dropdown = block.getField(dropdownName);
|
||||
const dropdown = block.getField(dropdownName);
|
||||
if (!dropdown.isOptionListDynamic()) {
|
||||
var options = dropdown.getOptions();
|
||||
for (var i = 0; i < options.length; ++i) {
|
||||
var optionKey = options[i][1]; // label, then value
|
||||
const options = dropdown.getOptions();
|
||||
for (let i = 0; i < options.length; ++i) {
|
||||
const optionKey = options[i][1]; // label, then value
|
||||
if (lookupTable[optionKey] == null) {
|
||||
console.warn('No tooltip mapping for value ' + optionKey +
|
||||
' of field ' + dropdownName + ' of block type ' + block.type);
|
||||
console.warn(
|
||||
'No tooltip mapping for value ' + optionKey + ' of field ' +
|
||||
dropdownName + ' of block type ' + block.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -404,48 +408,47 @@ Blockly.Extensions.checkDropdownOptionsInTable_ = function(block, dropdownName,
|
||||
* @param {string} fieldName The field with the replacement text.
|
||||
* @return {!Function} The extension function.
|
||||
*/
|
||||
Blockly.Extensions.buildTooltipWithFieldText = function(msgTemplate,
|
||||
fieldName) {
|
||||
const buildTooltipWithFieldText = function(msgTemplate, fieldName) {
|
||||
// Check the tooltip string messages for invalid references.
|
||||
// Wait for load, in case Blockly.Msg is not yet populated.
|
||||
// runAfterPageLoad() does not run in a Node.js environment due to lack of
|
||||
// document object, in which case skip the validation.
|
||||
if (typeof document == 'object') { // Relies on document.readyState
|
||||
Blockly.utils.runAfterPageLoad(function() {
|
||||
runAfterPageLoad(function() {
|
||||
// Will print warnings if reference is missing.
|
||||
Blockly.utils.checkMessageReferences(msgTemplate);
|
||||
checkMessageReferences(msgTemplate);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual extension.
|
||||
* @this {Blockly.Block}
|
||||
* @this {Block}
|
||||
*/
|
||||
var extensionFn = function() {
|
||||
const extensionFn = function() {
|
||||
this.setTooltip(function() {
|
||||
var field = this.getField(fieldName);
|
||||
return Blockly.utils.replaceMessageReferences(msgTemplate)
|
||||
const field = this.getField(fieldName);
|
||||
return replaceMessageReferences(msgTemplate)
|
||||
.replace('%1', field ? field.getText() : '');
|
||||
}.bind(this));
|
||||
};
|
||||
return extensionFn;
|
||||
};
|
||||
exports.buildTooltipWithFieldText = buildTooltipWithFieldText;
|
||||
|
||||
/**
|
||||
* Configures the tooltip to mimic the parent block when connected. Otherwise,
|
||||
* uses the tooltip text at the time this extension is initialized. This takes
|
||||
* advantage of the fact that all other values from JSON are initialized before
|
||||
* extensions.
|
||||
* @this {Blockly.Block}
|
||||
* @this {Block}
|
||||
* @private
|
||||
*/
|
||||
Blockly.Extensions.extensionParentTooltip_ = function() {
|
||||
this.tooltipWhenNotConnected_ = this.tooltip;
|
||||
const extensionParentTooltip = function() {
|
||||
this.tooltipWhenNotConnected = this.tooltip;
|
||||
this.setTooltip(function() {
|
||||
var parent = this.getParent();
|
||||
const parent = this.getParent();
|
||||
return (parent && parent.getInputsInline() && parent.tooltip) ||
|
||||
this.tooltipWhenNotConnected_;
|
||||
this.tooltipWhenNotConnected;
|
||||
}.bind(this));
|
||||
};
|
||||
Blockly.Extensions.register('parent_tooltip_when_inline',
|
||||
Blockly.Extensions.extensionParentTooltip_);
|
||||
register('parent_tooltip_when_inline', extensionParentTooltip);
|
||||
|
||||
482
core/field.js
482
core/field.js
File diff suppressed because it is too large
Load Diff
@@ -10,14 +10,15 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.FieldCheckbox');
|
||||
goog.module('Blockly.FieldCheckbox');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
const Field = goog.require('Blockly.Field');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockChange');
|
||||
goog.require('Blockly.Field');
|
||||
goog.require('Blockly.fieldRegistry');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.object');
|
||||
|
||||
|
||||
/**
|
||||
@@ -29,12 +30,13 @@ goog.require('Blockly.utils.object');
|
||||
* returns a validated value ('TRUE' or 'FALSE'), or null to abort the
|
||||
* change.
|
||||
* @param {Object=} opt_config A map of options used to configure the field.
|
||||
* See the [field creation documentation]{@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/checkbox#creation}
|
||||
* See the [field creation documentation]{@link
|
||||
* https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/checkbox#creation}
|
||||
* for a list of properties this parameter supports.
|
||||
* @extends {Blockly.Field}
|
||||
* @extends {Field}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldCheckbox = function(opt_value, opt_validator, opt_config) {
|
||||
const FieldCheckbox = function(opt_value, opt_validator, opt_config) {
|
||||
/**
|
||||
* Character for the check mark. Used to apply a different check mark
|
||||
* character to individual fields.
|
||||
@@ -43,26 +45,26 @@ Blockly.FieldCheckbox = function(opt_value, opt_validator, opt_config) {
|
||||
*/
|
||||
this.checkChar_ = null;
|
||||
|
||||
Blockly.FieldCheckbox.superClass_.constructor.call(
|
||||
FieldCheckbox.superClass_.constructor.call(
|
||||
this, opt_value, opt_validator, opt_config);
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.FieldCheckbox, Blockly.Field);
|
||||
inherits(FieldCheckbox, Field);
|
||||
|
||||
/**
|
||||
* The default value for this field.
|
||||
* @type {*}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.DEFAULT_VALUE = false;
|
||||
FieldCheckbox.prototype.DEFAULT_VALUE = false;
|
||||
|
||||
/**
|
||||
* Construct a FieldCheckbox from a JSON arg object.
|
||||
* @param {!Object} options A JSON object with options (checked).
|
||||
* @return {!Blockly.FieldCheckbox} The new field instance.
|
||||
* @return {!FieldCheckbox} The new field instance.
|
||||
* @package
|
||||
* @nocollapse
|
||||
*/
|
||||
Blockly.FieldCheckbox.fromJson = function(options) {
|
||||
FieldCheckbox.fromJson = function(options) {
|
||||
// `this` might be a subclass of FieldCheckbox if that class doesn't override
|
||||
// the static fromJson method.
|
||||
return new this(options['checked'], undefined, options);
|
||||
@@ -73,19 +75,19 @@ Blockly.FieldCheckbox.fromJson = function(options) {
|
||||
* @type {string}
|
||||
* @const
|
||||
*/
|
||||
Blockly.FieldCheckbox.CHECK_CHAR = '\u2713';
|
||||
FieldCheckbox.CHECK_CHAR = '\u2713';
|
||||
|
||||
/**
|
||||
* Serializable fields are saved by the XML renderer, non-serializable fields
|
||||
* are not. Editable fields should also be serializable.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.SERIALIZABLE = true;
|
||||
FieldCheckbox.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Mouse cursor style when over the hotspot that initiates editability.
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.CURSOR = 'default';
|
||||
FieldCheckbox.prototype.CURSOR = 'default';
|
||||
|
||||
/**
|
||||
* Configure the field based on the given map of options.
|
||||
@@ -93,8 +95,8 @@ Blockly.FieldCheckbox.prototype.CURSOR = 'default';
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.configure_ = function(config) {
|
||||
Blockly.FieldCheckbox.superClass_.configure_.call(this, config);
|
||||
FieldCheckbox.prototype.configure_ = function(config) {
|
||||
FieldCheckbox.superClass_.configure_.call(this, config);
|
||||
if (config['checkCharacter']) {
|
||||
this.checkChar_ = config['checkCharacter'];
|
||||
}
|
||||
@@ -104,10 +106,10 @@ Blockly.FieldCheckbox.prototype.configure_ = function(config) {
|
||||
* Create the block UI for this checkbox.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.initView = function() {
|
||||
Blockly.FieldCheckbox.superClass_.initView.call(this);
|
||||
FieldCheckbox.prototype.initView = function() {
|
||||
FieldCheckbox.superClass_.initView.call(this);
|
||||
|
||||
Blockly.utils.dom.addClass(
|
||||
dom.addClass(
|
||||
/** @type {!SVGTextElement} **/ (this.textElement_), 'blocklyCheckbox');
|
||||
this.textElement_.style.display = this.value_ ? 'block' : 'none';
|
||||
};
|
||||
@@ -115,7 +117,7 @@ Blockly.FieldCheckbox.prototype.initView = function() {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.render_ = function() {
|
||||
FieldCheckbox.prototype.render_ = function() {
|
||||
if (this.textContent_) {
|
||||
this.textContent_.nodeValue = this.getDisplayText_();
|
||||
}
|
||||
@@ -125,8 +127,8 @@ Blockly.FieldCheckbox.prototype.render_ = function() {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.getDisplayText_ = function() {
|
||||
return this.checkChar_ || Blockly.FieldCheckbox.CHECK_CHAR;
|
||||
FieldCheckbox.prototype.getDisplayText_ = function() {
|
||||
return this.checkChar_ || FieldCheckbox.CHECK_CHAR;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -134,7 +136,7 @@ Blockly.FieldCheckbox.prototype.getDisplayText_ = function() {
|
||||
* @param {?string} character The character to use for the check mark, or
|
||||
* null to use the default.
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.setCheckCharacter = function(character) {
|
||||
FieldCheckbox.prototype.setCheckCharacter = function(character) {
|
||||
this.checkChar_ = character;
|
||||
this.forceRerender();
|
||||
};
|
||||
@@ -143,7 +145,7 @@ Blockly.FieldCheckbox.prototype.setCheckCharacter = function(character) {
|
||||
* Toggle the state of the checkbox on click.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.showEditor_ = function() {
|
||||
FieldCheckbox.prototype.showEditor_ = function() {
|
||||
this.setValue(!this.value_);
|
||||
};
|
||||
|
||||
@@ -153,7 +155,7 @@ Blockly.FieldCheckbox.prototype.showEditor_ = function() {
|
||||
* @return {?string} A valid value ('TRUE' or 'FALSE), or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
FieldCheckbox.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
if (opt_newValue === true || opt_newValue === 'TRUE') {
|
||||
return 'TRUE';
|
||||
}
|
||||
@@ -169,7 +171,7 @@ Blockly.FieldCheckbox.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
* that this is a either 'TRUE' or 'FALSE'.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.doValueUpdate_ = function(newValue) {
|
||||
FieldCheckbox.prototype.doValueUpdate_ = function(newValue) {
|
||||
this.value_ = this.convertValueToBool_(newValue);
|
||||
// Update visual.
|
||||
if (this.textElement_) {
|
||||
@@ -181,7 +183,7 @@ Blockly.FieldCheckbox.prototype.doValueUpdate_ = function(newValue) {
|
||||
* Get the value of this field, either 'TRUE' or 'FALSE'.
|
||||
* @return {string} The value of this field.
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.getValue = function() {
|
||||
FieldCheckbox.prototype.getValue = function() {
|
||||
return this.value_ ? 'TRUE' : 'FALSE';
|
||||
};
|
||||
|
||||
@@ -189,7 +191,7 @@ Blockly.FieldCheckbox.prototype.getValue = function() {
|
||||
* Get the boolean value of this field.
|
||||
* @return {boolean} The boolean value of this field.
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.getValueBoolean = function() {
|
||||
FieldCheckbox.prototype.getValueBoolean = function() {
|
||||
return /** @type {boolean} */ (this.value_);
|
||||
};
|
||||
|
||||
@@ -198,7 +200,7 @@ Blockly.FieldCheckbox.prototype.getValueBoolean = function() {
|
||||
* @return {string} Text representing the value of this field
|
||||
* ('true' or 'false').
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.getText = function() {
|
||||
FieldCheckbox.prototype.getText = function() {
|
||||
return String(this.convertValueToBool_(this.value_));
|
||||
};
|
||||
|
||||
@@ -211,7 +213,7 @@ Blockly.FieldCheckbox.prototype.getText = function() {
|
||||
* @return {boolean} The converted value.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.convertValueToBool_ = function(value) {
|
||||
FieldCheckbox.prototype.convertValueToBool_ = function(value) {
|
||||
if (typeof value == 'string') {
|
||||
return value == 'TRUE';
|
||||
} else {
|
||||
@@ -219,4 +221,6 @@ Blockly.FieldCheckbox.prototype.convertValueToBool_ = function(value) {
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.fieldRegistry.register('field_checkbox', Blockly.FieldCheckbox);
|
||||
fieldRegistry.register('field_checkbox', FieldCheckbox);
|
||||
|
||||
exports = FieldCheckbox;
|
||||
|
||||
@@ -10,22 +10,24 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.FieldColour');
|
||||
goog.module('Blockly.FieldColour');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.browserEvents');
|
||||
goog.require('Blockly.Css');
|
||||
goog.require('Blockly.DropDownDiv');
|
||||
const Css = goog.require('Blockly.Css');
|
||||
const DropDownDiv = goog.require('Blockly.DropDownDiv');
|
||||
const Field = goog.require('Blockly.Field');
|
||||
const IdGenerator = goog.require('Blockly.utils.IdGenerator');
|
||||
const KeyCodes = goog.require('Blockly.utils.KeyCodes');
|
||||
const Size = goog.require('Blockly.utils.Size');
|
||||
const aria = goog.require('Blockly.utils.aria');
|
||||
const colour = goog.require('Blockly.utils.colour');
|
||||
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
||||
const {addClass, removeClass} = goog.require('Blockly.utils.dom');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const {conditionalBind, unbind, Data} = goog.require('Blockly.browserEvents');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockChange');
|
||||
goog.require('Blockly.Field');
|
||||
goog.require('Blockly.fieldRegistry');
|
||||
goog.require('Blockly.utils.aria');
|
||||
goog.require('Blockly.utils.colour');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.IdGenerator');
|
||||
goog.require('Blockly.utils.KeyCodes');
|
||||
goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.utils.Size');
|
||||
|
||||
|
||||
/**
|
||||
@@ -34,15 +36,17 @@ goog.require('Blockly.utils.Size');
|
||||
* '#rrggbb' format. Defaults to the first value in the default colour array.
|
||||
* @param {Function=} opt_validator A function that is called to validate
|
||||
* changes to the field's value. Takes in a colour string & returns a
|
||||
* validated colour string ('#rrggbb' format), or null to abort the change.
|
||||
* validated colour string ('#rrggbb' format), or null to abort the
|
||||
* change.Blockly.
|
||||
* @param {Object=} opt_config A map of options used to configure the field.
|
||||
* See the [field creation documentation]{@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/colour}
|
||||
* See the [field creation documentation]{@link
|
||||
* https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/colour}
|
||||
* for a list of properties this parameter supports.
|
||||
* @extends {Blockly.Field}
|
||||
* @extends {Field}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldColour = function(opt_value, opt_validator, opt_config) {
|
||||
Blockly.FieldColour.superClass_.constructor.call(
|
||||
const FieldColour = function(opt_value, opt_validator, opt_config) {
|
||||
FieldColour.superClass_.constructor.call(
|
||||
this, opt_value, opt_validator, opt_config);
|
||||
|
||||
/**
|
||||
@@ -61,49 +65,49 @@ Blockly.FieldColour = function(opt_value, opt_validator, opt_config) {
|
||||
|
||||
/**
|
||||
* Mouse click event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?Data}
|
||||
* @private
|
||||
*/
|
||||
this.onClickWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Mouse move event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?Data}
|
||||
* @private
|
||||
*/
|
||||
this.onMouseMoveWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Mouse enter event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?Data}
|
||||
* @private
|
||||
*/
|
||||
this.onMouseEnterWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Mouse leave event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?Data}
|
||||
* @private
|
||||
*/
|
||||
this.onMouseLeaveWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Key down event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?Data}
|
||||
* @private
|
||||
*/
|
||||
this.onKeyDownWrapper_ = null;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.FieldColour, Blockly.Field);
|
||||
inherits(FieldColour, Field);
|
||||
|
||||
/**
|
||||
* Construct a FieldColour from a JSON arg object.
|
||||
* @param {!Object} options A JSON object with options (colour).
|
||||
* @return {!Blockly.FieldColour} The new field instance.
|
||||
* @return {!FieldColour} The new field instance.
|
||||
* @package
|
||||
* @nocollapse
|
||||
*/
|
||||
Blockly.FieldColour.fromJson = function(options) {
|
||||
FieldColour.fromJson = function(options) {
|
||||
// `this` might be a subclass of FieldColour if that class doesn't override
|
||||
// the static fromJson method.
|
||||
return new this(options['colour'], undefined, options);
|
||||
@@ -114,12 +118,12 @@ Blockly.FieldColour.fromJson = function(options) {
|
||||
* are not. Editable fields should also be serializable.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.FieldColour.prototype.SERIALIZABLE = true;
|
||||
FieldColour.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Mouse cursor style when over the hotspot that initiates the editor.
|
||||
*/
|
||||
Blockly.FieldColour.prototype.CURSOR = 'default';
|
||||
FieldColour.prototype.CURSOR = 'default';
|
||||
|
||||
/**
|
||||
* Used to tell if the field needs to be rendered the next time the block is
|
||||
@@ -128,21 +132,21 @@ Blockly.FieldColour.prototype.CURSOR = 'default';
|
||||
* @type {boolean}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldColour.prototype.isDirty_ = false;
|
||||
FieldColour.prototype.isDirty_ = false;
|
||||
|
||||
/**
|
||||
* Array of colours used by this field. If null, use the global list.
|
||||
* @type {Array<string>}
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldColour.prototype.colours_ = null;
|
||||
FieldColour.prototype.colours_ = null;
|
||||
|
||||
/**
|
||||
* Array of colour tooltips used by this field. If null, use the global list.
|
||||
* @type {Array<string>}
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldColour.prototype.titles_ = null;
|
||||
FieldColour.prototype.titles_ = null;
|
||||
|
||||
/**
|
||||
* Number of colour columns used by this field. If 0, use the global setting.
|
||||
@@ -150,7 +154,7 @@ Blockly.FieldColour.prototype.titles_ = null;
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldColour.prototype.columns_ = 0;
|
||||
FieldColour.prototype.columns_ = 0;
|
||||
|
||||
/**
|
||||
* Configure the field based on the given map of options.
|
||||
@@ -158,8 +162,8 @@ Blockly.FieldColour.prototype.columns_ = 0;
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldColour.prototype.configure_ = function(config) {
|
||||
Blockly.FieldColour.superClass_.configure_.call(this, config);
|
||||
FieldColour.prototype.configure_ = function(config) {
|
||||
FieldColour.superClass_.configure_.call(this, config);
|
||||
if (config['colourOptions']) {
|
||||
this.colours_ = config['colourOptions'];
|
||||
this.titles_ = config['colourTitles'];
|
||||
@@ -173,8 +177,8 @@ Blockly.FieldColour.prototype.configure_ = function(config) {
|
||||
* Create the block UI for this colour field.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldColour.prototype.initView = function() {
|
||||
this.size_ = new Blockly.utils.Size(
|
||||
FieldColour.prototype.initView = function() {
|
||||
this.size_ = new Size(
|
||||
this.getConstants().FIELD_COLOUR_DEFAULT_WIDTH,
|
||||
this.getConstants().FIELD_COLOUR_DEFAULT_HEIGHT);
|
||||
if (!this.getConstants().FIELD_COLOUR_FULL_BLOCK) {
|
||||
@@ -188,7 +192,7 @@ Blockly.FieldColour.prototype.initView = function() {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldColour.prototype.applyColour = function() {
|
||||
FieldColour.prototype.applyColour = function() {
|
||||
if (!this.getConstants().FIELD_COLOUR_FULL_BLOCK) {
|
||||
if (this.borderRect_) {
|
||||
this.borderRect_.style.fill = /** @type {string} */ (this.getValue());
|
||||
@@ -205,11 +209,11 @@ Blockly.FieldColour.prototype.applyColour = function() {
|
||||
* @return {?string} A valid colour, or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldColour.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
FieldColour.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
if (typeof opt_newValue != 'string') {
|
||||
return null;
|
||||
}
|
||||
return Blockly.utils.colour.parse(opt_newValue);
|
||||
return colour.parse(opt_newValue);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -218,7 +222,7 @@ Blockly.FieldColour.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
* that this is a colour in '#rrggbb' format.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldColour.prototype.doValueUpdate_ = function(newValue) {
|
||||
FieldColour.prototype.doValueUpdate_ = function(newValue) {
|
||||
this.value_ = newValue;
|
||||
if (this.borderRect_) {
|
||||
this.borderRect_.style.fill = /** @type {string} */ (newValue);
|
||||
@@ -232,8 +236,8 @@ Blockly.FieldColour.prototype.doValueUpdate_ = function(newValue) {
|
||||
* Get the text for this field. Used when the block is collapsed.
|
||||
* @return {string} Text representing the value of this field.
|
||||
*/
|
||||
Blockly.FieldColour.prototype.getText = function() {
|
||||
var colour = /** @type {string} */ (this.value_);
|
||||
FieldColour.prototype.getText = function() {
|
||||
let colour = /** @type {string} */ (this.value_);
|
||||
// Try to use #rgb format if possible, rather than #rrggbb.
|
||||
if (/^#(.)\1(.)\2(.)\3$/.test(colour)) {
|
||||
colour = '#' + colour[1] + colour[3] + colour[5];
|
||||
@@ -247,7 +251,7 @@ Blockly.FieldColour.prototype.getText = function() {
|
||||
* All colour pickers use this unless overridden with setColours.
|
||||
* @type {!Array<string>}
|
||||
*/
|
||||
Blockly.FieldColour.COLOURS = [
|
||||
FieldColour.COLOURS = [
|
||||
// grays
|
||||
'#ffffff', '#cccccc', '#c0c0c0', '#999999', '#666666', '#333333', '#000000',
|
||||
// reds
|
||||
@@ -275,7 +279,7 @@ Blockly.FieldColour.COLOURS = [
|
||||
* @type {*}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldColour.prototype.DEFAULT_VALUE = Blockly.FieldColour.COLOURS[0];
|
||||
FieldColour.prototype.DEFAULT_VALUE = FieldColour.COLOURS[0];
|
||||
|
||||
/**
|
||||
* An array of tooltip strings for the palette. If not the same length as
|
||||
@@ -283,23 +287,23 @@ Blockly.FieldColour.prototype.DEFAULT_VALUE = Blockly.FieldColour.COLOURS[0];
|
||||
* All colour pickers use this unless overridden with setColours.
|
||||
* @type {!Array<string>}
|
||||
*/
|
||||
Blockly.FieldColour.TITLES = [];
|
||||
FieldColour.TITLES = [];
|
||||
|
||||
/**
|
||||
* Number of columns in the palette.
|
||||
* All colour pickers use this unless overridden with setColumns.
|
||||
*/
|
||||
Blockly.FieldColour.COLUMNS = 7;
|
||||
FieldColour.COLUMNS = 7;
|
||||
|
||||
/**
|
||||
* Set a custom colour grid for this field.
|
||||
* @param {Array<string>} colours Array of colours for this block,
|
||||
* or null to use default (Blockly.FieldColour.COLOURS).
|
||||
* or null to use default (FieldColour.COLOURS).
|
||||
* @param {Array<string>=} opt_titles Optional array of colour tooltips,
|
||||
* or null to use default (Blockly.FieldColour.TITLES).
|
||||
* @return {!Blockly.FieldColour} Returns itself (for method chaining).
|
||||
* or null to use default (FieldColour.TITLES).
|
||||
* @return {!FieldColour} Returns itself (for method chaining).
|
||||
*/
|
||||
Blockly.FieldColour.prototype.setColours = function(colours, opt_titles) {
|
||||
FieldColour.prototype.setColours = function(colours, opt_titles) {
|
||||
this.colours_ = colours;
|
||||
if (opt_titles) {
|
||||
this.titles_ = opt_titles;
|
||||
@@ -310,10 +314,10 @@ Blockly.FieldColour.prototype.setColours = function(colours, opt_titles) {
|
||||
/**
|
||||
* Set a custom grid size for this field.
|
||||
* @param {number} columns Number of columns for this block,
|
||||
* or 0 to use default (Blockly.FieldColour.COLUMNS).
|
||||
* @return {!Blockly.FieldColour} Returns itself (for method chaining).
|
||||
* or 0 to use default (FieldColour.COLUMNS).
|
||||
* @return {!FieldColour} Returns itself (for method chaining).
|
||||
*/
|
||||
Blockly.FieldColour.prototype.setColumns = function(columns) {
|
||||
FieldColour.prototype.setColumns = function(columns) {
|
||||
this.columns_ = columns;
|
||||
return this;
|
||||
};
|
||||
@@ -322,15 +326,14 @@ Blockly.FieldColour.prototype.setColumns = function(columns) {
|
||||
* Create and show the colour field's editor.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldColour.prototype.showEditor_ = function() {
|
||||
FieldColour.prototype.showEditor_ = function() {
|
||||
this.dropdownCreate_();
|
||||
Blockly.DropDownDiv.getContentDiv().appendChild(this.picker_);
|
||||
DropDownDiv.getContentDiv().appendChild(this.picker_);
|
||||
|
||||
Blockly.DropDownDiv.showPositionedByField(
|
||||
this, this.dropdownDispose_.bind(this));
|
||||
DropDownDiv.showPositionedByField(this, this.dropdownDispose_.bind(this));
|
||||
|
||||
// Focus so we can start receiving keyboard events.
|
||||
this.picker_.focus({preventScroll:true});
|
||||
this.picker_.focus({preventScroll: true});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -338,12 +341,12 @@ Blockly.FieldColour.prototype.showEditor_ = function() {
|
||||
* @param {!MouseEvent} e Mouse event.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldColour.prototype.onClick_ = function(e) {
|
||||
var cell = /** @type {!Element} */ (e.target);
|
||||
var colour = cell && cell.label;
|
||||
FieldColour.prototype.onClick_ = function(e) {
|
||||
const cell = /** @type {!Element} */ (e.target);
|
||||
const colour = cell && cell.label;
|
||||
if (colour !== null) {
|
||||
this.setValue(colour);
|
||||
Blockly.DropDownDiv.hideIfOwner(this);
|
||||
DropDownDiv.hideIfOwner(this);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -353,30 +356,30 @@ Blockly.FieldColour.prototype.onClick_ = function(e) {
|
||||
* @param {!KeyboardEvent} e Keyboard event.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldColour.prototype.onKeyDown_ = function(e) {
|
||||
var handled = false;
|
||||
if (e.keyCode === Blockly.utils.KeyCodes.UP) {
|
||||
FieldColour.prototype.onKeyDown_ = function(e) {
|
||||
let handled = false;
|
||||
if (e.keyCode === KeyCodes.UP) {
|
||||
this.moveHighlightBy_(0, -1);
|
||||
handled = true;
|
||||
} else if (e.keyCode === Blockly.utils.KeyCodes.DOWN) {
|
||||
} else if (e.keyCode === KeyCodes.DOWN) {
|
||||
this.moveHighlightBy_(0, 1);
|
||||
handled = true;
|
||||
} else if (e.keyCode === Blockly.utils.KeyCodes.LEFT) {
|
||||
} else if (e.keyCode === KeyCodes.LEFT) {
|
||||
this.moveHighlightBy_(-1, 0);
|
||||
handled = true;
|
||||
} else if (e.keyCode === Blockly.utils.KeyCodes.RIGHT) {
|
||||
} else if (e.keyCode === KeyCodes.RIGHT) {
|
||||
this.moveHighlightBy_(1, 0);
|
||||
handled = true;
|
||||
} else if (e.keyCode === Blockly.utils.KeyCodes.ENTER) {
|
||||
} else if (e.keyCode === KeyCodes.ENTER) {
|
||||
// Select the highlighted colour.
|
||||
var highlighted = this.getHighlighted_();
|
||||
const highlighted = this.getHighlighted_();
|
||||
if (highlighted) {
|
||||
var colour = highlighted && highlighted.label;
|
||||
const colour = highlighted && highlighted.label;
|
||||
if (colour !== null) {
|
||||
this.setValue(colour);
|
||||
}
|
||||
}
|
||||
Blockly.DropDownDiv.hideWithoutAnimation();
|
||||
DropDownDiv.hideWithoutAnimation();
|
||||
handled = true;
|
||||
}
|
||||
if (handled) {
|
||||
@@ -390,13 +393,13 @@ Blockly.FieldColour.prototype.onKeyDown_ = function(e) {
|
||||
* @param {number} dy Change of y
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldColour.prototype.moveHighlightBy_ = function(dx, dy) {
|
||||
var colours = this.colours_ || Blockly.FieldColour.COLOURS;
|
||||
var columns = this.columns_ || Blockly.FieldColour.COLUMNS;
|
||||
FieldColour.prototype.moveHighlightBy_ = function(dx, dy) {
|
||||
const colours = this.colours_ || FieldColour.COLOURS;
|
||||
const columns = this.columns_ || FieldColour.COLUMNS;
|
||||
|
||||
// Get the current x and y coordinates
|
||||
var x = this.highlightedIndex_ % columns;
|
||||
var y = Math.floor(this.highlightedIndex_ / columns);
|
||||
let x = this.highlightedIndex_ % columns;
|
||||
let y = Math.floor(this.highlightedIndex_ / columns);
|
||||
|
||||
// Add the offset
|
||||
x += dx;
|
||||
@@ -414,8 +417,7 @@ Blockly.FieldColour.prototype.moveHighlightBy_ = function(dx, dy) {
|
||||
} else if (dx > 0) {
|
||||
// Move right one grid cell, even in RTL.
|
||||
// Loop to the start of the next row, if there's room.
|
||||
if (x > columns - 1 &&
|
||||
y < Math.floor(colours.length / columns) - 1) {
|
||||
if (x > columns - 1 && y < Math.floor(colours.length / columns) - 1) {
|
||||
x = 0;
|
||||
y++;
|
||||
} else if (x > columns - 1) {
|
||||
@@ -434,8 +436,9 @@ Blockly.FieldColour.prototype.moveHighlightBy_ = function(dx, dy) {
|
||||
}
|
||||
|
||||
// Move the highlight to the new coordinates.
|
||||
var cell = /** @type {!Element} */ (this.picker_.childNodes[y].childNodes[x]);
|
||||
var index = (y * columns) + x;
|
||||
const cell =
|
||||
/** @type {!Element} */ (this.picker_.childNodes[y].childNodes[x]);
|
||||
const index = (y * columns) + x;
|
||||
this.setHighlightedCell_(cell, index);
|
||||
};
|
||||
|
||||
@@ -444,9 +447,9 @@ Blockly.FieldColour.prototype.moveHighlightBy_ = function(dx, dy) {
|
||||
* @param {!MouseEvent} e Mouse event.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldColour.prototype.onMouseMove_ = function(e) {
|
||||
var cell = /** @type {!Element} */ (e.target);
|
||||
var index = cell && Number(cell.getAttribute('data-index'));
|
||||
FieldColour.prototype.onMouseMove_ = function(e) {
|
||||
const cell = /** @type {!Element} */ (e.target);
|
||||
const index = cell && Number(cell.getAttribute('data-index'));
|
||||
if (index !== null && index !== this.highlightedIndex_) {
|
||||
this.setHighlightedCell_(cell, index);
|
||||
}
|
||||
@@ -456,8 +459,8 @@ Blockly.FieldColour.prototype.onMouseMove_ = function(e) {
|
||||
* Handle a mouse enter event. Focus the picker.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldColour.prototype.onMouseEnter_ = function() {
|
||||
this.picker_.focus({preventScroll:true});
|
||||
FieldColour.prototype.onMouseEnter_ = function() {
|
||||
this.picker_.focus({preventScroll: true});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -465,11 +468,11 @@ Blockly.FieldColour.prototype.onMouseEnter_ = function() {
|
||||
* the currently highlighted colour.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldColour.prototype.onMouseLeave_ = function() {
|
||||
FieldColour.prototype.onMouseLeave_ = function() {
|
||||
this.picker_.blur();
|
||||
var highlighted = this.getHighlighted_();
|
||||
const highlighted = this.getHighlighted_();
|
||||
if (highlighted) {
|
||||
Blockly.utils.dom.removeClass(highlighted, 'blocklyColourHighlighted');
|
||||
removeClass(highlighted, 'blocklyColourHighlighted');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -478,15 +481,15 @@ Blockly.FieldColour.prototype.onMouseLeave_ = function() {
|
||||
* @return {?HTMLElement} Highlighted item (null if none).
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldColour.prototype.getHighlighted_ = function() {
|
||||
var columns = this.columns_ || Blockly.FieldColour.COLUMNS;
|
||||
var x = this.highlightedIndex_ % columns;
|
||||
var y = Math.floor(this.highlightedIndex_ / columns);
|
||||
var row = this.picker_.childNodes[y];
|
||||
FieldColour.prototype.getHighlighted_ = function() {
|
||||
const columns = this.columns_ || FieldColour.COLUMNS;
|
||||
const x = this.highlightedIndex_ % columns;
|
||||
const y = Math.floor(this.highlightedIndex_ / columns);
|
||||
const row = this.picker_.childNodes[y];
|
||||
if (!row) {
|
||||
return null;
|
||||
}
|
||||
var col = /** @type {HTMLElement} */ (row.childNodes[x]);
|
||||
const col = /** @type {HTMLElement} */ (row.childNodes[x]);
|
||||
return col;
|
||||
};
|
||||
|
||||
@@ -496,60 +499,58 @@ Blockly.FieldColour.prototype.getHighlighted_ = function() {
|
||||
* @param {number} index the index of the new cell
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldColour.prototype.setHighlightedCell_ = function(cell, index) {
|
||||
FieldColour.prototype.setHighlightedCell_ = function(cell, index) {
|
||||
// Unhighlight the current item.
|
||||
var highlighted = this.getHighlighted_();
|
||||
const highlighted = this.getHighlighted_();
|
||||
if (highlighted) {
|
||||
Blockly.utils.dom.removeClass(highlighted, 'blocklyColourHighlighted');
|
||||
removeClass(highlighted, 'blocklyColourHighlighted');
|
||||
}
|
||||
// Highlight new item.
|
||||
Blockly.utils.dom.addClass(cell, 'blocklyColourHighlighted');
|
||||
addClass(cell, 'blocklyColourHighlighted');
|
||||
// Set new highlighted index.
|
||||
this.highlightedIndex_ = index;
|
||||
|
||||
// Update accessibility roles.
|
||||
Blockly.utils.aria.setState(/** @type {!Element} */ (this.picker_),
|
||||
Blockly.utils.aria.State.ACTIVEDESCENDANT, cell.getAttribute('id'));
|
||||
aria.setState(
|
||||
/** @type {!Element} */ (this.picker_), aria.State.ACTIVEDESCENDANT,
|
||||
cell.getAttribute('id'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a colour picker dropdown editor.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldColour.prototype.dropdownCreate_ = function() {
|
||||
var columns = this.columns_ || Blockly.FieldColour.COLUMNS;
|
||||
var colours = this.colours_ || Blockly.FieldColour.COLOURS;
|
||||
var titles = this.titles_ || Blockly.FieldColour.TITLES;
|
||||
var selectedColour = this.getValue();
|
||||
FieldColour.prototype.dropdownCreate_ = function() {
|
||||
const columns = this.columns_ || FieldColour.COLUMNS;
|
||||
const colours = this.colours_ || FieldColour.COLOURS;
|
||||
const titles = this.titles_ || FieldColour.TITLES;
|
||||
const selectedColour = this.getValue();
|
||||
// Create the palette.
|
||||
var table = document.createElement('table');
|
||||
const table = document.createElement('table');
|
||||
table.className = 'blocklyColourTable';
|
||||
table.tabIndex = 0;
|
||||
table.dir = 'ltr';
|
||||
Blockly.utils.aria.setRole(table, Blockly.utils.aria.Role.GRID);
|
||||
Blockly.utils.aria.setState(table, Blockly.utils.aria.State.EXPANDED, true);
|
||||
Blockly.utils.aria.setState(table, Blockly.utils.aria.State.ROWCOUNT,
|
||||
Math.floor(colours.length / columns));
|
||||
Blockly.utils.aria.setState(table, Blockly.utils.aria.State.COLCOUNT,
|
||||
columns);
|
||||
var row;
|
||||
for (var i = 0; i < colours.length; i++) {
|
||||
aria.setRole(table, aria.Role.GRID);
|
||||
aria.setState(table, aria.State.EXPANDED, true);
|
||||
aria.setState(
|
||||
table, aria.State.ROWCOUNT, Math.floor(colours.length / columns));
|
||||
aria.setState(table, aria.State.COLCOUNT, columns);
|
||||
let row;
|
||||
for (let i = 0; i < colours.length; i++) {
|
||||
if (i % columns == 0) {
|
||||
row = document.createElement('tr');
|
||||
Blockly.utils.aria.setRole(row, Blockly.utils.aria.Role.ROW);
|
||||
aria.setRole(row, aria.Role.ROW);
|
||||
table.appendChild(row);
|
||||
}
|
||||
var cell = document.createElement('td');
|
||||
const cell = document.createElement('td');
|
||||
row.appendChild(cell);
|
||||
cell.label = colours[i]; // This becomes the value, if clicked.
|
||||
cell.title = titles[i] || colours[i];
|
||||
cell.id = Blockly.utils.IdGenerator.getNextUniqueId();
|
||||
cell.id = IdGenerator.getNextUniqueId();
|
||||
cell.setAttribute('data-index', i);
|
||||
Blockly.utils.aria.setRole(cell, Blockly.utils.aria.Role.GRIDCELL);
|
||||
Blockly.utils.aria.setState(cell,
|
||||
Blockly.utils.aria.State.LABEL, colours[i]);
|
||||
Blockly.utils.aria.setState(cell,
|
||||
Blockly.utils.aria.State.SELECTED, colours[i] == selectedColour);
|
||||
aria.setRole(cell, aria.Role.GRIDCELL);
|
||||
aria.setState(cell, aria.State.LABEL, colours[i]);
|
||||
aria.setState(cell, aria.State.SELECTED, colours[i] == selectedColour);
|
||||
cell.style.backgroundColor = colours[i];
|
||||
if (colours[i] == selectedColour) {
|
||||
cell.className = 'blocklyColourSelected';
|
||||
@@ -558,16 +559,16 @@ Blockly.FieldColour.prototype.dropdownCreate_ = function() {
|
||||
}
|
||||
|
||||
// Configure event handler on the table to listen for any event in a cell.
|
||||
this.onClickWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
table, 'click', this, this.onClick_, true);
|
||||
this.onMouseMoveWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
table, 'mousemove', this, this.onMouseMove_, true);
|
||||
this.onMouseEnterWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
table, 'mouseenter', this, this.onMouseEnter_, true);
|
||||
this.onMouseLeaveWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
table, 'mouseleave', this, this.onMouseLeave_, true);
|
||||
this.onKeyDownWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
table, 'keydown', this, this.onKeyDown_);
|
||||
this.onClickWrapper_ =
|
||||
conditionalBind(table, 'click', this, this.onClick_, true);
|
||||
this.onMouseMoveWrapper_ =
|
||||
conditionalBind(table, 'mousemove', this, this.onMouseMove_, true);
|
||||
this.onMouseEnterWrapper_ =
|
||||
conditionalBind(table, 'mouseenter', this, this.onMouseEnter_, true);
|
||||
this.onMouseLeaveWrapper_ =
|
||||
conditionalBind(table, 'mouseleave', this, this.onMouseLeave_, true);
|
||||
this.onKeyDownWrapper_ =
|
||||
conditionalBind(table, 'keydown', this, this.onKeyDown_);
|
||||
|
||||
this.picker_ = table;
|
||||
};
|
||||
@@ -576,25 +577,25 @@ Blockly.FieldColour.prototype.dropdownCreate_ = function() {
|
||||
* Disposes of events and DOM-references belonging to the colour editor.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldColour.prototype.dropdownDispose_ = function() {
|
||||
FieldColour.prototype.dropdownDispose_ = function() {
|
||||
if (this.onClickWrapper_) {
|
||||
Blockly.browserEvents.unbind(this.onClickWrapper_);
|
||||
unbind(this.onClickWrapper_);
|
||||
this.onClickWrapper_ = null;
|
||||
}
|
||||
if (this.onMouseMoveWrapper_) {
|
||||
Blockly.browserEvents.unbind(this.onMouseMoveWrapper_);
|
||||
unbind(this.onMouseMoveWrapper_);
|
||||
this.onMouseMoveWrapper_ = null;
|
||||
}
|
||||
if (this.onMouseEnterWrapper_) {
|
||||
Blockly.browserEvents.unbind(this.onMouseEnterWrapper_);
|
||||
unbind(this.onMouseEnterWrapper_);
|
||||
this.onMouseEnterWrapper_ = null;
|
||||
}
|
||||
if (this.onMouseLeaveWrapper_) {
|
||||
Blockly.browserEvents.unbind(this.onMouseLeaveWrapper_);
|
||||
unbind(this.onMouseLeaveWrapper_);
|
||||
this.onMouseLeaveWrapper_ = null;
|
||||
}
|
||||
if (this.onKeyDownWrapper_) {
|
||||
Blockly.browserEvents.unbind(this.onKeyDownWrapper_);
|
||||
unbind(this.onKeyDownWrapper_);
|
||||
this.onKeyDownWrapper_ = null;
|
||||
}
|
||||
this.picker_ = null;
|
||||
@@ -604,7 +605,7 @@ Blockly.FieldColour.prototype.dropdownDispose_ = function() {
|
||||
/**
|
||||
* CSS for colour picker. See css.js for use.
|
||||
*/
|
||||
Blockly.Css.register([
|
||||
Css.register([
|
||||
/* eslint-disable indent */
|
||||
'.blocklyColourTable {',
|
||||
'border-collapse: collapse;',
|
||||
@@ -637,4 +638,6 @@ Blockly.Css.register([
|
||||
/* eslint-enable indent */
|
||||
]);
|
||||
|
||||
Blockly.fieldRegistry.register('field_colour', Blockly.FieldColour);
|
||||
fieldRegistry.register('field_colour', FieldColour);
|
||||
|
||||
exports = FieldColour;
|
||||
|
||||
@@ -12,21 +12,22 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.FieldDropdown');
|
||||
goog.module('Blockly.FieldDropdown');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.DropDownDiv');
|
||||
goog.require('Blockly.Field');
|
||||
goog.require('Blockly.fieldRegistry');
|
||||
goog.require('Blockly.Menu');
|
||||
goog.require('Blockly.MenuItem');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.aria');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.utils.string');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
goog.require('Blockly.utils.userAgent');
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
const DropDownDiv = goog.require('Blockly.DropDownDiv');
|
||||
const Field = goog.require('Blockly.Field');
|
||||
const Menu = goog.require('Blockly.Menu');
|
||||
const MenuItem = goog.require('Blockly.MenuItem');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
const aria = goog.require('Blockly.utils.aria');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
||||
const userAgent = goog.require('Blockly.utils.userAgent');
|
||||
const {commonWordPrefix, commonWordSuffix, shortestStringLength} = goog.require('Blockly.utils.string');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
const {replaceMessageReferences} = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
@@ -38,22 +39,23 @@ goog.require('Blockly.utils.userAgent');
|
||||
* option & returns a validated language-neutral dropdown option, or null to
|
||||
* abort the change.
|
||||
* @param {Object=} opt_config A map of options used to configure the field.
|
||||
* See the [field creation documentation]{@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/dropdown#creation}
|
||||
* See the [field creation documentation]{@link
|
||||
* https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/dropdown#creation}
|
||||
* for a list of properties this parameter supports.
|
||||
* @extends {Blockly.Field}
|
||||
* @extends {Field}
|
||||
* @constructor
|
||||
* @throws {TypeError} If `menuGenerator` options are incorrectly structured.
|
||||
*/
|
||||
Blockly.FieldDropdown = function(menuGenerator, opt_validator, opt_config) {
|
||||
const FieldDropdown = function(menuGenerator, opt_validator, opt_config) {
|
||||
if (typeof menuGenerator != 'function') {
|
||||
Blockly.FieldDropdown.validateOptions_(menuGenerator);
|
||||
validateOptions(menuGenerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of options for a dropdown list,
|
||||
* or a function which generates these options.
|
||||
* @type {(!Array<!Array>|
|
||||
* !function(this:Blockly.FieldDropdown): !Array<!Array>)}
|
||||
* !function(this:FieldDropdown): !Array<!Array>)}
|
||||
* @protected
|
||||
*/
|
||||
this.menuGenerator_ = menuGenerator;
|
||||
@@ -90,19 +92,19 @@ Blockly.FieldDropdown = function(menuGenerator, opt_validator, opt_config) {
|
||||
this.selectedOption_ = this.getOptions(false)[0];
|
||||
|
||||
// Call parent's constructor.
|
||||
Blockly.FieldDropdown.superClass_.constructor.call(
|
||||
FieldDropdown.superClass_.constructor.call(
|
||||
this, this.selectedOption_[1], opt_validator, opt_config);
|
||||
|
||||
/**
|
||||
* A reference to the currently selected menu item.
|
||||
* @type {?Blockly.MenuItem}
|
||||
* @type {?MenuItem}
|
||||
* @private
|
||||
*/
|
||||
this.selectedMenuItem_ = null;
|
||||
|
||||
/**
|
||||
* The dropdown menu.
|
||||
* @type {?Blockly.Menu}
|
||||
* @type {?Menu}
|
||||
* @protected
|
||||
*/
|
||||
this.menu_ = null;
|
||||
@@ -128,27 +130,27 @@ Blockly.FieldDropdown = function(menuGenerator, opt_validator, opt_config) {
|
||||
*/
|
||||
this.svgArrow_ = null;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.FieldDropdown, Blockly.Field);
|
||||
inherits(FieldDropdown, Field);
|
||||
|
||||
/**
|
||||
* Dropdown image properties.
|
||||
* @typedef {{
|
||||
* src:string,
|
||||
* alt:string,
|
||||
* width:number,
|
||||
* height:number
|
||||
* }}
|
||||
*/
|
||||
Blockly.FieldDropdown.ImageProperties;
|
||||
* src:string,
|
||||
* alt:string,
|
||||
* width:number,
|
||||
* height:number
|
||||
* }}
|
||||
*/
|
||||
FieldDropdown.ImageProperties;
|
||||
|
||||
/**
|
||||
* Construct a FieldDropdown from a JSON arg object.
|
||||
* @param {!Object} options A JSON object with options (options).
|
||||
* @return {!Blockly.FieldDropdown} The new field instance.
|
||||
* @return {!FieldDropdown} The new field instance.
|
||||
* @package
|
||||
* @nocollapse
|
||||
*/
|
||||
Blockly.FieldDropdown.fromJson = function(options) {
|
||||
FieldDropdown.fromJson = function(options) {
|
||||
// `this` might be a subclass of FieldDropdown if that class doesn't override
|
||||
// the static fromJson method.
|
||||
return new this(options['options'], undefined, options);
|
||||
@@ -161,7 +163,7 @@ Blockly.FieldDropdown.fromJson = function(options) {
|
||||
* field's state.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.fromXml = function(fieldElement) {
|
||||
FieldDropdown.prototype.fromXml = function(fieldElement) {
|
||||
if (this.isOptionListDynamic()) {
|
||||
this.getOptions(false);
|
||||
}
|
||||
@@ -173,52 +175,48 @@ Blockly.FieldDropdown.prototype.fromXml = function(fieldElement) {
|
||||
* are not. Editable fields should also be serializable.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.SERIALIZABLE = true;
|
||||
FieldDropdown.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Horizontal distance that a checkmark overhangs the dropdown.
|
||||
*/
|
||||
Blockly.FieldDropdown.CHECKMARK_OVERHANG = 25;
|
||||
FieldDropdown.CHECKMARK_OVERHANG = 25;
|
||||
|
||||
/**
|
||||
* Maximum height of the dropdown menu, as a percentage of the viewport height.
|
||||
*/
|
||||
Blockly.FieldDropdown.MAX_MENU_HEIGHT_VH = 0.45;
|
||||
FieldDropdown.MAX_MENU_HEIGHT_VH = 0.45;
|
||||
|
||||
/**
|
||||
* The y offset from the top of the field to the top of the image, if an image
|
||||
* is selected.
|
||||
* @type {number}
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldDropdown.IMAGE_Y_OFFSET = 5;
|
||||
const IMAGE_Y_OFFSET = 5;
|
||||
|
||||
/**
|
||||
* The total vertical padding above and below an image.
|
||||
* @type {number}
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldDropdown.IMAGE_Y_PADDING =
|
||||
Blockly.FieldDropdown.IMAGE_Y_OFFSET * 2;
|
||||
const IMAGE_Y_PADDING = IMAGE_Y_OFFSET * 2;
|
||||
|
||||
/**
|
||||
* Android can't (in 2014) display "▾", so use "▼" instead.
|
||||
*/
|
||||
Blockly.FieldDropdown.ARROW_CHAR =
|
||||
Blockly.utils.userAgent.ANDROID ? '\u25BC' : '\u25BE';
|
||||
FieldDropdown.ARROW_CHAR = userAgent.ANDROID ? '\u25BC' : '\u25BE';
|
||||
|
||||
/**
|
||||
* Mouse cursor style when over the hotspot that initiates the editor.
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.CURSOR = 'default';
|
||||
FieldDropdown.prototype.CURSOR = 'default';
|
||||
|
||||
/**
|
||||
* Create the block UI for this dropdown.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.initView = function() {
|
||||
FieldDropdown.prototype.initView = function() {
|
||||
if (this.shouldAddBorderRect_()) {
|
||||
this.createBorderRect_();
|
||||
} else {
|
||||
@@ -226,8 +224,7 @@ Blockly.FieldDropdown.prototype.initView = function() {
|
||||
}
|
||||
this.createTextElement_();
|
||||
|
||||
this.imageElement_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.IMAGE, {}, this.fieldGroup_);
|
||||
this.imageElement_ = dom.createSvgElement(Svg.IMAGE, {}, this.fieldGroup_);
|
||||
|
||||
if (this.getConstants().FIELD_DROPDOWN_SVG_ARROW) {
|
||||
this.createSVGArrow_();
|
||||
@@ -236,7 +233,7 @@ Blockly.FieldDropdown.prototype.initView = function() {
|
||||
}
|
||||
|
||||
if (this.borderRect_) {
|
||||
Blockly.utils.dom.addClass(this.borderRect_, 'blocklyDropdownRect');
|
||||
dom.addClass(this.borderRect_, 'blocklyDropdownRect');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -245,23 +242,21 @@ Blockly.FieldDropdown.prototype.initView = function() {
|
||||
* @return {boolean} True if the dropdown field should add a border rect.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.shouldAddBorderRect_ = function() {
|
||||
FieldDropdown.prototype.shouldAddBorderRect_ = function() {
|
||||
return !this.getConstants().FIELD_DROPDOWN_NO_BORDER_RECT_SHADOW ||
|
||||
(this.getConstants().FIELD_DROPDOWN_NO_BORDER_RECT_SHADOW &&
|
||||
!this.sourceBlock_.isShadow());
|
||||
!this.sourceBlock_.isShadow());
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a tspan based arrow.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.createTextArrow_ = function() {
|
||||
this.arrow_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.TSPAN, {}, this.textElement_);
|
||||
FieldDropdown.prototype.createTextArrow_ = function() {
|
||||
this.arrow_ = dom.createSvgElement(Svg.TSPAN, {}, this.textElement_);
|
||||
this.arrow_.appendChild(document.createTextNode(
|
||||
this.sourceBlock_.RTL ?
|
||||
Blockly.FieldDropdown.ARROW_CHAR + ' ' :
|
||||
' ' + Blockly.FieldDropdown.ARROW_CHAR));
|
||||
this.sourceBlock_.RTL ? FieldDropdown.ARROW_CHAR + ' ' :
|
||||
' ' + FieldDropdown.ARROW_CHAR));
|
||||
if (this.sourceBlock_.RTL) {
|
||||
this.textElement_.insertBefore(this.arrow_, this.textContent_);
|
||||
} else {
|
||||
@@ -273,13 +268,15 @@ Blockly.FieldDropdown.prototype.createTextArrow_ = function() {
|
||||
* Create an SVG based arrow.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.createSVGArrow_ = function() {
|
||||
this.svgArrow_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.IMAGE, {
|
||||
FieldDropdown.prototype.createSVGArrow_ = function() {
|
||||
this.svgArrow_ = dom.createSvgElement(
|
||||
Svg.IMAGE, {
|
||||
'height': this.getConstants().FIELD_DROPDOWN_SVG_ARROW_SIZE + 'px',
|
||||
'width': this.getConstants().FIELD_DROPDOWN_SVG_ARROW_SIZE + 'px'
|
||||
}, this.fieldGroup_);
|
||||
this.svgArrow_.setAttributeNS(Blockly.utils.dom.XLINK_NS, 'xlink:href',
|
||||
},
|
||||
this.fieldGroup_);
|
||||
this.svgArrow_.setAttributeNS(
|
||||
dom.XLINK_NS, 'xlink:href',
|
||||
this.getConstants().FIELD_DROPDOWN_SVG_ARROW_DATAURI);
|
||||
};
|
||||
|
||||
@@ -289,31 +286,29 @@ Blockly.FieldDropdown.prototype.createSVGArrow_ = function() {
|
||||
* or undefined if triggered programmatically.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.showEditor_ = function(opt_e) {
|
||||
FieldDropdown.prototype.showEditor_ = function(opt_e) {
|
||||
this.dropdownCreate_();
|
||||
if (opt_e && typeof opt_e.clientX === 'number') {
|
||||
this.menu_.openingCoords =
|
||||
new Blockly.utils.Coordinate(opt_e.clientX, opt_e.clientY);
|
||||
this.menu_.openingCoords = new Coordinate(opt_e.clientX, opt_e.clientY);
|
||||
} else {
|
||||
this.menu_.openingCoords = null;
|
||||
}
|
||||
// Element gets created in render.
|
||||
this.menu_.render(Blockly.DropDownDiv.getContentDiv());
|
||||
var menuElement = /** @type {!Element} */ (this.menu_.getElement());
|
||||
Blockly.utils.dom.addClass(menuElement, 'blocklyDropdownMenu');
|
||||
this.menu_.render(DropDownDiv.getContentDiv());
|
||||
const menuElement = /** @type {!Element} */ (this.menu_.getElement());
|
||||
dom.addClass(menuElement, 'blocklyDropdownMenu');
|
||||
|
||||
if (this.getConstants().FIELD_DROPDOWN_COLOURED_DIV) {
|
||||
var primaryColour = (this.sourceBlock_.isShadow()) ?
|
||||
const primaryColour = (this.sourceBlock_.isShadow()) ?
|
||||
this.sourceBlock_.getParent().getColour() :
|
||||
this.sourceBlock_.getColour();
|
||||
var borderColour = (this.sourceBlock_.isShadow()) ?
|
||||
const borderColour = (this.sourceBlock_.isShadow()) ?
|
||||
this.sourceBlock_.getParent().style.colourTertiary :
|
||||
this.sourceBlock_.style.colourTertiary;
|
||||
Blockly.DropDownDiv.setColour(primaryColour, borderColour);
|
||||
DropDownDiv.setColour(primaryColour, borderColour);
|
||||
}
|
||||
|
||||
Blockly.DropDownDiv.showPositionedByField(
|
||||
this, this.dropdownDispose_.bind(this));
|
||||
DropDownDiv.showPositionedByField(this, this.dropdownDispose_.bind(this));
|
||||
|
||||
// Focusing needs to be handled after the menu is rendered and positioned.
|
||||
// Otherwise it will cause a page scroll to get the misplaced menu in
|
||||
@@ -331,25 +326,25 @@ Blockly.FieldDropdown.prototype.showEditor_ = function(opt_e) {
|
||||
* Create the dropdown editor.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.dropdownCreate_ = function() {
|
||||
var menu = new Blockly.Menu();
|
||||
menu.setRole(Blockly.utils.aria.Role.LISTBOX);
|
||||
FieldDropdown.prototype.dropdownCreate_ = function() {
|
||||
const menu = new Menu();
|
||||
menu.setRole(aria.Role.LISTBOX);
|
||||
this.menu_ = menu;
|
||||
|
||||
var options = this.getOptions(false);
|
||||
const options = this.getOptions(false);
|
||||
this.selectedMenuItem_ = null;
|
||||
for (var i = 0; i < options.length; i++) {
|
||||
var content = options[i][0]; // Human-readable text or image.
|
||||
var value = options[i][1]; // Language-neutral value.
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
let content = options[i][0]; // Human-readable text or image.
|
||||
const value = options[i][1]; // Language-neutral value.
|
||||
if (typeof content == 'object') {
|
||||
// An image, not text.
|
||||
var image = new Image(content['width'], content['height']);
|
||||
const image = new Image(content['width'], content['height']);
|
||||
image.src = content['src'];
|
||||
image.alt = content['alt'] || '';
|
||||
content = image;
|
||||
}
|
||||
var menuItem = new Blockly.MenuItem(content, value);
|
||||
menuItem.setRole(Blockly.utils.aria.Role.OPTION);
|
||||
const menuItem = new MenuItem(content, value);
|
||||
menuItem.setRole(aria.Role.OPTION);
|
||||
menuItem.setRightToLeft(this.sourceBlock_.RTL);
|
||||
menuItem.setCheckable(true);
|
||||
menu.addChild(menuItem);
|
||||
@@ -365,7 +360,7 @@ Blockly.FieldDropdown.prototype.dropdownCreate_ = function() {
|
||||
* Disposes of events and DOM-references belonging to the dropdown editor.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.dropdownDispose_ = function() {
|
||||
FieldDropdown.prototype.dropdownDispose_ = function() {
|
||||
if (this.menu_) {
|
||||
this.menu_.dispose();
|
||||
}
|
||||
@@ -376,21 +371,21 @@ Blockly.FieldDropdown.prototype.dropdownDispose_ = function() {
|
||||
|
||||
/**
|
||||
* Handle an action in the dropdown menu.
|
||||
* @param {!Blockly.MenuItem} menuItem The MenuItem selected within menu.
|
||||
* @param {!MenuItem} menuItem The MenuItem selected within menu.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.handleMenuActionEvent_ = function(menuItem) {
|
||||
Blockly.DropDownDiv.hideIfOwner(this, true);
|
||||
this.onItemSelected_(/** @type {!Blockly.Menu} */ (this.menu_), menuItem);
|
||||
FieldDropdown.prototype.handleMenuActionEvent_ = function(menuItem) {
|
||||
DropDownDiv.hideIfOwner(this, true);
|
||||
this.onItemSelected_(/** @type {!Menu} */ (this.menu_), menuItem);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle the selection of an item in the dropdown menu.
|
||||
* @param {!Blockly.Menu} menu The Menu component clicked.
|
||||
* @param {!Blockly.MenuItem} menuItem The MenuItem selected within menu.
|
||||
* @param {!Menu} menu The Menu component clicked.
|
||||
* @param {!MenuItem} menuItem The MenuItem selected within menu.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.onItemSelected_ = function(menu, menuItem) {
|
||||
FieldDropdown.prototype.onItemSelected_ = function(menu, menuItem) {
|
||||
this.setValue(menuItem.getValue());
|
||||
};
|
||||
|
||||
@@ -399,21 +394,21 @@ Blockly.FieldDropdown.prototype.onItemSelected_ = function(menu, menuItem) {
|
||||
* Create prefix and/or suffix labels.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.trimOptions_ = function() {
|
||||
var options = this.menuGenerator_;
|
||||
FieldDropdown.prototype.trimOptions_ = function() {
|
||||
const options = this.menuGenerator_;
|
||||
if (!Array.isArray(options)) {
|
||||
return;
|
||||
}
|
||||
var hasImages = false;
|
||||
let hasImages = false;
|
||||
|
||||
// Localize label text and image alt text.
|
||||
for (var i = 0; i < options.length; i++) {
|
||||
var label = options[i][0];
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
const label = options[i][0];
|
||||
if (typeof label == 'string') {
|
||||
options[i][0] = Blockly.utils.replaceMessageReferences(label);
|
||||
options[i][0] = replaceMessageReferences(label);
|
||||
} else {
|
||||
if (label.alt != null) {
|
||||
options[i][0].alt = Blockly.utils.replaceMessageReferences(label.alt);
|
||||
options[i][0].alt = replaceMessageReferences(label.alt);
|
||||
}
|
||||
hasImages = true;
|
||||
}
|
||||
@@ -421,13 +416,13 @@ Blockly.FieldDropdown.prototype.trimOptions_ = function() {
|
||||
if (hasImages || options.length < 2) {
|
||||
return; // Do nothing if too few items or at least one label is an image.
|
||||
}
|
||||
var strings = [];
|
||||
for (var i = 0; i < options.length; i++) {
|
||||
const strings = [];
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
strings.push(options[i][0]);
|
||||
}
|
||||
var shortest = Blockly.utils.string.shortestStringLength(strings);
|
||||
var prefixLength = Blockly.utils.string.commonWordPrefix(strings, shortest);
|
||||
var suffixLength = Blockly.utils.string.commonWordSuffix(strings, shortest);
|
||||
const shortest = shortestStringLength(strings);
|
||||
const prefixLength = commonWordPrefix(strings, shortest);
|
||||
const suffixLength = commonWordSuffix(strings, shortest);
|
||||
if (!prefixLength && !suffixLength) {
|
||||
return;
|
||||
}
|
||||
@@ -442,8 +437,8 @@ Blockly.FieldDropdown.prototype.trimOptions_ = function() {
|
||||
this.suffixField = strings[0].substr(1 - suffixLength);
|
||||
}
|
||||
|
||||
this.menuGenerator_ = Blockly.FieldDropdown.applyTrim_(options, prefixLength,
|
||||
suffixLength);
|
||||
this.menuGenerator_ =
|
||||
FieldDropdown.applyTrim_(options, prefixLength, suffixLength);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -455,13 +450,12 @@ Blockly.FieldDropdown.prototype.trimOptions_ = function() {
|
||||
* @param {number} suffixLength The length of the common suffix
|
||||
* @return {!Array<!Array>} A new array with all of the option text trimmed.
|
||||
*/
|
||||
Blockly.FieldDropdown.applyTrim_ = function(options,
|
||||
prefixLength, suffixLength) {
|
||||
var newOptions = [];
|
||||
FieldDropdown.applyTrim_ = function(options, prefixLength, suffixLength) {
|
||||
const newOptions = [];
|
||||
// Remove the prefix and suffix from the options.
|
||||
for (var i = 0; i < options.length; i++) {
|
||||
var text = options[i][0];
|
||||
var value = options[i][1];
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
let text = options[i][0];
|
||||
const value = options[i][1];
|
||||
text = text.substring(prefixLength, text.length - suffixLength);
|
||||
newOptions[i] = [text, value];
|
||||
}
|
||||
@@ -472,7 +466,7 @@ Blockly.FieldDropdown.applyTrim_ = function(options,
|
||||
* @return {boolean} True if the option list is generated by a function.
|
||||
* Otherwise false.
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.isOptionListDynamic = function() {
|
||||
FieldDropdown.prototype.isOptionListDynamic = function() {
|
||||
return typeof this.menuGenerator_ == 'function';
|
||||
};
|
||||
|
||||
@@ -484,11 +478,11 @@ Blockly.FieldDropdown.prototype.isOptionListDynamic = function() {
|
||||
* (human-readable text or image, language-neutral name).
|
||||
* @throws {TypeError} If generated options are incorrectly structured.
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.getOptions = function(opt_useCache) {
|
||||
FieldDropdown.prototype.getOptions = function(opt_useCache) {
|
||||
if (this.isOptionListDynamic()) {
|
||||
if (!this.generatedOptions_ || !opt_useCache) {
|
||||
this.generatedOptions_ = this.menuGenerator_.call(this);
|
||||
Blockly.FieldDropdown.validateOptions_(this.generatedOptions_);
|
||||
validateOptions(this.generatedOptions_);
|
||||
}
|
||||
return this.generatedOptions_;
|
||||
}
|
||||
@@ -501,10 +495,10 @@ Blockly.FieldDropdown.prototype.getOptions = function(opt_useCache) {
|
||||
* @return {?string} A valid language-neutral option, or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
var isValueValid = false;
|
||||
var options = this.getOptions(true);
|
||||
for (var i = 0, option; (option = options[i]); i++) {
|
||||
FieldDropdown.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
let isValueValid = false;
|
||||
const options = this.getOptions(true);
|
||||
for (let i = 0, option; (option = options[i]); i++) {
|
||||
// Options are tuples of human-readable text and language-neutral values.
|
||||
if (option[1] == opt_newValue) {
|
||||
isValueValid = true;
|
||||
@@ -513,9 +507,10 @@ Blockly.FieldDropdown.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
}
|
||||
if (!isValueValid) {
|
||||
if (this.sourceBlock_) {
|
||||
console.warn('Cannot set the dropdown\'s value to an unavailable option.' +
|
||||
' Block type: ' + this.sourceBlock_.type + ', Field name: ' + this.name +
|
||||
', Value: ' + opt_newValue);
|
||||
console.warn(
|
||||
'Cannot set the dropdown\'s value to an unavailable option.' +
|
||||
' Block type: ' + this.sourceBlock_.type +
|
||||
', Field name: ' + this.name + ', Value: ' + opt_newValue);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -528,10 +523,10 @@ Blockly.FieldDropdown.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
* that this is one of the valid dropdown options.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.doValueUpdate_ = function(newValue) {
|
||||
Blockly.FieldDropdown.superClass_.doValueUpdate_.call(this, newValue);
|
||||
var options = this.getOptions(true);
|
||||
for (var i = 0, option; (option = options[i]); i++) {
|
||||
FieldDropdown.prototype.doValueUpdate_ = function(newValue) {
|
||||
FieldDropdown.superClass_.doValueUpdate_.call(this, newValue);
|
||||
const options = this.getOptions(true);
|
||||
for (let i = 0, option; (option = options[i]); i++) {
|
||||
if (option[1] == this.value_) {
|
||||
this.selectedOption_ = option;
|
||||
}
|
||||
@@ -542,13 +537,13 @@ Blockly.FieldDropdown.prototype.doValueUpdate_ = function(newValue) {
|
||||
* Updates the dropdown arrow to match the colour/style of the block.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.applyColour = function() {
|
||||
FieldDropdown.prototype.applyColour = function() {
|
||||
if (this.borderRect_) {
|
||||
this.borderRect_.setAttribute('stroke',
|
||||
this.sourceBlock_.style.colourTertiary);
|
||||
this.borderRect_.setAttribute(
|
||||
'stroke', this.sourceBlock_.style.colourTertiary);
|
||||
if (this.menu_) {
|
||||
this.borderRect_.setAttribute('fill',
|
||||
this.sourceBlock_.style.colourTertiary);
|
||||
this.borderRect_.setAttribute(
|
||||
'fill', this.sourceBlock_.style.colourTertiary);
|
||||
} else {
|
||||
this.borderRect_.setAttribute('fill', 'transparent');
|
||||
}
|
||||
@@ -567,16 +562,16 @@ Blockly.FieldDropdown.prototype.applyColour = function() {
|
||||
* Draws the border with the correct width.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.render_ = function() {
|
||||
FieldDropdown.prototype.render_ = function() {
|
||||
// Hide both elements.
|
||||
this.textContent_.nodeValue = '';
|
||||
this.imageElement_.style.display = 'none';
|
||||
|
||||
// Show correct element.
|
||||
var option = this.selectedOption_ && this.selectedOption_[0];
|
||||
const option = this.selectedOption_ && this.selectedOption_[0];
|
||||
if (option && typeof option == 'object') {
|
||||
this.renderSelectedImage_(
|
||||
/** @type {!Blockly.FieldDropdown.ImageProperties} */ (option));
|
||||
/** @type {!FieldDropdown.ImageProperties} */ (option));
|
||||
} else {
|
||||
this.renderSelectedText_();
|
||||
}
|
||||
@@ -586,32 +581,33 @@ Blockly.FieldDropdown.prototype.render_ = function() {
|
||||
|
||||
/**
|
||||
* Renders the selected option, which must be an image.
|
||||
* @param {!Blockly.FieldDropdown.ImageProperties} imageJson Selected
|
||||
* @param {!FieldDropdown.ImageProperties} imageJson Selected
|
||||
* option that must be an image.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.renderSelectedImage_ = function(imageJson) {
|
||||
FieldDropdown.prototype.renderSelectedImage_ = function(imageJson) {
|
||||
this.imageElement_.style.display = '';
|
||||
this.imageElement_.setAttributeNS(
|
||||
Blockly.utils.dom.XLINK_NS, 'xlink:href', imageJson.src);
|
||||
this.imageElement_.setAttributeNS(dom.XLINK_NS, 'xlink:href', imageJson.src);
|
||||
this.imageElement_.setAttribute('height', imageJson.height);
|
||||
this.imageElement_.setAttribute('width', imageJson.width);
|
||||
|
||||
var imageHeight = Number(imageJson.height);
|
||||
var imageWidth = Number(imageJson.width);
|
||||
const imageHeight = Number(imageJson.height);
|
||||
const imageWidth = Number(imageJson.width);
|
||||
|
||||
// Height and width include the border rect.
|
||||
var hasBorder = !!this.borderRect_;
|
||||
var height = Math.max(
|
||||
const hasBorder = !!this.borderRect_;
|
||||
const height = Math.max(
|
||||
hasBorder ? this.getConstants().FIELD_DROPDOWN_BORDER_RECT_HEIGHT : 0,
|
||||
imageHeight + Blockly.FieldDropdown.IMAGE_Y_PADDING);
|
||||
var xPadding = hasBorder ? this.getConstants().FIELD_BORDER_RECT_X_PADDING : 0;
|
||||
var arrowWidth = 0;
|
||||
imageHeight + IMAGE_Y_PADDING);
|
||||
const xPadding =
|
||||
hasBorder ? this.getConstants().FIELD_BORDER_RECT_X_PADDING : 0;
|
||||
let arrowWidth = 0;
|
||||
if (this.svgArrow_) {
|
||||
arrowWidth = this.positionSVGArrow_(imageWidth + xPadding, height / 2 -
|
||||
this.getConstants().FIELD_DROPDOWN_SVG_ARROW_SIZE / 2);
|
||||
arrowWidth = this.positionSVGArrow_(
|
||||
imageWidth + xPadding,
|
||||
height / 2 - this.getConstants().FIELD_DROPDOWN_SVG_ARROW_SIZE / 2);
|
||||
} else {
|
||||
arrowWidth = Blockly.utils.dom.getFastTextWidth(
|
||||
arrowWidth = dom.getFastTextWidth(
|
||||
/** @type {!SVGTSpanElement} */ (this.arrow_),
|
||||
this.getConstants().FIELD_TEXT_FONTSIZE,
|
||||
this.getConstants().FIELD_TEXT_FONTWEIGHT,
|
||||
@@ -620,9 +616,9 @@ Blockly.FieldDropdown.prototype.renderSelectedImage_ = function(imageJson) {
|
||||
this.size_.width = imageWidth + arrowWidth + xPadding * 2;
|
||||
this.size_.height = height;
|
||||
|
||||
var arrowX = 0;
|
||||
let arrowX = 0;
|
||||
if (this.sourceBlock_.RTL) {
|
||||
var imageX = xPadding + arrowWidth;
|
||||
const imageX = xPadding + arrowWidth;
|
||||
this.imageElement_.setAttribute('x', imageX);
|
||||
} else {
|
||||
arrowX = imageWidth + arrowWidth;
|
||||
@@ -638,27 +634,29 @@ Blockly.FieldDropdown.prototype.renderSelectedImage_ = function(imageJson) {
|
||||
* Renders the selected option, which must be text.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.renderSelectedText_ = function() {
|
||||
FieldDropdown.prototype.renderSelectedText_ = function() {
|
||||
// Retrieves the selected option to display through getText_.
|
||||
this.textContent_.nodeValue = this.getDisplayText_();
|
||||
Blockly.utils.dom.addClass(/** @type {!Element} */ (this.textElement_),
|
||||
'blocklyDropdownText');
|
||||
dom.addClass(
|
||||
/** @type {!Element} */ (this.textElement_), 'blocklyDropdownText');
|
||||
this.textElement_.setAttribute('text-anchor', 'start');
|
||||
|
||||
// Height and width include the border rect.
|
||||
var hasBorder = !!this.borderRect_;
|
||||
var height = Math.max(
|
||||
const hasBorder = !!this.borderRect_;
|
||||
const height = Math.max(
|
||||
hasBorder ? this.getConstants().FIELD_DROPDOWN_BORDER_RECT_HEIGHT : 0,
|
||||
this.getConstants().FIELD_TEXT_HEIGHT);
|
||||
var textWidth = Blockly.utils.dom.getFastTextWidth(this.textElement_,
|
||||
this.getConstants().FIELD_TEXT_FONTSIZE,
|
||||
const textWidth = dom.getFastTextWidth(
|
||||
this.textElement_, this.getConstants().FIELD_TEXT_FONTSIZE,
|
||||
this.getConstants().FIELD_TEXT_FONTWEIGHT,
|
||||
this.getConstants().FIELD_TEXT_FONTFAMILY);
|
||||
var xPadding = hasBorder ? this.getConstants().FIELD_BORDER_RECT_X_PADDING : 0;
|
||||
var arrowWidth = 0;
|
||||
const xPadding =
|
||||
hasBorder ? this.getConstants().FIELD_BORDER_RECT_X_PADDING : 0;
|
||||
let arrowWidth = 0;
|
||||
if (this.svgArrow_) {
|
||||
arrowWidth = this.positionSVGArrow_(textWidth + xPadding, height / 2 -
|
||||
this.getConstants().FIELD_DROPDOWN_SVG_ARROW_SIZE / 2);
|
||||
arrowWidth = this.positionSVGArrow_(
|
||||
textWidth + xPadding,
|
||||
height / 2 - this.getConstants().FIELD_DROPDOWN_SVG_ARROW_SIZE / 2);
|
||||
}
|
||||
this.size_.width = textWidth + arrowWidth + xPadding * 2;
|
||||
this.size_.height = height;
|
||||
@@ -673,17 +671,18 @@ Blockly.FieldDropdown.prototype.renderSelectedText_ = function() {
|
||||
* @return {number} Amount of space the arrow is taking up, in px.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.positionSVGArrow_ = function(x, y) {
|
||||
FieldDropdown.prototype.positionSVGArrow_ = function(x, y) {
|
||||
if (!this.svgArrow_) {
|
||||
return 0;
|
||||
}
|
||||
var hasBorder = !!this.borderRect_;
|
||||
var xPadding = hasBorder ? this.getConstants().FIELD_BORDER_RECT_X_PADDING : 0;
|
||||
var textPadding = this.getConstants().FIELD_DROPDOWN_SVG_ARROW_PADDING;
|
||||
var svgArrowSize = this.getConstants().FIELD_DROPDOWN_SVG_ARROW_SIZE;
|
||||
var arrowX = this.sourceBlock_.RTL ? xPadding : x + textPadding;
|
||||
this.svgArrow_.setAttribute('transform',
|
||||
'translate(' + arrowX + ',' + y + ')');
|
||||
const hasBorder = !!this.borderRect_;
|
||||
const xPadding =
|
||||
hasBorder ? this.getConstants().FIELD_BORDER_RECT_X_PADDING : 0;
|
||||
const textPadding = this.getConstants().FIELD_DROPDOWN_SVG_ARROW_PADDING;
|
||||
const svgArrowSize = this.getConstants().FIELD_DROPDOWN_SVG_ARROW_SIZE;
|
||||
const arrowX = this.sourceBlock_.RTL ? xPadding : x + textPadding;
|
||||
this.svgArrow_.setAttribute(
|
||||
'transform', 'translate(' + arrowX + ',' + y + ')');
|
||||
return svgArrowSize + textPadding;
|
||||
};
|
||||
|
||||
@@ -695,11 +694,11 @@ Blockly.FieldDropdown.prototype.positionSVGArrow_ = function(x, y) {
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.getText_ = function() {
|
||||
FieldDropdown.prototype.getText_ = function() {
|
||||
if (!this.selectedOption_) {
|
||||
return null;
|
||||
}
|
||||
var option = this.selectedOption_[0];
|
||||
const option = this.selectedOption_[0];
|
||||
if (typeof option == 'object') {
|
||||
return option['alt'];
|
||||
}
|
||||
@@ -710,35 +709,36 @@ Blockly.FieldDropdown.prototype.getText_ = function() {
|
||||
* 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.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldDropdown.validateOptions_ = function(options) {
|
||||
const validateOptions = function(options) {
|
||||
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.');
|
||||
}
|
||||
var foundError = false;
|
||||
for (var i = 0; i < options.length; ++i) {
|
||||
var tuple = options[i];
|
||||
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);
|
||||
'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')) {
|
||||
'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: ',
|
||||
'string label or image description. Found' + tuple[0] + ' in: ',
|
||||
tuple);
|
||||
}
|
||||
}
|
||||
@@ -747,4 +747,6 @@ Blockly.FieldDropdown.validateOptions_ = function(options) {
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.fieldRegistry.register('field_dropdown', Blockly.FieldDropdown);
|
||||
fieldRegistry.register('field_dropdown', FieldDropdown);
|
||||
|
||||
exports = FieldDropdown;
|
||||
|
||||
@@ -10,15 +10,16 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.FieldImage');
|
||||
goog.module('Blockly.FieldImage');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Field');
|
||||
goog.require('Blockly.fieldRegistry');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.utils.Size');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
const Field = goog.require('Blockly.Field');
|
||||
const Size = goog.require('Blockly.utils.Size');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
||||
const {createSvgElement, XLINK_NS} = goog.require('Blockly.utils.dom');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
const {replaceMessageReferences} = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
@@ -27,32 +28,35 @@ goog.require('Blockly.utils.Svg');
|
||||
* @param {!(string|number)} width Width of the image.
|
||||
* @param {!(string|number)} height Height of the image.
|
||||
* @param {string=} opt_alt Optional alt text for when block is collapsed.
|
||||
* @param {function(!Blockly.FieldImage)=} opt_onClick Optional function to be
|
||||
* @param {function(!FieldImage)=} opt_onClick Optional function to be
|
||||
* called when the image is clicked. If opt_onClick is defined, opt_alt must
|
||||
* also be defined.
|
||||
* @param {boolean=} opt_flipRtl Whether to flip the icon in RTL.
|
||||
* @param {Object=} opt_config A map of options used to configure the field.
|
||||
* See the [field creation documentation]{@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/image#creation}
|
||||
* See the [field creation documentation]{@link
|
||||
* https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/image#creation}
|
||||
* for a list of properties this parameter supports.
|
||||
* @extends {Blockly.Field}
|
||||
* @extends {Field}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldImage = function(src, width, height,
|
||||
opt_alt, opt_onClick, opt_flipRtl, opt_config) {
|
||||
const FieldImage = function(
|
||||
src, width, height, opt_alt, opt_onClick, opt_flipRtl, opt_config) {
|
||||
// Return early.
|
||||
if (!src) {
|
||||
throw Error('Src value of an image field is required');
|
||||
}
|
||||
src = Blockly.utils.replaceMessageReferences(src);
|
||||
var imageHeight = Number(Blockly.utils.replaceMessageReferences(height));
|
||||
var imageWidth = Number(Blockly.utils.replaceMessageReferences(width));
|
||||
src = replaceMessageReferences(src);
|
||||
const imageHeight = Number(replaceMessageReferences(height));
|
||||
const imageWidth = Number(replaceMessageReferences(width));
|
||||
if (isNaN(imageHeight) || isNaN(imageWidth)) {
|
||||
throw Error('Height and width values of an image field must cast to' +
|
||||
' numbers.');
|
||||
throw Error(
|
||||
'Height and width values of an image field must cast to' +
|
||||
' numbers.');
|
||||
}
|
||||
if (imageHeight <= 0 || imageWidth <= 0) {
|
||||
throw Error('Height and width values of an image field must be greater' +
|
||||
' than 0.');
|
||||
throw Error(
|
||||
'Height and width values of an image field must be greater' +
|
||||
' than 0.');
|
||||
}
|
||||
|
||||
// Initialize configurable properties.
|
||||
@@ -70,23 +74,21 @@ Blockly.FieldImage = function(src, width, height,
|
||||
*/
|
||||
this.altText_ = '';
|
||||
|
||||
Blockly.FieldImage.superClass_.constructor.call(
|
||||
this, src, null, opt_config);
|
||||
FieldImage.superClass_.constructor.call(this, src, null, opt_config);
|
||||
|
||||
if (!opt_config) { // If the config wasn't passed, do old configuration.
|
||||
this.flipRtl_ = !!opt_flipRtl;
|
||||
this.altText_ = Blockly.utils.replaceMessageReferences(opt_alt) || '';
|
||||
this.altText_ = replaceMessageReferences(opt_alt) || '';
|
||||
}
|
||||
|
||||
// Initialize other properties.
|
||||
/**
|
||||
* The size of the area rendered by the field.
|
||||
* @type {Blockly.utils.Size}
|
||||
* @type {Size}
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
this.size_ = new Blockly.utils.Size(imageWidth,
|
||||
imageHeight + Blockly.FieldImage.Y_PADDING);
|
||||
this.size_ = new Size(imageWidth, imageHeight + FieldImage.Y_PADDING);
|
||||
|
||||
/**
|
||||
* Store the image height, since it is different from the field height.
|
||||
@@ -97,7 +99,7 @@ Blockly.FieldImage = function(src, width, height,
|
||||
|
||||
/**
|
||||
* The function to be called when this field is clicked.
|
||||
* @type {?function(!Blockly.FieldImage)}
|
||||
* @type {?function(!FieldImage)}
|
||||
* @private
|
||||
*/
|
||||
this.clickHandler_ = null;
|
||||
@@ -113,29 +115,30 @@ Blockly.FieldImage = function(src, width, height,
|
||||
*/
|
||||
this.imageElement_ = null;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.FieldImage, Blockly.Field);
|
||||
inherits(FieldImage, Field);
|
||||
|
||||
/**
|
||||
* The default value for this field.
|
||||
* @type {*}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldImage.prototype.DEFAULT_VALUE = '';
|
||||
FieldImage.prototype.DEFAULT_VALUE = '';
|
||||
|
||||
/**
|
||||
* Construct a FieldImage from a JSON arg object,
|
||||
* dereferencing any string table references.
|
||||
* @param {!Object} options A JSON object with options (src, width, height,
|
||||
* alt, and flipRtl).
|
||||
* @return {!Blockly.FieldImage} The new field instance.
|
||||
* @return {!FieldImage} The new field instance.
|
||||
* @package
|
||||
* @nocollapse
|
||||
*/
|
||||
Blockly.FieldImage.fromJson = function(options) {
|
||||
FieldImage.fromJson = function(options) {
|
||||
// `this` might be a subclass of FieldImage if that class doesn't override
|
||||
// the static fromJson method.
|
||||
return new this(options['src'], options['width'], options['height'],
|
||||
undefined, undefined, undefined, options);
|
||||
return new this(
|
||||
options['src'], options['width'], options['height'], undefined, undefined,
|
||||
undefined, options);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -144,14 +147,14 @@ Blockly.FieldImage.fromJson = function(options) {
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldImage.Y_PADDING = 1;
|
||||
FieldImage.Y_PADDING = 1;
|
||||
|
||||
/**
|
||||
* Editable fields usually show some sort of UI indicating they are
|
||||
* editable. This field should not.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.FieldImage.prototype.EDITABLE = false;
|
||||
FieldImage.prototype.EDITABLE = false;
|
||||
|
||||
/**
|
||||
* Used to tell if the field needs to be rendered the next time the block is
|
||||
@@ -160,7 +163,7 @@ Blockly.FieldImage.prototype.EDITABLE = false;
|
||||
* @type {boolean}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldImage.prototype.isDirty_ = false;
|
||||
FieldImage.prototype.isDirty_ = false;
|
||||
|
||||
/**
|
||||
* Configure the field based on the given map of options.
|
||||
@@ -168,27 +171,26 @@ Blockly.FieldImage.prototype.isDirty_ = false;
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldImage.prototype.configure_ = function(config) {
|
||||
Blockly.FieldImage.superClass_.configure_.call(this, config);
|
||||
FieldImage.prototype.configure_ = function(config) {
|
||||
FieldImage.superClass_.configure_.call(this, config);
|
||||
this.flipRtl_ = !!config['flipRtl'];
|
||||
this.altText_ = Blockly.utils.replaceMessageReferences(config['alt']) || '';
|
||||
this.altText_ = replaceMessageReferences(config['alt']) || '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the block UI for this image.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldImage.prototype.initView = function() {
|
||||
this.imageElement_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.IMAGE,
|
||||
{
|
||||
FieldImage.prototype.initView = function() {
|
||||
this.imageElement_ = createSvgElement(
|
||||
Svg.IMAGE, {
|
||||
'height': this.imageHeight_ + 'px',
|
||||
'width': this.size_.width + 'px',
|
||||
'alt': this.altText_
|
||||
},
|
||||
this.fieldGroup_);
|
||||
this.imageElement_.setAttributeNS(Blockly.utils.dom.XLINK_NS,
|
||||
'xlink:href', /** @type {string} */ (this.value_));
|
||||
this.imageElement_.setAttributeNS(
|
||||
XLINK_NS, 'xlink:href', /** @type {string} */ (this.value_));
|
||||
|
||||
if (this.clickHandler_) {
|
||||
this.imageElement_.style.cursor = 'pointer';
|
||||
@@ -198,7 +200,7 @@ Blockly.FieldImage.prototype.initView = function() {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldImage.prototype.updateSize_ = function() {
|
||||
FieldImage.prototype.updateSize_ = function() {
|
||||
// NOP
|
||||
};
|
||||
|
||||
@@ -208,7 +210,7 @@ Blockly.FieldImage.prototype.updateSize_ = function() {
|
||||
* @return {?string} A string, or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldImage.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
FieldImage.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
if (typeof opt_newValue != 'string') {
|
||||
return null;
|
||||
}
|
||||
@@ -221,11 +223,11 @@ Blockly.FieldImage.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
* that this is a string.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldImage.prototype.doValueUpdate_ = function(newValue) {
|
||||
FieldImage.prototype.doValueUpdate_ = function(newValue) {
|
||||
this.value_ = newValue;
|
||||
if (this.imageElement_) {
|
||||
this.imageElement_.setAttributeNS(Blockly.utils.dom.XLINK_NS,
|
||||
'xlink:href', String(this.value_));
|
||||
this.imageElement_.setAttributeNS(
|
||||
XLINK_NS, 'xlink:href', String(this.value_));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -234,7 +236,7 @@ Blockly.FieldImage.prototype.doValueUpdate_ = function(newValue) {
|
||||
* @return {boolean} True if we should flip in RTL.
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldImage.prototype.getFlipRtl = function() {
|
||||
FieldImage.prototype.getFlipRtl = function() {
|
||||
return this.flipRtl_;
|
||||
};
|
||||
|
||||
@@ -243,7 +245,7 @@ Blockly.FieldImage.prototype.getFlipRtl = function() {
|
||||
* @param {?string} alt New alt text.
|
||||
* @public
|
||||
*/
|
||||
Blockly.FieldImage.prototype.setAlt = function(alt) {
|
||||
FieldImage.prototype.setAlt = function(alt) {
|
||||
if (alt == this.altText_) {
|
||||
return;
|
||||
}
|
||||
@@ -258,7 +260,7 @@ Blockly.FieldImage.prototype.setAlt = function(alt) {
|
||||
* call the handler.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldImage.prototype.showEditor_ = function() {
|
||||
FieldImage.prototype.showEditor_ = function() {
|
||||
if (this.clickHandler_) {
|
||||
this.clickHandler_(this);
|
||||
}
|
||||
@@ -266,10 +268,10 @@ Blockly.FieldImage.prototype.showEditor_ = function() {
|
||||
|
||||
/**
|
||||
* Set the function that is called when this image is clicked.
|
||||
* @param {?function(!Blockly.FieldImage)} func The function that is called
|
||||
* @param {?function(!FieldImage)} func The function that is called
|
||||
* when the image is clicked, or null to remove.
|
||||
*/
|
||||
Blockly.FieldImage.prototype.setOnClickHandler = function(func) {
|
||||
FieldImage.prototype.setOnClickHandler = function(func) {
|
||||
this.clickHandler_ = func;
|
||||
};
|
||||
|
||||
@@ -281,8 +283,10 @@ Blockly.FieldImage.prototype.setOnClickHandler = function(func) {
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldImage.prototype.getText_ = function() {
|
||||
FieldImage.prototype.getText_ = function() {
|
||||
return this.altText_;
|
||||
};
|
||||
|
||||
Blockly.fieldRegistry.register('field_image', Blockly.FieldImage);
|
||||
fieldRegistry.register('field_image', FieldImage);
|
||||
|
||||
exports = FieldImage;
|
||||
|
||||
@@ -11,13 +11,14 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.FieldLabel');
|
||||
goog.module('Blockly.FieldLabel');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Field');
|
||||
goog.require('Blockly.fieldRegistry');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.object');
|
||||
const Field = goog.require('Blockly.Field');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
const {replaceMessageReferences} = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
@@ -26,12 +27,13 @@ goog.require('Blockly.utils.object');
|
||||
* string. Defaults to an empty string if null or undefined.
|
||||
* @param {string=} opt_class Optional CSS class for the field's text.
|
||||
* @param {Object=} opt_config A map of options used to configure the field.
|
||||
* See the [field creation documentation]{@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/label#creation}
|
||||
* See the [field creation documentation]{@link
|
||||
* https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/label#creation}
|
||||
* for a list of properties this parameter supports.
|
||||
* @extends {Blockly.Field}
|
||||
* @extends {Field}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldLabel = function(opt_value, opt_class, opt_config) {
|
||||
const FieldLabel = function(opt_value, opt_class, opt_config) {
|
||||
/**
|
||||
* The html class name to use for this field.
|
||||
* @type {?string}
|
||||
@@ -39,32 +41,31 @@ Blockly.FieldLabel = function(opt_value, opt_class, opt_config) {
|
||||
*/
|
||||
this.class_ = null;
|
||||
|
||||
Blockly.FieldLabel.superClass_.constructor.call(
|
||||
this, opt_value, null, opt_config);
|
||||
FieldLabel.superClass_.constructor.call(this, opt_value, null, opt_config);
|
||||
|
||||
if (!opt_config) { // If the config was not passed use old configuration.
|
||||
this.class_ = opt_class || null;
|
||||
}
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.FieldLabel, Blockly.Field);
|
||||
inherits(FieldLabel, Field);
|
||||
|
||||
/**
|
||||
* The default value for this field.
|
||||
* @type {*}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldLabel.prototype.DEFAULT_VALUE = '';
|
||||
FieldLabel.prototype.DEFAULT_VALUE = '';
|
||||
|
||||
/**
|
||||
* Construct a FieldLabel from a JSON arg object,
|
||||
* dereferencing any string table references.
|
||||
* @param {!Object} options A JSON object with options (text, and class).
|
||||
* @return {!Blockly.FieldLabel} The new field instance.
|
||||
* @return {!FieldLabel} The new field instance.
|
||||
* @package
|
||||
* @nocollapse
|
||||
*/
|
||||
Blockly.FieldLabel.fromJson = function(options) {
|
||||
var text = Blockly.utils.replaceMessageReferences(options['text']);
|
||||
FieldLabel.fromJson = function(options) {
|
||||
const text = replaceMessageReferences(options['text']);
|
||||
// `this` might be a subclass of FieldLabel if that class doesn't override
|
||||
// the static fromJson method.
|
||||
return new this(text, undefined, options);
|
||||
@@ -75,13 +76,13 @@ Blockly.FieldLabel.fromJson = function(options) {
|
||||
* editable. This field should not.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.FieldLabel.prototype.EDITABLE = false;
|
||||
FieldLabel.prototype.EDITABLE = false;
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldLabel.prototype.configure_ = function(config) {
|
||||
Blockly.FieldLabel.superClass_.configure_.call(this, config);
|
||||
FieldLabel.prototype.configure_ = function(config) {
|
||||
FieldLabel.superClass_.configure_.call(this, config);
|
||||
this.class_ = config['class'];
|
||||
};
|
||||
|
||||
@@ -89,10 +90,10 @@ Blockly.FieldLabel.prototype.configure_ = function(config) {
|
||||
* Create block UI for this label.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldLabel.prototype.initView = function() {
|
||||
FieldLabel.prototype.initView = function() {
|
||||
this.createTextElement_();
|
||||
if (this.class_) {
|
||||
Blockly.utils.dom.addClass(
|
||||
dom.addClass(
|
||||
/** @type {!SVGTextElement} */ (this.textElement_), this.class_);
|
||||
}
|
||||
};
|
||||
@@ -103,7 +104,7 @@ Blockly.FieldLabel.prototype.initView = function() {
|
||||
* @return {?string} A valid string, or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldLabel.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
FieldLabel.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
if (opt_newValue === null || opt_newValue === undefined) {
|
||||
return null;
|
||||
}
|
||||
@@ -114,18 +115,20 @@ Blockly.FieldLabel.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
* Set the CSS class applied to the field's textElement_.
|
||||
* @param {?string} cssClass The new CSS class name, or null to remove.
|
||||
*/
|
||||
Blockly.FieldLabel.prototype.setClass = function(cssClass) {
|
||||
FieldLabel.prototype.setClass = function(cssClass) {
|
||||
if (this.textElement_) {
|
||||
// This check isn't necessary, but it's faster than letting removeClass
|
||||
// figure it out.
|
||||
if (this.class_) {
|
||||
Blockly.utils.dom.removeClass(this.textElement_, this.class_);
|
||||
dom.removeClass(this.textElement_, this.class_);
|
||||
}
|
||||
if (cssClass) {
|
||||
Blockly.utils.dom.addClass(this.textElement_, cssClass);
|
||||
dom.addClass(this.textElement_, cssClass);
|
||||
}
|
||||
}
|
||||
this.class_ = cssClass;
|
||||
};
|
||||
|
||||
Blockly.fieldRegistry.register('field_label', Blockly.FieldLabel);
|
||||
fieldRegistry.register('field_label', FieldLabel);
|
||||
|
||||
exports = FieldLabel;
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.FieldLabelSerializable');
|
||||
goog.module('Blockly.FieldLabelSerializable');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.FieldLabel');
|
||||
goog.require('Blockly.fieldRegistry');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.object');
|
||||
const FieldLabel = goog.require('Blockly.FieldLabel');
|
||||
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
const {replaceMessageReferences} = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
@@ -25,29 +26,29 @@ goog.require('Blockly.utils.object');
|
||||
* string. Defaults to an empty string if null or undefined.
|
||||
* @param {string=} opt_class Optional CSS class for the field's text.
|
||||
* @param {Object=} opt_config A map of options used to configure the field.
|
||||
* See the [field creation documentation]{@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/label-serializable#creation}
|
||||
* See the [field creation documentation]{@link
|
||||
* https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/label-serializable#creation}
|
||||
* for a list of properties this parameter supports.
|
||||
* @extends {Blockly.FieldLabel}
|
||||
* @extends {FieldLabel}
|
||||
* @constructor
|
||||
*
|
||||
*/
|
||||
Blockly.FieldLabelSerializable = function(opt_value, opt_class, opt_config) {
|
||||
Blockly.FieldLabelSerializable.superClass_.constructor.call(
|
||||
const FieldLabelSerializable = function(opt_value, opt_class, opt_config) {
|
||||
FieldLabelSerializable.superClass_.constructor.call(
|
||||
this, opt_value, opt_class, opt_config);
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.FieldLabelSerializable,
|
||||
Blockly.FieldLabel);
|
||||
inherits(FieldLabelSerializable, FieldLabel);
|
||||
|
||||
/**
|
||||
* Construct a FieldLabelSerializable from a JSON arg object,
|
||||
* dereferencing any string table references.
|
||||
* @param {!Object} options A JSON object with options (text, and class).
|
||||
* @return {!Blockly.FieldLabelSerializable} The new field instance.
|
||||
* @return {!FieldLabelSerializable} The new field instance.
|
||||
* @package
|
||||
* @nocollapse
|
||||
*/
|
||||
Blockly.FieldLabelSerializable.fromJson = function(options) {
|
||||
var text = Blockly.utils.replaceMessageReferences(options['text']);
|
||||
FieldLabelSerializable.fromJson = function(options) {
|
||||
const text = replaceMessageReferences(options['text']);
|
||||
// `this` might be a subclass of FieldLabelSerializable if that class doesn't
|
||||
// override the static fromJson method.
|
||||
return new this(text, undefined, options);
|
||||
@@ -58,14 +59,15 @@ Blockly.FieldLabelSerializable.fromJson = function(options) {
|
||||
* editable. This field should not.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.FieldLabelSerializable.prototype.EDITABLE = false;
|
||||
FieldLabelSerializable.prototype.EDITABLE = false;
|
||||
|
||||
/**
|
||||
* Serializable fields are saved by the XML renderer, non-serializable fields
|
||||
* are not. This field should be serialized, but only edited programmatically.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.FieldLabelSerializable.prototype.SERIALIZABLE = true;
|
||||
FieldLabelSerializable.prototype.SERIALIZABLE = true;
|
||||
|
||||
Blockly.fieldRegistry.register(
|
||||
'field_label_serializable', Blockly.FieldLabelSerializable);
|
||||
fieldRegistry.register('field_label_serializable', FieldLabelSerializable);
|
||||
|
||||
exports = FieldLabelSerializable;
|
||||
|
||||
@@ -12,20 +12,21 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.FieldMultilineInput');
|
||||
goog.module('Blockly.FieldMultilineInput');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Css');
|
||||
goog.require('Blockly.Field');
|
||||
goog.require('Blockly.fieldRegistry');
|
||||
goog.require('Blockly.FieldTextInput');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.aria');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.KeyCodes');
|
||||
goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
goog.require('Blockly.utils.userAgent');
|
||||
goog.require('Blockly.WidgetDiv');
|
||||
const Css = goog.require('Blockly.Css');
|
||||
const Field = goog.require('Blockly.Field');
|
||||
const FieldTextInput = goog.require('Blockly.FieldTextInput');
|
||||
const KeyCodes = goog.require('Blockly.utils.KeyCodes');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
const WidgetDiv = goog.require('Blockly.WidgetDiv');
|
||||
const aria = goog.require('Blockly.utils.aria');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
||||
const userAgent = goog.require('Blockly.utils.userAgent');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
const {replaceMessageReferences} = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
@@ -37,14 +38,15 @@ goog.require('Blockly.WidgetDiv');
|
||||
* text as an argument and returns either the accepted text, a replacement
|
||||
* text, or null to abort the change.
|
||||
* @param {Object=} opt_config A map of options used to configure the field.
|
||||
* See the [field creation documentation]{@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/multiline-text-input#creation}
|
||||
* See the [field creation documentation]{@link
|
||||
* https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/multiline-text-input#creation}
|
||||
* for a list of properties this parameter supports.
|
||||
* @extends {Blockly.FieldTextInput}
|
||||
* @extends {FieldTextInput}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldMultilineInput = function(opt_value, opt_validator, opt_config) {
|
||||
Blockly.FieldMultilineInput.superClass_.constructor.call(this,
|
||||
opt_value, opt_validator, opt_config);
|
||||
const FieldMultilineInput = function(opt_value, opt_validator, opt_config) {
|
||||
FieldMultilineInput.superClass_.constructor.call(
|
||||
this, opt_value, opt_validator, opt_config);
|
||||
|
||||
/**
|
||||
* The SVG group element that will contain a text element for each text row
|
||||
@@ -68,14 +70,13 @@ Blockly.FieldMultilineInput = function(opt_value, opt_validator, opt_config) {
|
||||
*/
|
||||
this.isOverflowedY_ = false;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.FieldMultilineInput,
|
||||
Blockly.FieldTextInput);
|
||||
inherits(FieldMultilineInput, FieldTextInput);
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.configure_ = function(config) {
|
||||
Blockly.FieldMultilineInput.superClass_.configure_.call(this, config);
|
||||
FieldMultilineInput.prototype.configure_ = function(config) {
|
||||
FieldMultilineInput.superClass_.configure_.call(this, config);
|
||||
config.maxLines && this.setMaxLines(config.maxLines);
|
||||
};
|
||||
|
||||
@@ -83,12 +84,12 @@ Blockly.FieldMultilineInput.prototype.configure_ = function(config) {
|
||||
* Construct a FieldMultilineInput from a JSON arg object,
|
||||
* dereferencing any string table references.
|
||||
* @param {!Object} options A JSON object with options (text, and spellcheck).
|
||||
* @return {!Blockly.FieldMultilineInput} The new field instance.
|
||||
* @return {!FieldMultilineInput} The new field instance.
|
||||
* @package
|
||||
* @nocollapse
|
||||
*/
|
||||
Blockly.FieldMultilineInput.fromJson = function(options) {
|
||||
var text = Blockly.utils.replaceMessageReferences(options['text']);
|
||||
FieldMultilineInput.fromJson = function(options) {
|
||||
const text = replaceMessageReferences(options['text']);
|
||||
// `this` might be a subclass of FieldMultilineInput if that class doesn't
|
||||
// override the static fromJson method.
|
||||
return new this(text, undefined, options);
|
||||
@@ -101,7 +102,7 @@ Blockly.FieldMultilineInput.fromJson = function(options) {
|
||||
* @return {!Element} The element containing info about the field's state.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.toXml = function(fieldElement) {
|
||||
FieldMultilineInput.prototype.toXml = function(fieldElement) {
|
||||
// Replace '\n' characters with HTML-escaped equivalent '
'. This is
|
||||
// needed so the plain-text representation of the XML produced by
|
||||
// `Blockly.Xml.domToText` will appear on a single line (this is a limitation
|
||||
@@ -117,7 +118,7 @@ Blockly.FieldMultilineInput.prototype.toXml = function(fieldElement) {
|
||||
* field's state.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.fromXml = function(fieldElement) {
|
||||
FieldMultilineInput.prototype.fromXml = function(fieldElement) {
|
||||
this.setValue(fieldElement.textContent.replace(/ /g, '\n'));
|
||||
};
|
||||
|
||||
@@ -125,12 +126,13 @@ Blockly.FieldMultilineInput.prototype.fromXml = function(fieldElement) {
|
||||
* Create the block UI for this field.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.initView = function() {
|
||||
FieldMultilineInput.prototype.initView = function() {
|
||||
this.createBorderRect_();
|
||||
this.textGroup_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.G, {
|
||||
this.textGroup_ = dom.createSvgElement(
|
||||
Svg.G, {
|
||||
'class': 'blocklyEditableText',
|
||||
}, this.fieldGroup_);
|
||||
},
|
||||
this.fieldGroup_);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -140,17 +142,18 @@ Blockly.FieldMultilineInput.prototype.initView = function() {
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.getDisplayText_ = function() {
|
||||
var textLines = this.getText();
|
||||
FieldMultilineInput.prototype.getDisplayText_ = function() {
|
||||
let textLines = this.getText();
|
||||
if (!textLines) {
|
||||
// Prevent the field from disappearing if empty.
|
||||
return Blockly.Field.NBSP;
|
||||
return Field.NBSP;
|
||||
}
|
||||
var lines = textLines.split('\n');
|
||||
const lines = textLines.split('\n');
|
||||
textLines = '';
|
||||
var displayLinesNumber = this.isOverflowedY_ ? this.maxLines_ : lines.length;
|
||||
for (var i = 0; i < displayLinesNumber; i++) {
|
||||
var text = lines[i];
|
||||
const displayLinesNumber =
|
||||
this.isOverflowedY_ ? this.maxLines_ : lines.length;
|
||||
for (let i = 0; i < displayLinesNumber; i++) {
|
||||
let text = lines[i];
|
||||
if (text.length > this.maxDisplayLength) {
|
||||
// Truncate displayed string and add an ellipsis ('...').
|
||||
text = text.substring(0, this.maxDisplayLength - 4) + '...';
|
||||
@@ -158,7 +161,7 @@ Blockly.FieldMultilineInput.prototype.getDisplayText_ = function() {
|
||||
text = text.substring(0, text.length - 3) + '...';
|
||||
}
|
||||
// Replace whitespace with non-breaking spaces so the text doesn't collapse.
|
||||
text = text.replace(/\s/g, Blockly.Field.NBSP);
|
||||
text = text.replace(/\s/g, Field.NBSP);
|
||||
|
||||
textLines += text;
|
||||
if (i !== displayLinesNumber - 1) {
|
||||
@@ -181,8 +184,8 @@ Blockly.FieldMultilineInput.prototype.getDisplayText_ = function() {
|
||||
* that this is a string.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.doValueUpdate_ = function(newValue) {
|
||||
Blockly.FieldMultilineInput.superClass_.doValueUpdate_.call(this, newValue);
|
||||
FieldMultilineInput.prototype.doValueUpdate_ = function(newValue) {
|
||||
FieldMultilineInput.superClass_.doValueUpdate_.call(this, newValue);
|
||||
this.isOverflowedY_ = this.value_.split('\n').length > this.maxLines_;
|
||||
};
|
||||
|
||||
@@ -190,36 +193,37 @@ Blockly.FieldMultilineInput.prototype.doValueUpdate_ = function(newValue) {
|
||||
* Updates the text of the textElement.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.render_ = function() {
|
||||
FieldMultilineInput.prototype.render_ = function() {
|
||||
// Remove all text group children.
|
||||
var currentChild;
|
||||
let currentChild;
|
||||
while ((currentChild = this.textGroup_.firstChild)) {
|
||||
this.textGroup_.removeChild(currentChild);
|
||||
}
|
||||
|
||||
// Add in text elements into the group.
|
||||
var lines = this.getDisplayText_().split('\n');
|
||||
var y = 0;
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var lineHeight = this.getConstants().FIELD_TEXT_HEIGHT +
|
||||
const lines = this.getDisplayText_().split('\n');
|
||||
let y = 0;
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const lineHeight = this.getConstants().FIELD_TEXT_HEIGHT +
|
||||
this.getConstants().FIELD_BORDER_RECT_Y_PADDING;
|
||||
var span = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.TEXT, {
|
||||
const span = dom.createSvgElement(
|
||||
Svg.TEXT, {
|
||||
'class': 'blocklyText blocklyMultilineText',
|
||||
x: this.getConstants().FIELD_BORDER_RECT_X_PADDING,
|
||||
y: y + this.getConstants().FIELD_BORDER_RECT_Y_PADDING,
|
||||
dy: this.getConstants().FIELD_TEXT_BASELINE
|
||||
}, this.textGroup_);
|
||||
},
|
||||
this.textGroup_);
|
||||
span.appendChild(document.createTextNode(lines[i]));
|
||||
y += lineHeight;
|
||||
}
|
||||
|
||||
if (this.isBeingEdited_) {
|
||||
var htmlInput = /** @type {!HTMLElement} */(this.htmlInput_);
|
||||
var htmlInput = /** @type {!HTMLElement} */ (this.htmlInput_);
|
||||
if (this.isOverflowedY_) {
|
||||
Blockly.utils.dom.addClass(htmlInput, 'blocklyHtmlTextAreaInputOverflowedY');
|
||||
dom.addClass(htmlInput, 'blocklyHtmlTextAreaInputOverflowedY');
|
||||
} else {
|
||||
Blockly.utils.dom.removeClass(htmlInput, 'blocklyHtmlTextAreaInputOverflowedY');
|
||||
dom.removeClass(htmlInput, 'blocklyHtmlTextAreaInputOverflowedY');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,15 +238,13 @@ Blockly.FieldMultilineInput.prototype.render_ = function() {
|
||||
} else {
|
||||
this.resizeEditor_();
|
||||
}
|
||||
var htmlInput = /** @type {!HTMLElement} */(this.htmlInput_);
|
||||
var htmlInput = /** @type {!HTMLElement} */ (this.htmlInput_);
|
||||
if (!this.isTextValid_) {
|
||||
Blockly.utils.dom.addClass(htmlInput, 'blocklyInvalidInput');
|
||||
Blockly.utils.aria.setState(htmlInput,
|
||||
Blockly.utils.aria.State.INVALID, true);
|
||||
dom.addClass(htmlInput, 'blocklyInvalidInput');
|
||||
aria.setState(htmlInput, aria.State.INVALID, true);
|
||||
} else {
|
||||
Blockly.utils.dom.removeClass(htmlInput, 'blocklyInvalidInput');
|
||||
Blockly.utils.aria.setState(htmlInput,
|
||||
Blockly.utils.aria.State.INVALID, false);
|
||||
dom.removeClass(htmlInput, 'blocklyInvalidInput');
|
||||
aria.setState(htmlInput, aria.State.INVALID, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -251,13 +253,13 @@ Blockly.FieldMultilineInput.prototype.render_ = function() {
|
||||
* Updates the size of the field based on the text.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.updateSize_ = function() {
|
||||
var nodes = this.textGroup_.childNodes;
|
||||
var totalWidth = 0;
|
||||
var totalHeight = 0;
|
||||
FieldMultilineInput.prototype.updateSize_ = function() {
|
||||
const nodes = this.textGroup_.childNodes;
|
||||
let totalWidth = 0;
|
||||
let totalHeight = 0;
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var tspan = /** @type {!Element} */ (nodes[i]);
|
||||
var textWidth = Blockly.utils.dom.getTextWidth(tspan);
|
||||
const tspan = /** @type {!Element} */ (nodes[i]);
|
||||
const textWidth = dom.getTextWidth(tspan);
|
||||
if (textWidth > totalWidth) {
|
||||
totalWidth = textWidth;
|
||||
}
|
||||
@@ -270,26 +272,28 @@ Blockly.FieldMultilineInput.prototype.updateSize_ = function() {
|
||||
// absolute longest line, even if it would be truncated after editing.
|
||||
// Otherwise we would get wrong editor width when there are more
|
||||
// lines than this.maxLines_.
|
||||
var actualEditorLines = this.value_.split('\n');
|
||||
var dummyTextElement = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.TEXT,{'class': 'blocklyText blocklyMultilineText'});
|
||||
var fontSize = this.getConstants().FIELD_TEXT_FONTSIZE;
|
||||
var fontWeight = this.getConstants().FIELD_TEXT_FONTWEIGHT;
|
||||
var fontFamily = this.getConstants().FIELD_TEXT_FONTFAMILY;
|
||||
const actualEditorLines = this.value_.split('\n');
|
||||
const dummyTextElement = dom.createSvgElement(
|
||||
Svg.TEXT, {'class': 'blocklyText blocklyMultilineText'});
|
||||
const fontSize = this.getConstants().FIELD_TEXT_FONTSIZE;
|
||||
const fontWeight = this.getConstants().FIELD_TEXT_FONTWEIGHT;
|
||||
const fontFamily = this.getConstants().FIELD_TEXT_FONTFAMILY;
|
||||
|
||||
for (var i = 0; i < actualEditorLines.length; i++) {
|
||||
if (actualEditorLines[i].length > this.maxDisplayLength) {
|
||||
actualEditorLines[i] = actualEditorLines[i].substring(0, this.maxDisplayLength);
|
||||
actualEditorLines[i] =
|
||||
actualEditorLines[i].substring(0, this.maxDisplayLength);
|
||||
}
|
||||
dummyTextElement.textContent = actualEditorLines[i];
|
||||
var lineWidth = Blockly.utils.dom.getFastTextWidth(
|
||||
const lineWidth = dom.getFastTextWidth(
|
||||
dummyTextElement, fontSize, fontWeight, fontFamily);
|
||||
if (lineWidth > totalWidth) {
|
||||
totalWidth = lineWidth;
|
||||
}
|
||||
}
|
||||
|
||||
var scrollbarWidth = this.htmlInput_.offsetWidth - this.htmlInput_.clientWidth;
|
||||
const scrollbarWidth =
|
||||
this.htmlInput_.offsetWidth - this.htmlInput_.clientWidth;
|
||||
totalWidth += scrollbarWidth;
|
||||
}
|
||||
if (this.borderRect_) {
|
||||
@@ -314,8 +318,9 @@ Blockly.FieldMultilineInput.prototype.updateSize_ = function() {
|
||||
* focus. Defaults to false.
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.showEditor_ = function(_opt_e, opt_quietInput) {
|
||||
Blockly.FieldMultilineInput.superClass_.showEditor_.call(this, _opt_e, opt_quietInput);
|
||||
FieldMultilineInput.prototype.showEditor_ = function(_opt_e, opt_quietInput) {
|
||||
FieldMultilineInput.superClass_.showEditor_.call(
|
||||
this, _opt_e, opt_quietInput);
|
||||
this.forceRerender();
|
||||
};
|
||||
|
||||
@@ -324,24 +329,24 @@ Blockly.FieldMultilineInput.prototype.showEditor_ = function(_opt_e, opt_quietIn
|
||||
* @return {!HTMLTextAreaElement} The newly created text input editor.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.widgetCreate_ = function() {
|
||||
var div = Blockly.WidgetDiv.DIV;
|
||||
var scale = this.workspace_.getScale();
|
||||
FieldMultilineInput.prototype.widgetCreate_ = function() {
|
||||
const div = WidgetDiv.DIV;
|
||||
const scale = this.workspace_.getScale();
|
||||
|
||||
var htmlInput =
|
||||
/** @type {HTMLTextAreaElement} */ (document.createElement('textarea'));
|
||||
const htmlInput =
|
||||
/** @type {HTMLTextAreaElement} */ (document.createElement('textarea'));
|
||||
htmlInput.className = 'blocklyHtmlInput blocklyHtmlTextAreaInput';
|
||||
htmlInput.setAttribute('spellcheck', this.spellcheck_);
|
||||
var fontSize = (this.getConstants().FIELD_TEXT_FONTSIZE * scale) + 'pt';
|
||||
const fontSize = (this.getConstants().FIELD_TEXT_FONTSIZE * scale) + 'pt';
|
||||
div.style.fontSize = fontSize;
|
||||
htmlInput.style.fontSize = fontSize;
|
||||
var borderRadius = (Blockly.FieldTextInput.BORDERRADIUS * scale) + 'px';
|
||||
const borderRadius = (FieldTextInput.BORDERRADIUS * scale) + 'px';
|
||||
htmlInput.style.borderRadius = borderRadius;
|
||||
var paddingX = this.getConstants().FIELD_BORDER_RECT_X_PADDING * scale;
|
||||
var paddingY = this.getConstants().FIELD_BORDER_RECT_Y_PADDING * scale / 2;
|
||||
htmlInput.style.padding = paddingY + 'px ' + paddingX + 'px ' + paddingY +
|
||||
'px ' + paddingX + 'px';
|
||||
var lineHeight = this.getConstants().FIELD_TEXT_HEIGHT +
|
||||
const paddingX = this.getConstants().FIELD_BORDER_RECT_X_PADDING * scale;
|
||||
const paddingY = this.getConstants().FIELD_BORDER_RECT_Y_PADDING * scale / 2;
|
||||
htmlInput.style.padding =
|
||||
paddingY + 'px ' + paddingX + 'px ' + paddingY + 'px ' + paddingX + 'px';
|
||||
const lineHeight = this.getConstants().FIELD_TEXT_HEIGHT +
|
||||
this.getConstants().FIELD_BORDER_RECT_Y_PADDING;
|
||||
htmlInput.style.lineHeight = (lineHeight * scale) + 'px';
|
||||
|
||||
@@ -350,7 +355,7 @@ Blockly.FieldMultilineInput.prototype.widgetCreate_ = function() {
|
||||
htmlInput.value = htmlInput.defaultValue = this.getEditorText_(this.value_);
|
||||
htmlInput.untypedDefaultValue_ = this.value_;
|
||||
htmlInput.oldValue_ = null;
|
||||
if (Blockly.utils.userAgent.GECKO) {
|
||||
if (userAgent.GECKO) {
|
||||
// In FF, ensure the browser reflows before resizing to avoid issue #2777.
|
||||
setTimeout(this.resizeEditor_.bind(this), 0);
|
||||
} else {
|
||||
@@ -367,8 +372,9 @@ Blockly.FieldMultilineInput.prototype.widgetCreate_ = function() {
|
||||
* @param {number} maxLines Defines the maximum number of lines allowed,
|
||||
* before scrolling functionality is enabled.
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.setMaxLines = function(maxLines) {
|
||||
if (typeof maxLines === 'number' && maxLines > 0 && maxLines !== this.maxLines_) {
|
||||
FieldMultilineInput.prototype.setMaxLines = function(maxLines) {
|
||||
if (typeof maxLines === 'number' && maxLines > 0 &&
|
||||
maxLines !== this.maxLines_) {
|
||||
this.maxLines_ = maxLines;
|
||||
this.forceRerender();
|
||||
}
|
||||
@@ -378,7 +384,7 @@ Blockly.FieldMultilineInput.prototype.setMaxLines = function(maxLines) {
|
||||
* Returns the maxLines config of this field.
|
||||
* @return {number} The maxLines config value.
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.getMaxLines = function() {
|
||||
FieldMultilineInput.prototype.getMaxLines = function() {
|
||||
return this.maxLines_;
|
||||
};
|
||||
|
||||
@@ -388,29 +394,29 @@ Blockly.FieldMultilineInput.prototype.getMaxLines = function() {
|
||||
* @param {!Event} e Keyboard event.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.onHtmlInputKeyDown_ = function(e) {
|
||||
if (e.keyCode !== Blockly.utils.KeyCodes.ENTER) {
|
||||
Blockly.FieldMultilineInput.superClass_.onHtmlInputKeyDown_.call(this, e);
|
||||
FieldMultilineInput.prototype.onHtmlInputKeyDown_ = function(e) {
|
||||
if (e.keyCode !== KeyCodes.ENTER) {
|
||||
FieldMultilineInput.superClass_.onHtmlInputKeyDown_.call(this, e);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* CSS for multiline field. See css.js for use.
|
||||
*/
|
||||
Blockly.Css.register([
|
||||
/* eslint-disable indent */
|
||||
'.blocklyHtmlTextAreaInput {',
|
||||
'font-family: monospace;',
|
||||
'resize: none;',
|
||||
'overflow: hidden;',
|
||||
'height: 100%;',
|
||||
'text-align: left;',
|
||||
'}',
|
||||
'.blocklyHtmlTextAreaInputOverflowedY {',
|
||||
'overflow-y: scroll;',
|
||||
'}'
|
||||
/* eslint-enable indent */
|
||||
Css.register([
|
||||
`.blocklyHtmlTextAreaInput {
|
||||
font-family: monospace;
|
||||
resize: none;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
text-align: left;
|
||||
}`,
|
||||
`.blocklyHtmlTextAreaInputOverflowedY {
|
||||
overflow-y: scroll;
|
||||
}`
|
||||
]);
|
||||
|
||||
|
||||
Blockly.fieldRegistry.register('field_multilinetext', Blockly.FieldMultilineInput);
|
||||
fieldRegistry.register('field_multilinetext', FieldMultilineInput);
|
||||
|
||||
exports = FieldMultilineInput;
|
||||
|
||||
@@ -10,12 +10,13 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.FieldNumber');
|
||||
goog.module('Blockly.FieldNumber');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.fieldRegistry');
|
||||
goog.require('Blockly.FieldTextInput');
|
||||
goog.require('Blockly.utils.aria');
|
||||
goog.require('Blockly.utils.object');
|
||||
const FieldTextInput = goog.require('Blockly.FieldTextInput');
|
||||
const aria = goog.require('Blockly.utils.aria');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
const {register} = goog.require('Blockly.fieldRegistry');
|
||||
|
||||
|
||||
/**
|
||||
@@ -29,14 +30,14 @@ goog.require('Blockly.utils.object');
|
||||
* changes to the field's value. Takes in a number & returns a validated
|
||||
* number, or null to abort the change.
|
||||
* @param {Object=} opt_config A map of options used to configure the field.
|
||||
* See the [field creation documentation]{@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/number#creation}
|
||||
* See the [field creation documentation]{@link
|
||||
* https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/number#creation}
|
||||
* for a list of properties this parameter supports.
|
||||
* @extends {Blockly.FieldTextInput}
|
||||
* @extends {FieldTextInput}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldNumber = function(opt_value, opt_min, opt_max, opt_precision,
|
||||
opt_validator, opt_config) {
|
||||
|
||||
const FieldNumber = function(
|
||||
opt_value, opt_min, opt_max, opt_precision, opt_validator, opt_config) {
|
||||
/**
|
||||
* The minimum value this number field can contain.
|
||||
* @type {number}
|
||||
@@ -66,35 +67,35 @@ Blockly.FieldNumber = function(opt_value, opt_min, opt_max, opt_precision,
|
||||
*/
|
||||
this.decimalPlaces_ = null;
|
||||
|
||||
Blockly.FieldNumber.superClass_.constructor.call(
|
||||
FieldNumber.superClass_.constructor.call(
|
||||
this, opt_value, opt_validator, opt_config);
|
||||
|
||||
if (!opt_config) { // Only do one kind of configuration or the other.
|
||||
this.setConstraints(opt_min, opt_max, opt_precision);
|
||||
}
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.FieldNumber, Blockly.FieldTextInput);
|
||||
inherits(FieldNumber, FieldTextInput);
|
||||
|
||||
/**
|
||||
* The default value for this field.
|
||||
* @type {*}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.DEFAULT_VALUE = 0;
|
||||
FieldNumber.prototype.DEFAULT_VALUE = 0;
|
||||
|
||||
/**
|
||||
* Construct a FieldNumber from a JSON arg object.
|
||||
* @param {!Object} options A JSON object with options (value, min, max, and
|
||||
* precision).
|
||||
* @return {!Blockly.FieldNumber} The new field instance.
|
||||
* @return {!FieldNumber} The new field instance.
|
||||
* @package
|
||||
* @nocollapse
|
||||
*/
|
||||
Blockly.FieldNumber.fromJson = function(options) {
|
||||
FieldNumber.fromJson = function(options) {
|
||||
// `this` might be a subclass of FieldNumber if that class doesn't override
|
||||
// the static fromJson method.
|
||||
return new this(options['value'],
|
||||
undefined, undefined, undefined, undefined, options);
|
||||
return new this(
|
||||
options['value'], undefined, undefined, undefined, undefined, options);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -102,7 +103,7 @@ Blockly.FieldNumber.fromJson = function(options) {
|
||||
* are not. Editable fields should also be serializable.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.SERIALIZABLE = true;
|
||||
FieldNumber.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Configure the field based on the given map of options.
|
||||
@@ -110,8 +111,8 @@ Blockly.FieldNumber.prototype.SERIALIZABLE = true;
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.configure_ = function(config) {
|
||||
Blockly.FieldNumber.superClass_.configure_.call(this, config);
|
||||
FieldNumber.prototype.configure_ = function(config) {
|
||||
FieldNumber.superClass_.configure_.call(this, config);
|
||||
this.setMinInternal_(config['min']);
|
||||
this.setMaxInternal_(config['max']);
|
||||
this.setPrecisionInternal_(config['precision']);
|
||||
@@ -128,7 +129,7 @@ Blockly.FieldNumber.prototype.configure_ = function(config) {
|
||||
* @param {?(number|string|undefined)} max Maximum value.
|
||||
* @param {?(number|string|undefined)} precision Precision for value.
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.setConstraints = function(min, max, precision) {
|
||||
FieldNumber.prototype.setConstraints = function(min, max, precision) {
|
||||
this.setMinInternal_(min);
|
||||
this.setMaxInternal_(max);
|
||||
this.setPrecisionInternal_(precision);
|
||||
@@ -139,7 +140,7 @@ Blockly.FieldNumber.prototype.setConstraints = function(min, max, precision) {
|
||||
* Sets the minimum value this field can contain. Updates the value to reflect.
|
||||
* @param {?(number|string|undefined)} min Minimum value.
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.setMin = function(min) {
|
||||
FieldNumber.prototype.setMin = function(min) {
|
||||
this.setMinInternal_(min);
|
||||
this.setValue(this.getValue());
|
||||
};
|
||||
@@ -150,7 +151,7 @@ Blockly.FieldNumber.prototype.setMin = function(min) {
|
||||
* @param {?(number|string|undefined)} min Minimum value.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.setMinInternal_ = function(min) {
|
||||
FieldNumber.prototype.setMinInternal_ = function(min) {
|
||||
if (min == null) {
|
||||
this.min_ = -Infinity;
|
||||
} else {
|
||||
@@ -166,7 +167,7 @@ Blockly.FieldNumber.prototype.setMinInternal_ = function(min) {
|
||||
* -Infinity.
|
||||
* @return {number} The current minimum value this field can contain.
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.getMin = function() {
|
||||
FieldNumber.prototype.getMin = function() {
|
||||
return this.min_;
|
||||
};
|
||||
|
||||
@@ -174,7 +175,7 @@ Blockly.FieldNumber.prototype.getMin = function() {
|
||||
* Sets the maximum value this field can contain. Updates the value to reflect.
|
||||
* @param {?(number|string|undefined)} max Maximum value.
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.setMax = function(max) {
|
||||
FieldNumber.prototype.setMax = function(max) {
|
||||
this.setMaxInternal_(max);
|
||||
this.setValue(this.getValue());
|
||||
};
|
||||
@@ -185,7 +186,7 @@ Blockly.FieldNumber.prototype.setMax = function(max) {
|
||||
* @param {?(number|string|undefined)} max Maximum value.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.setMaxInternal_ = function(max) {
|
||||
FieldNumber.prototype.setMaxInternal_ = function(max) {
|
||||
if (max == null) {
|
||||
this.max_ = Infinity;
|
||||
} else {
|
||||
@@ -201,7 +202,7 @@ Blockly.FieldNumber.prototype.setMaxInternal_ = function(max) {
|
||||
* Infinity.
|
||||
* @return {number} The current maximum value this field can contain.
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.getMax = function() {
|
||||
FieldNumber.prototype.getMax = function() {
|
||||
return this.max_;
|
||||
};
|
||||
|
||||
@@ -211,7 +212,7 @@ Blockly.FieldNumber.prototype.getMax = function() {
|
||||
* @param {?(number|string|undefined)} precision The number to which the
|
||||
* field's value is rounded.
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.setPrecision = function(precision) {
|
||||
FieldNumber.prototype.setPrecision = function(precision) {
|
||||
this.setPrecisionInternal_(precision);
|
||||
this.setValue(this.getValue());
|
||||
};
|
||||
@@ -223,16 +224,16 @@ Blockly.FieldNumber.prototype.setPrecision = function(precision) {
|
||||
* field's value is rounded.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.setPrecisionInternal_ = function(precision) {
|
||||
FieldNumber.prototype.setPrecisionInternal_ = function(precision) {
|
||||
this.precision_ = Number(precision) || 0;
|
||||
var precisionString = String(this.precision_);
|
||||
let precisionString = String(this.precision_);
|
||||
if (precisionString.indexOf('e') != -1) {
|
||||
// String() is fast. But it turns .0000001 into '1e-7'.
|
||||
// Use the much slower toLocaleString to access all the digits.
|
||||
precisionString =
|
||||
this.precision_.toLocaleString('en-US', {maximumFractionDigits: 20});
|
||||
}
|
||||
var decimalIndex = precisionString.indexOf('.');
|
||||
const decimalIndex = precisionString.indexOf('.');
|
||||
if (decimalIndex == -1) {
|
||||
// If the precision is 0 (float) allow any number of decimals,
|
||||
// otherwise allow none.
|
||||
@@ -248,7 +249,7 @@ Blockly.FieldNumber.prototype.setPrecisionInternal_ = function(precision) {
|
||||
* the value is not rounded.
|
||||
* @return {number} The number to which this field's value is rounded.
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.getPrecision = function() {
|
||||
FieldNumber.prototype.getPrecision = function() {
|
||||
return this.precision_;
|
||||
};
|
||||
|
||||
@@ -260,12 +261,12 @@ Blockly.FieldNumber.prototype.getPrecision = function() {
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
FieldNumber.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
if (opt_newValue === null) {
|
||||
return null;
|
||||
}
|
||||
// Clean up text.
|
||||
var newValue = String(opt_newValue);
|
||||
let newValue = String(opt_newValue);
|
||||
// TODO: Handle cases like 'ten', '1.203,14', etc.
|
||||
// 'O' is sometimes mistaken for '0' by inexperienced users.
|
||||
newValue = newValue.replace(/O/ig, '0');
|
||||
@@ -275,7 +276,7 @@ Blockly.FieldNumber.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
newValue = newValue.replace(/infinity/i, 'Infinity');
|
||||
|
||||
// Clean up number.
|
||||
var n = Number(newValue || 0);
|
||||
let n = Number(newValue || 0);
|
||||
if (isNaN(n)) {
|
||||
// Invalid number.
|
||||
return null;
|
||||
@@ -299,19 +300,19 @@ Blockly.FieldNumber.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.widgetCreate_ = function() {
|
||||
var htmlInput = Blockly.FieldNumber.superClass_.widgetCreate_.call(this);
|
||||
FieldNumber.prototype.widgetCreate_ = function() {
|
||||
const htmlInput = FieldNumber.superClass_.widgetCreate_.call(this);
|
||||
|
||||
// Set the accessibility state
|
||||
if (this.min_ > -Infinity) {
|
||||
Blockly.utils.aria.setState(htmlInput,
|
||||
Blockly.utils.aria.State.VALUEMIN, this.min_);
|
||||
aria.setState(htmlInput, aria.State.VALUEMIN, this.min_);
|
||||
}
|
||||
if (this.max_ < Infinity) {
|
||||
Blockly.utils.aria.setState(htmlInput,
|
||||
Blockly.utils.aria.State.VALUEMAX, this.max_);
|
||||
aria.setState(htmlInput, aria.State.VALUEMAX, this.max_);
|
||||
}
|
||||
return htmlInput;
|
||||
};
|
||||
|
||||
Blockly.fieldRegistry.register('field_number', Blockly.FieldNumber);
|
||||
register('field_number', FieldNumber);
|
||||
|
||||
exports = FieldNumber;
|
||||
|
||||
@@ -12,56 +12,62 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.fieldRegistry');
|
||||
goog.module('Blockly.fieldRegistry');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.registry');
|
||||
|
||||
goog.requireType('Blockly.Field');
|
||||
goog.requireType('Blockly.IRegistrableField');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Field = goog.requireType('Blockly.Field');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IRegistrableField = goog.requireType('Blockly.IRegistrableField');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
* Registers a field type.
|
||||
* Blockly.fieldRegistry.fromJson uses this registry to
|
||||
* fieldRegistry.fromJson uses this registry to
|
||||
* find the appropriate field type.
|
||||
* @param {string} type The field type name as used in the JSON definition.
|
||||
* @param {!Blockly.IRegistrableField} fieldClass The field class containing a
|
||||
* @param {!IRegistrableField} fieldClass The field class containing a
|
||||
* fromJson function that can construct an instance of the field.
|
||||
* @throws {Error} if the type name is empty, the field is already
|
||||
* registered, or the fieldClass is not an object containing a fromJson
|
||||
* function.
|
||||
*/
|
||||
Blockly.fieldRegistry.register = function(type, fieldClass) {
|
||||
Blockly.registry.register(Blockly.registry.Type.FIELD, type, fieldClass);
|
||||
const register = function(type, fieldClass) {
|
||||
registry.register(registry.Type.FIELD, type, fieldClass);
|
||||
};
|
||||
exports.register = register;
|
||||
|
||||
/**
|
||||
* Unregisters the field registered with the given type.
|
||||
* @param {string} type The field type name as used in the JSON definition.
|
||||
*/
|
||||
Blockly.fieldRegistry.unregister = function(type) {
|
||||
Blockly.registry.unregister(Blockly.registry.Type.FIELD, type);
|
||||
const unregister = function(type) {
|
||||
registry.unregister(registry.Type.FIELD, type);
|
||||
};
|
||||
exports.unregister = unregister;
|
||||
|
||||
/**
|
||||
* Construct a Field from a JSON arg object.
|
||||
* Finds the appropriate registered field by the type name as registered using
|
||||
* Blockly.fieldRegistry.register.
|
||||
* fieldRegistry.register.
|
||||
* @param {!Object} options A JSON object with a type and options specific
|
||||
* to the field type.
|
||||
* @return {?Blockly.Field} The new field instance or null if a field wasn't
|
||||
* @return {?Field} The new field instance or null if a field wasn't
|
||||
* found with the given type name
|
||||
* @package
|
||||
*/
|
||||
Blockly.fieldRegistry.fromJson = function(options) {
|
||||
var fieldObject = /** @type {?Blockly.IRegistrableField} */ (
|
||||
Blockly.registry.getObject(Blockly.registry.Type.FIELD, options['type']));
|
||||
const fromJson = function(options) {
|
||||
const fieldObject = /** @type {?IRegistrableField} */ (
|
||||
registry.getObject(registry.Type.FIELD, options['type']));
|
||||
if (!fieldObject) {
|
||||
console.warn('Blockly could not create a field of type ' + options['type'] +
|
||||
'. The field is probably not being registered. This could be because' +
|
||||
' the file is not loaded, the field does not register itself (Issue' +
|
||||
' #1584), or the registration is not being reached.');
|
||||
console.warn(
|
||||
'Blockly could not create a field of type ' + options['type'] +
|
||||
'. The field is probably not being registered. This could be because' +
|
||||
' the file is not loaded, the field does not register itself (Issue' +
|
||||
' #1584), or the registration is not being reached.');
|
||||
return null;
|
||||
}
|
||||
return fieldObject.fromJson(options);
|
||||
};
|
||||
/** @package */
|
||||
exports.fromJson = fromJson;
|
||||
|
||||
@@ -10,27 +10,30 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.FieldTextInput');
|
||||
goog.module('Blockly.FieldTextInput');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.browserEvents');
|
||||
goog.require('Blockly.DropDownDiv');
|
||||
goog.require('Blockly.Events');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
const DropDownDiv = goog.require('Blockly.DropDownDiv');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const Field = goog.require('Blockly.Field');
|
||||
const KeyCodes = goog.require('Blockly.utils.KeyCodes');
|
||||
const Msg = goog.require('Blockly.Msg');
|
||||
const WidgetDiv = goog.require('Blockly.WidgetDiv');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const aria = goog.require('Blockly.utils.aria');
|
||||
const browserEvents = goog.require('Blockly.browserEvents');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
||||
const userAgent = goog.require('Blockly.utils.userAgent');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
const {prompt: blocklyPrompt} = goog.require('Blockly');
|
||||
const {replaceMessageReferences} = goog.require('Blockly.utils');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockChange');
|
||||
goog.require('Blockly.Field');
|
||||
goog.require('Blockly.fieldRegistry');
|
||||
goog.require('Blockly.Msg');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.aria');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.KeyCodes');
|
||||
goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.utils.userAgent');
|
||||
goog.require('Blockly.WidgetDiv');
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
|
||||
|
||||
/**
|
||||
@@ -41,12 +44,13 @@ goog.requireType('Blockly.WorkspaceSvg');
|
||||
* changes to the field's value. Takes in a string & returns a validated
|
||||
* string, or null to abort the change.
|
||||
* @param {Object=} opt_config A map of options used to configure the field.
|
||||
* See the [field creation documentation]{@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/text-input#creation}
|
||||
* See the [field creation documentation]{@link
|
||||
* https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/text-input#creation}
|
||||
* for a list of properties this parameter supports.
|
||||
* @extends {Blockly.Field}
|
||||
* @extends {Field}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldTextInput = function(opt_value, opt_validator, opt_config) {
|
||||
const FieldTextInput = function(opt_value, opt_validator, opt_config) {
|
||||
/**
|
||||
* Allow browser to spellcheck this field.
|
||||
* @type {boolean}
|
||||
@@ -54,8 +58,8 @@ Blockly.FieldTextInput = function(opt_value, opt_validator, opt_config) {
|
||||
*/
|
||||
this.spellcheck_ = true;
|
||||
|
||||
Blockly.FieldTextInput.superClass_.constructor.call(this,
|
||||
opt_value, opt_validator, opt_config);
|
||||
FieldTextInput.superClass_.constructor.call(
|
||||
this, opt_value, opt_validator, opt_config);
|
||||
|
||||
/**
|
||||
* The HTML input element.
|
||||
@@ -65,14 +69,14 @@ Blockly.FieldTextInput = function(opt_value, opt_validator, opt_config) {
|
||||
|
||||
/**
|
||||
* Key down event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.onKeyDownWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Key input event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.onKeyInputWrapper_ = null;
|
||||
@@ -86,30 +90,30 @@ Blockly.FieldTextInput = function(opt_value, opt_validator, opt_config) {
|
||||
|
||||
/**
|
||||
* The workspace that this field belongs to.
|
||||
* @type {?Blockly.WorkspaceSvg}
|
||||
* @type {?WorkspaceSvg}
|
||||
* @protected
|
||||
*/
|
||||
this.workspace_ = null;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.FieldTextInput, Blockly.Field);
|
||||
inherits(FieldTextInput, Field);
|
||||
|
||||
/**
|
||||
* The default value for this field.
|
||||
* @type {*}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.DEFAULT_VALUE = '';
|
||||
FieldTextInput.prototype.DEFAULT_VALUE = '';
|
||||
|
||||
/**
|
||||
* Construct a FieldTextInput from a JSON arg object,
|
||||
* dereferencing any string table references.
|
||||
* @param {!Object} options A JSON object with options (text, and spellcheck).
|
||||
* @return {!Blockly.FieldTextInput} The new field instance.
|
||||
* @return {!FieldTextInput} The new field instance.
|
||||
* @package
|
||||
* @nocollapse
|
||||
*/
|
||||
Blockly.FieldTextInput.fromJson = function(options) {
|
||||
var text = Blockly.utils.replaceMessageReferences(options['text']);
|
||||
FieldTextInput.fromJson = function(options) {
|
||||
const text = replaceMessageReferences(options['text']);
|
||||
// `this` might be a subclass of FieldTextInput if that class doesn't override
|
||||
// the static fromJson method.
|
||||
return new this(text, undefined, options);
|
||||
@@ -120,24 +124,24 @@ Blockly.FieldTextInput.fromJson = function(options) {
|
||||
* are not. Editable fields should also be serializable.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.SERIALIZABLE = true;
|
||||
FieldTextInput.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Pixel size of input border radius.
|
||||
* Should match blocklyText's border-radius in CSS.
|
||||
*/
|
||||
Blockly.FieldTextInput.BORDERRADIUS = 4;
|
||||
FieldTextInput.BORDERRADIUS = 4;
|
||||
|
||||
/**
|
||||
* Mouse cursor style when over the hotspot that initiates the editor.
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.CURSOR = 'text';
|
||||
FieldTextInput.prototype.CURSOR = 'text';
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.configure_ = function(config) {
|
||||
Blockly.FieldTextInput.superClass_.configure_.call(this, config);
|
||||
FieldTextInput.prototype.configure_ = function(config) {
|
||||
FieldTextInput.superClass_.configure_.call(this, config);
|
||||
if (typeof config['spellcheck'] == 'boolean') {
|
||||
this.spellcheck_ = config['spellcheck'];
|
||||
}
|
||||
@@ -146,17 +150,17 @@ Blockly.FieldTextInput.prototype.configure_ = function(config) {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.initView = function() {
|
||||
FieldTextInput.prototype.initView = function() {
|
||||
if (this.getConstants().FULL_BLOCK_FIELDS) {
|
||||
// Step one: figure out if this is the only field on this block.
|
||||
// Rendering is quite different in that case.
|
||||
var nFields = 0;
|
||||
var nConnections = 0;
|
||||
let nFields = 0;
|
||||
let nConnections = 0;
|
||||
|
||||
// Count the number of fields, excluding text fields
|
||||
for (var i = 0, input; (input = this.sourceBlock_.inputList[i]); i++) {
|
||||
for (var j = 0; (input.fieldRow[j]); j++) {
|
||||
nFields ++;
|
||||
for (let i = 0, input; (input = this.sourceBlock_.inputList[i]); i++) {
|
||||
for (let j = 0; (input.fieldRow[j]); j++) {
|
||||
nFields++;
|
||||
}
|
||||
if (input.connection) {
|
||||
nConnections++;
|
||||
@@ -184,7 +188,7 @@ Blockly.FieldTextInput.prototype.initView = function() {
|
||||
* @return {*} A valid string, or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
FieldTextInput.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
if (opt_newValue === null || opt_newValue === undefined) {
|
||||
return null;
|
||||
}
|
||||
@@ -200,15 +204,16 @@ Blockly.FieldTextInput.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
* the htmlInput_.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.doValueInvalid_ = function(_invalidValue) {
|
||||
FieldTextInput.prototype.doValueInvalid_ = function(_invalidValue) {
|
||||
if (this.isBeingEdited_) {
|
||||
this.isTextValid_ = false;
|
||||
var oldValue = this.value_;
|
||||
const oldValue = this.value_;
|
||||
// Revert value when the text becomes invalid.
|
||||
this.value_ = this.htmlInput_.untypedDefaultValue_;
|
||||
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
|
||||
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))(
|
||||
this.sourceBlock_, 'field', this.name || null, oldValue, this.value_));
|
||||
if (this.sourceBlock_ && Events.isEnabled()) {
|
||||
Events.fire(new (Events.get(Events.BLOCK_CHANGE))(
|
||||
this.sourceBlock_, 'field', this.name || null, oldValue,
|
||||
this.value_));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -221,7 +226,7 @@ Blockly.FieldTextInput.prototype.doValueInvalid_ = function(_invalidValue) {
|
||||
* that this is a string.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.doValueUpdate_ = function(newValue) {
|
||||
FieldTextInput.prototype.doValueUpdate_ = function(newValue) {
|
||||
this.isTextValid_ = true;
|
||||
this.value_ = newValue;
|
||||
if (!this.isBeingEdited_) {
|
||||
@@ -234,14 +239,14 @@ Blockly.FieldTextInput.prototype.doValueUpdate_ = function(newValue) {
|
||||
* Updates text field to match the colour/style of the block.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.applyColour = function() {
|
||||
FieldTextInput.prototype.applyColour = function() {
|
||||
if (this.sourceBlock_ && this.getConstants().FULL_BLOCK_FIELDS) {
|
||||
if (this.borderRect_) {
|
||||
this.borderRect_.setAttribute('stroke',
|
||||
this.sourceBlock_.style.colourTertiary);
|
||||
this.borderRect_.setAttribute(
|
||||
'stroke', this.sourceBlock_.style.colourTertiary);
|
||||
} else {
|
||||
this.sourceBlock_.pathObject.svgPath.setAttribute('fill',
|
||||
this.getConstants().FIELD_BORDER_RECT_COLOUR);
|
||||
this.sourceBlock_.pathObject.svgPath.setAttribute(
|
||||
'fill', this.getConstants().FIELD_BORDER_RECT_COLOUR);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -251,21 +256,19 @@ Blockly.FieldTextInput.prototype.applyColour = function() {
|
||||
* field's value.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.render_ = function() {
|
||||
Blockly.FieldTextInput.superClass_.render_.call(this);
|
||||
FieldTextInput.prototype.render_ = function() {
|
||||
FieldTextInput.superClass_.render_.call(this);
|
||||
// This logic is done in render_ rather than doValueInvalid_ or
|
||||
// doValueUpdate_ so that the code is more centralized.
|
||||
if (this.isBeingEdited_) {
|
||||
this.resizeEditor_();
|
||||
var htmlInput = /** @type {!HTMLElement} */(this.htmlInput_);
|
||||
const htmlInput = /** @type {!HTMLElement} */ (this.htmlInput_);
|
||||
if (!this.isTextValid_) {
|
||||
Blockly.utils.dom.addClass(htmlInput, 'blocklyInvalidInput');
|
||||
Blockly.utils.aria.setState(htmlInput,
|
||||
Blockly.utils.aria.State.INVALID, true);
|
||||
dom.addClass(htmlInput, 'blocklyInvalidInput');
|
||||
aria.setState(htmlInput, aria.State.INVALID, true);
|
||||
} else {
|
||||
Blockly.utils.dom.removeClass(htmlInput, 'blocklyInvalidInput');
|
||||
Blockly.utils.aria.setState(htmlInput,
|
||||
Blockly.utils.aria.State.INVALID, false);
|
||||
dom.removeClass(htmlInput, 'blocklyInvalidInput');
|
||||
aria.setState(htmlInput, aria.State.INVALID, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -274,7 +277,7 @@ Blockly.FieldTextInput.prototype.render_ = function() {
|
||||
* Set whether this field is spellchecked by the browser.
|
||||
* @param {boolean} check True if checked.
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.setSpellcheck = function(check) {
|
||||
FieldTextInput.prototype.setSpellcheck = function(check) {
|
||||
if (check == this.spellcheck_) {
|
||||
return;
|
||||
}
|
||||
@@ -292,14 +295,11 @@ Blockly.FieldTextInput.prototype.setSpellcheck = function(check) {
|
||||
* focus. Defaults to false.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.showEditor_ = function(_opt_e,
|
||||
opt_quietInput) {
|
||||
this.workspace_ =
|
||||
(/** @type {!Blockly.BlockSvg} */ (this.sourceBlock_)).workspace;
|
||||
var quietInput = opt_quietInput || false;
|
||||
if (!quietInput && (Blockly.utils.userAgent.MOBILE ||
|
||||
Blockly.utils.userAgent.ANDROID ||
|
||||
Blockly.utils.userAgent.IPAD)) {
|
||||
FieldTextInput.prototype.showEditor_ = function(_opt_e, opt_quietInput) {
|
||||
this.workspace_ = (/** @type {!BlockSvg} */ (this.sourceBlock_)).workspace;
|
||||
const quietInput = opt_quietInput || false;
|
||||
if (!quietInput &&
|
||||
(userAgent.MOBILE || userAgent.ANDROID || userAgent.IPAD)) {
|
||||
this.showPromptEditor_();
|
||||
} else {
|
||||
this.showInlineEditor_(quietInput);
|
||||
@@ -311,11 +311,10 @@ Blockly.FieldTextInput.prototype.showEditor_ = function(_opt_e,
|
||||
* Mobile browsers have issues with in-line textareas (focus and keyboards).
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.showPromptEditor_ = function() {
|
||||
Blockly.prompt(Blockly.Msg['CHANGE_VALUE_TITLE'], this.getText(),
|
||||
function(text) {
|
||||
this.setValue(this.getValueFromEditorText_(text));
|
||||
}.bind(this));
|
||||
FieldTextInput.prototype.showPromptEditor_ = function() {
|
||||
blocklyPrompt(Msg['CHANGE_VALUE_TITLE'], this.getText(), function(text) {
|
||||
this.setValue(this.getValueFromEditorText_(text));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -324,14 +323,13 @@ Blockly.FieldTextInput.prototype.showPromptEditor_ = function() {
|
||||
* focus.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) {
|
||||
Blockly.WidgetDiv.show(
|
||||
this, this.sourceBlock_.RTL, this.widgetDispose_.bind(this));
|
||||
FieldTextInput.prototype.showInlineEditor_ = function(quietInput) {
|
||||
WidgetDiv.show(this, this.sourceBlock_.RTL, this.widgetDispose_.bind(this));
|
||||
this.htmlInput_ = this.widgetCreate_();
|
||||
this.isBeingEdited_ = true;
|
||||
|
||||
if (!quietInput) {
|
||||
this.htmlInput_.focus({preventScroll:true});
|
||||
this.htmlInput_.focus({preventScroll: true});
|
||||
this.htmlInput_.select();
|
||||
}
|
||||
};
|
||||
@@ -341,38 +339,37 @@ Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) {
|
||||
* @return {!HTMLElement} The newly created text input editor.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.widgetCreate_ = function() {
|
||||
Blockly.Events.setGroup(true);
|
||||
var div = Blockly.WidgetDiv.DIV;
|
||||
FieldTextInput.prototype.widgetCreate_ = function() {
|
||||
Events.setGroup(true);
|
||||
const div = WidgetDiv.DIV;
|
||||
|
||||
Blockly.utils.dom.addClass(this.getClickTarget_(), 'editing');
|
||||
dom.addClass(this.getClickTarget_(), 'editing');
|
||||
|
||||
var htmlInput = /** @type {HTMLInputElement} */ (document.createElement('input'));
|
||||
const htmlInput =
|
||||
/** @type {HTMLInputElement} */ (document.createElement('input'));
|
||||
htmlInput.className = 'blocklyHtmlInput';
|
||||
htmlInput.setAttribute('spellcheck', this.spellcheck_);
|
||||
var scale = this.workspace_.getScale();
|
||||
var fontSize =
|
||||
(this.getConstants().FIELD_TEXT_FONTSIZE * scale) + 'pt';
|
||||
const scale = this.workspace_.getScale();
|
||||
const fontSize = (this.getConstants().FIELD_TEXT_FONTSIZE * scale) + 'pt';
|
||||
div.style.fontSize = fontSize;
|
||||
htmlInput.style.fontSize = fontSize;
|
||||
var borderRadius =
|
||||
(Blockly.FieldTextInput.BORDERRADIUS * scale) + 'px';
|
||||
let borderRadius = (FieldTextInput.BORDERRADIUS * scale) + 'px';
|
||||
|
||||
if (this.fullBlockClickTarget_) {
|
||||
var bBox = this.getScaledBBox();
|
||||
const bBox = this.getScaledBBox();
|
||||
|
||||
// Override border radius.
|
||||
borderRadius = (bBox.bottom - bBox.top) / 2 + 'px';
|
||||
// Pull stroke colour from the existing shadow block
|
||||
var strokeColour = this.sourceBlock_.getParent() ?
|
||||
this.sourceBlock_.getParent().style.colourTertiary :
|
||||
this.sourceBlock_.style.colourTertiary;
|
||||
const strokeColour = this.sourceBlock_.getParent() ?
|
||||
this.sourceBlock_.getParent().style.colourTertiary :
|
||||
this.sourceBlock_.style.colourTertiary;
|
||||
htmlInput.style.border = (1 * scale) + 'px solid ' + strokeColour;
|
||||
div.style.borderRadius = borderRadius;
|
||||
div.style.transition = 'box-shadow 0.25s ease 0s';
|
||||
if (this.getConstants().FIELD_TEXTINPUT_BOX_SHADOW) {
|
||||
div.style.boxShadow = 'rgba(255, 255, 255, 0.3) 0 0 0 ' +
|
||||
(4 * scale) + 'px';
|
||||
div.style.boxShadow =
|
||||
'rgba(255, 255, 255, 0.3) 0 0 0 ' + (4 * scale) + 'px';
|
||||
}
|
||||
}
|
||||
htmlInput.style.borderRadius = borderRadius;
|
||||
@@ -395,7 +392,7 @@ Blockly.FieldTextInput.prototype.widgetCreate_ = function() {
|
||||
* DOM-references belonging to the editor.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.widgetDispose_ = function() {
|
||||
FieldTextInput.prototype.widgetDispose_ = function() {
|
||||
// Non-disposal related things that we do when the editor closes.
|
||||
this.isBeingEdited_ = false;
|
||||
this.isTextValid_ = true;
|
||||
@@ -405,11 +402,11 @@ Blockly.FieldTextInput.prototype.widgetDispose_ = function() {
|
||||
if (this.onFinishEditing_) {
|
||||
this.onFinishEditing_(this.value_);
|
||||
}
|
||||
Blockly.Events.setGroup(false);
|
||||
Events.setGroup(false);
|
||||
|
||||
// Actual disposal.
|
||||
this.unbindInputEvents_();
|
||||
var style = Blockly.WidgetDiv.DIV.style;
|
||||
const style = WidgetDiv.DIV.style;
|
||||
style.width = 'auto';
|
||||
style.height = 'auto';
|
||||
style.fontSize = '';
|
||||
@@ -417,7 +414,7 @@ Blockly.FieldTextInput.prototype.widgetDispose_ = function() {
|
||||
style.boxShadow = '';
|
||||
this.htmlInput_ = null;
|
||||
|
||||
Blockly.utils.dom.removeClass(this.getClickTarget_(), 'editing');
|
||||
dom.removeClass(this.getClickTarget_(), 'editing');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -426,12 +423,12 @@ Blockly.FieldTextInput.prototype.widgetDispose_ = function() {
|
||||
* handlers will be bound.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.bindInputEvents_ = function(htmlInput) {
|
||||
FieldTextInput.prototype.bindInputEvents_ = function(htmlInput) {
|
||||
// Trap Enter without IME and Esc to hide.
|
||||
this.onKeyDownWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
this.onKeyDownWrapper_ = browserEvents.conditionalBind(
|
||||
htmlInput, 'keydown', this, this.onHtmlInputKeyDown_);
|
||||
// Resize after every input change.
|
||||
this.onKeyInputWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
this.onKeyInputWrapper_ = browserEvents.conditionalBind(
|
||||
htmlInput, 'input', this, this.onHtmlInputChange_);
|
||||
};
|
||||
|
||||
@@ -439,13 +436,13 @@ Blockly.FieldTextInput.prototype.bindInputEvents_ = function(htmlInput) {
|
||||
* Unbind handlers for user input and workspace size changes.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.unbindInputEvents_ = function() {
|
||||
FieldTextInput.prototype.unbindInputEvents_ = function() {
|
||||
if (this.onKeyDownWrapper_) {
|
||||
Blockly.browserEvents.unbind(this.onKeyDownWrapper_);
|
||||
browserEvents.unbind(this.onKeyDownWrapper_);
|
||||
this.onKeyDownWrapper_ = null;
|
||||
}
|
||||
if (this.onKeyInputWrapper_) {
|
||||
Blockly.browserEvents.unbind(this.onKeyInputWrapper_);
|
||||
browserEvents.unbind(this.onKeyInputWrapper_);
|
||||
this.onKeyInputWrapper_ = null;
|
||||
}
|
||||
};
|
||||
@@ -455,17 +452,17 @@ Blockly.FieldTextInput.prototype.unbindInputEvents_ = function() {
|
||||
* @param {!Event} e Keyboard event.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.onHtmlInputKeyDown_ = function(e) {
|
||||
if (e.keyCode == Blockly.utils.KeyCodes.ENTER) {
|
||||
Blockly.WidgetDiv.hide();
|
||||
Blockly.DropDownDiv.hideWithoutAnimation();
|
||||
} else if (e.keyCode == Blockly.utils.KeyCodes.ESC) {
|
||||
FieldTextInput.prototype.onHtmlInputKeyDown_ = function(e) {
|
||||
if (e.keyCode == KeyCodes.ENTER) {
|
||||
WidgetDiv.hide();
|
||||
DropDownDiv.hideWithoutAnimation();
|
||||
} else if (e.keyCode == KeyCodes.ESC) {
|
||||
this.setValue(this.htmlInput_.untypedDefaultValue_);
|
||||
Blockly.WidgetDiv.hide();
|
||||
Blockly.DropDownDiv.hideWithoutAnimation();
|
||||
} else if (e.keyCode == Blockly.utils.KeyCodes.TAB) {
|
||||
Blockly.WidgetDiv.hide();
|
||||
Blockly.DropDownDiv.hideWithoutAnimation();
|
||||
WidgetDiv.hide();
|
||||
DropDownDiv.hideWithoutAnimation();
|
||||
} else if (e.keyCode == KeyCodes.TAB) {
|
||||
WidgetDiv.hide();
|
||||
DropDownDiv.hideWithoutAnimation();
|
||||
this.sourceBlock_.tab(this, !e.shiftKey);
|
||||
e.preventDefault();
|
||||
}
|
||||
@@ -476,12 +473,12 @@ Blockly.FieldTextInput.prototype.onHtmlInputKeyDown_ = function(e) {
|
||||
* @param {!Event} _e Keyboard event.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.onHtmlInputChange_ = function(_e) {
|
||||
var text = this.htmlInput_.value;
|
||||
FieldTextInput.prototype.onHtmlInputChange_ = function(_e) {
|
||||
const text = this.htmlInput_.value;
|
||||
if (text !== this.htmlInput_.oldValue_) {
|
||||
this.htmlInput_.oldValue_ = text;
|
||||
|
||||
var value = this.getValueFromEditorText_(text);
|
||||
const value = this.getValueFromEditorText_(text);
|
||||
this.setValue(value);
|
||||
this.forceRerender();
|
||||
this.resizeEditor_();
|
||||
@@ -495,7 +492,7 @@ Blockly.FieldTextInput.prototype.onHtmlInputChange_ = function(_e) {
|
||||
* @param {*} newValue New value.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.setEditorValue_ = function(newValue) {
|
||||
FieldTextInput.prototype.setEditorValue_ = function(newValue) {
|
||||
this.isDirty_ = true;
|
||||
if (this.isBeingEdited_) {
|
||||
// In the case this method is passed an invalid value, we still
|
||||
@@ -511,16 +508,16 @@ Blockly.FieldTextInput.prototype.setEditorValue_ = function(newValue) {
|
||||
* Resize the editor to fit the text.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.resizeEditor_ = function() {
|
||||
var div = Blockly.WidgetDiv.DIV;
|
||||
var bBox = this.getScaledBBox();
|
||||
FieldTextInput.prototype.resizeEditor_ = function() {
|
||||
const div = WidgetDiv.DIV;
|
||||
const bBox = this.getScaledBBox();
|
||||
div.style.width = bBox.right - bBox.left + 'px';
|
||||
div.style.height = bBox.bottom - bBox.top + 'px';
|
||||
|
||||
// In RTL mode block fields and LTR input fields the left edge moves,
|
||||
// whereas the right edge is fixed. Reposition the editor.
|
||||
var x = this.sourceBlock_.RTL ? bBox.right - div.offsetWidth : bBox.left;
|
||||
var xy = new Blockly.utils.Coordinate(x, bBox.top);
|
||||
const x = this.sourceBlock_.RTL ? bBox.right - div.offsetWidth : bBox.left;
|
||||
const xy = new Coordinate(x, bBox.top);
|
||||
|
||||
div.style.left = xy.x + 'px';
|
||||
div.style.top = xy.y + 'px';
|
||||
@@ -531,20 +528,20 @@ Blockly.FieldTextInput.prototype.resizeEditor_ = function() {
|
||||
* @return {boolean} True if the field is tab navigable.
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.isTabNavigable = function() {
|
||||
FieldTextInput.prototype.isTabNavigable = function() {
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Use the `getText_` developer hook to override the field's text representation.
|
||||
* When we're currently editing, return the current HTML value instead.
|
||||
* Otherwise, return null which tells the field to use the default behaviour
|
||||
* (which is a string cast of the field's value).
|
||||
* Use the `getText_` developer hook to override the field's text
|
||||
* representation. When we're currently editing, return the current HTML value
|
||||
* instead. Otherwise, return null which tells the field to use the default
|
||||
* behaviour (which is a string cast of the field's value).
|
||||
* @return {?string} The HTML value if we're editing, otherwise null.
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.getText_ = function() {
|
||||
FieldTextInput.prototype.getText_ = function() {
|
||||
if (this.isBeingEdited_ && this.htmlInput_) {
|
||||
// We are currently editing, return the HTML input value instead.
|
||||
return this.htmlInput_.value;
|
||||
@@ -561,7 +558,7 @@ Blockly.FieldTextInput.prototype.getText_ = function() {
|
||||
* @return {string} The text to show on the HTML input.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.getEditorText_ = function(value) {
|
||||
FieldTextInput.prototype.getEditorText_ = function(value) {
|
||||
return String(value);
|
||||
};
|
||||
|
||||
@@ -575,8 +572,10 @@ Blockly.FieldTextInput.prototype.getEditorText_ = function(value) {
|
||||
* @return {*} The value to store.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.getValueFromEditorText_ = function(text) {
|
||||
FieldTextInput.prototype.getValueFromEditorText_ = function(text) {
|
||||
return text;
|
||||
};
|
||||
|
||||
Blockly.fieldRegistry.register('field_input', Blockly.FieldTextInput);
|
||||
fieldRegistry.register('field_input', FieldTextInput);
|
||||
|
||||
exports = FieldTextInput;
|
||||
|
||||
@@ -10,26 +10,24 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.FieldVariable');
|
||||
goog.module('Blockly.FieldVariable');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/** @suppress {extraRequire} */
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
const FieldDropdown = goog.require('Blockly.FieldDropdown');
|
||||
const Menu = goog.requireType('Blockly.Menu');
|
||||
const MenuItem = goog.requireType('Blockly.MenuItem');
|
||||
const Msg = goog.require('Blockly.Msg');
|
||||
const Size = goog.require('Blockly.utils.Size');
|
||||
const VariableModel = goog.require('Blockly.VariableModel');
|
||||
const Variables = goog.require('Blockly.Variables');
|
||||
const Xml = goog.require('Blockly.Xml');
|
||||
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
||||
const internalConstants = goog.require('Blockly.internalConstants');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
const {replaceMessageReferences} = goog.require('Blockly.utils');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockChange');
|
||||
goog.require('Blockly.FieldDropdown');
|
||||
goog.require('Blockly.fieldRegistry');
|
||||
goog.require('Blockly.Msg');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.utils.Size');
|
||||
goog.require('Blockly.VariableModel');
|
||||
goog.require('Blockly.Variables');
|
||||
goog.require('Blockly.Xml');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
goog.requireType('Blockly.Menu');
|
||||
goog.requireType('Blockly.MenuItem');
|
||||
|
||||
|
||||
/**
|
||||
@@ -44,13 +42,14 @@ goog.requireType('Blockly.MenuItem');
|
||||
* @param {string=} opt_defaultType The type of variable to create if this
|
||||
* field's value is not explicitly set. Defaults to ''.
|
||||
* @param {Object=} opt_config A map of options used to configure the field.
|
||||
* See the [field creation documentation]{@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/variable#creation}
|
||||
* See the [field creation documentation]{@link
|
||||
* https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/variable#creation}
|
||||
* for a list of properties this parameter supports.
|
||||
* @extends {Blockly.FieldDropdown}
|
||||
* @extends {FieldDropdown}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldVariable = function(varName, opt_validator, opt_variableTypes,
|
||||
opt_defaultType, opt_config) {
|
||||
const FieldVariable = function(
|
||||
varName, opt_validator, opt_variableTypes, opt_defaultType, opt_config) {
|
||||
// The FieldDropdown constructor expects the field's initial value to be
|
||||
// the first entry in the menu generator, which it may or may not be.
|
||||
// Just do the relevant parts of the constructor.
|
||||
@@ -59,10 +58,10 @@ Blockly.FieldVariable = function(varName, opt_validator, opt_variableTypes,
|
||||
* An array of options for a dropdown list,
|
||||
* or a function which generates these options.
|
||||
* @type {(!Array<!Array>|
|
||||
* !function(this:Blockly.FieldDropdown): !Array<!Array>)}
|
||||
* !function(this:FieldDropdown): !Array<!Array>)}
|
||||
* @protected
|
||||
*/
|
||||
this.menuGenerator_ = Blockly.FieldVariable.dropdownCreate;
|
||||
this.menuGenerator_ = FieldVariable.dropdownCreate;
|
||||
|
||||
/**
|
||||
* The initial variable name passed to this field's constructor, or an
|
||||
@@ -74,11 +73,11 @@ Blockly.FieldVariable = function(varName, opt_validator, opt_variableTypes,
|
||||
|
||||
/**
|
||||
* The size of the area rendered by the field.
|
||||
* @type {Blockly.utils.Size}
|
||||
* @type {Size}
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
this.size_ = new Blockly.utils.Size(0, 0);
|
||||
this.size_ = new Size(0, 0);
|
||||
|
||||
opt_config && this.configure_(opt_config);
|
||||
opt_validator && this.setValidator(opt_validator);
|
||||
@@ -87,19 +86,19 @@ Blockly.FieldVariable = function(varName, opt_validator, opt_variableTypes,
|
||||
this.setTypes_(opt_variableTypes, opt_defaultType);
|
||||
}
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.FieldVariable, Blockly.FieldDropdown);
|
||||
inherits(FieldVariable, FieldDropdown);
|
||||
|
||||
/**
|
||||
* Construct a FieldVariable from a JSON arg object,
|
||||
* dereferencing any string table references.
|
||||
* @param {!Object} options A JSON object with options (variable,
|
||||
* variableTypes, and defaultType).
|
||||
* @return {!Blockly.FieldVariable} The new field instance.
|
||||
* @return {!FieldVariable} The new field instance.
|
||||
* @package
|
||||
* @nocollapse
|
||||
*/
|
||||
Blockly.FieldVariable.fromJson = function(options) {
|
||||
var varName = Blockly.utils.replaceMessageReferences(options['variable']);
|
||||
FieldVariable.fromJson = function(options) {
|
||||
const varName = replaceMessageReferences(options['variable']);
|
||||
// `this` might be a subclass of FieldVariable if that class doesn't override
|
||||
// the static fromJson method.
|
||||
return new this(varName, undefined, undefined, undefined, options);
|
||||
@@ -110,15 +109,15 @@ Blockly.FieldVariable.fromJson = function(options) {
|
||||
* are not. Editable fields should also be serializable.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.SERIALIZABLE = true;
|
||||
FieldVariable.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Configure the field based on the given map of options.
|
||||
* @param {!Object} config A map of options to configure the field based on.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.configure_ = function(config) {
|
||||
Blockly.FieldVariable.superClass_.configure_.call(this, config);
|
||||
FieldVariable.prototype.configure_ = function(config) {
|
||||
FieldVariable.superClass_.configure_.call(this, config);
|
||||
this.setTypes_(config['variableTypes'], config['defaultType']);
|
||||
};
|
||||
|
||||
@@ -128,13 +127,13 @@ Blockly.FieldVariable.prototype.configure_ = function(config) {
|
||||
* variable rather than let the value be invalid.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.initModel = function() {
|
||||
FieldVariable.prototype.initModel = function() {
|
||||
if (this.variable_) {
|
||||
return; // Initialization already happened.
|
||||
}
|
||||
var variable = Blockly.Variables.getOrCreateVariablePackage(
|
||||
this.sourceBlock_.workspace, null,
|
||||
this.defaultVariableName, this.defaultType_);
|
||||
const variable = Variables.getOrCreateVariablePackage(
|
||||
this.sourceBlock_.workspace, null, this.defaultVariableName,
|
||||
this.defaultType_);
|
||||
|
||||
// Don't call setValue because we don't want to cause a rerender.
|
||||
this.doValueUpdate_(variable.getId());
|
||||
@@ -143,10 +142,10 @@ Blockly.FieldVariable.prototype.initModel = function() {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.shouldAddBorderRect_ = function() {
|
||||
return Blockly.FieldVariable.superClass_.shouldAddBorderRect_.call(this) &&
|
||||
(!this.getConstants().FIELD_DROPDOWN_NO_BORDER_RECT_SHADOW ||
|
||||
this.sourceBlock_.type != 'variables_get');
|
||||
FieldVariable.prototype.shouldAddBorderRect_ = function() {
|
||||
return FieldVariable.superClass_.shouldAddBorderRect_.call(this) &&
|
||||
(!this.getConstants().FIELD_DROPDOWN_NO_BORDER_RECT_SHADOW ||
|
||||
this.sourceBlock_.type != 'variables_get');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -154,23 +153,24 @@ Blockly.FieldVariable.prototype.shouldAddBorderRect_ = function() {
|
||||
* @param {!Element} fieldElement The element containing information about the
|
||||
* variable field's state.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.fromXml = function(fieldElement) {
|
||||
var id = fieldElement.getAttribute('id');
|
||||
var variableName = fieldElement.textContent;
|
||||
FieldVariable.prototype.fromXml = function(fieldElement) {
|
||||
const id = fieldElement.getAttribute('id');
|
||||
const variableName = fieldElement.textContent;
|
||||
// 'variabletype' should be lowercase, but until July 2019 it was sometimes
|
||||
// recorded as 'variableType'. Thus we need to check for both.
|
||||
var variableType = fieldElement.getAttribute('variabletype') ||
|
||||
const variableType = fieldElement.getAttribute('variabletype') ||
|
||||
fieldElement.getAttribute('variableType') || '';
|
||||
|
||||
var variable = Blockly.Variables.getOrCreateVariablePackage(
|
||||
const variable = Variables.getOrCreateVariablePackage(
|
||||
this.sourceBlock_.workspace, id, variableName, variableType);
|
||||
|
||||
// This should never happen :)
|
||||
if (variableType != null && variableType !== variable.type) {
|
||||
throw Error('Serialized variable type with id \'' +
|
||||
variable.getId() + '\' had type ' + variable.type + ', and ' +
|
||||
'does not match variable field that references it: ' +
|
||||
Blockly.Xml.domToText(fieldElement) + '.');
|
||||
throw Error(
|
||||
'Serialized variable type with id \'' + variable.getId() +
|
||||
'\' had type ' + variable.type + ', and ' +
|
||||
'does not match variable field that references it: ' +
|
||||
Xml.domToText(fieldElement) + '.');
|
||||
}
|
||||
|
||||
this.setValue(variable.getId());
|
||||
@@ -182,7 +182,7 @@ Blockly.FieldVariable.prototype.fromXml = function(fieldElement) {
|
||||
* field's state.
|
||||
* @return {!Element} The element containing info about the field's state.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.toXml = function(fieldElement) {
|
||||
FieldVariable.prototype.toXml = function(fieldElement) {
|
||||
// Make sure the variable is initialized.
|
||||
this.initModel();
|
||||
|
||||
@@ -196,20 +196,20 @@ Blockly.FieldVariable.prototype.toXml = function(fieldElement) {
|
||||
|
||||
/**
|
||||
* Attach this field to a block.
|
||||
* @param {!Blockly.Block} block The block containing this field.
|
||||
* @param {!Block} block The block containing this field.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.setSourceBlock = function(block) {
|
||||
FieldVariable.prototype.setSourceBlock = function(block) {
|
||||
if (block.isShadow()) {
|
||||
throw Error('Variable fields are not allowed to exist on shadow blocks.');
|
||||
}
|
||||
Blockly.FieldVariable.superClass_.setSourceBlock.call(this, block);
|
||||
FieldVariable.superClass_.setSourceBlock.call(this, block);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the variable's ID.
|
||||
* @return {string} Current variable's ID.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.getValue = function() {
|
||||
FieldVariable.prototype.getValue = function() {
|
||||
return this.variable_ ? this.variable_.getId() : null;
|
||||
};
|
||||
|
||||
@@ -218,7 +218,7 @@ Blockly.FieldVariable.prototype.getValue = function() {
|
||||
* @return {string} The selected variable's name, or the empty string if no
|
||||
* variable is selected.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.getText = function() {
|
||||
FieldVariable.prototype.getText = function() {
|
||||
return this.variable_ ? this.variable_.name : '';
|
||||
};
|
||||
|
||||
@@ -226,11 +226,11 @@ Blockly.FieldVariable.prototype.getText = function() {
|
||||
* Get the variable model for the selected variable.
|
||||
* Not guaranteed to be in the variable map on the workspace (e.g. if accessed
|
||||
* after the variable has been deleted).
|
||||
* @return {?Blockly.VariableModel} The selected variable, or null if none was
|
||||
* @return {?VariableModel} The selected variable, or null if none was
|
||||
* selected.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.getVariable = function() {
|
||||
FieldVariable.prototype.getVariable = function() {
|
||||
return this.variable_;
|
||||
};
|
||||
|
||||
@@ -241,7 +241,7 @@ Blockly.FieldVariable.prototype.getVariable = function() {
|
||||
* a block and workspace at that point.
|
||||
* @return {?Function} Validation function, or null.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.getValidator = function() {
|
||||
FieldVariable.prototype.getValidator = function() {
|
||||
// Validators shouldn't operate on the initial setValue call.
|
||||
// Normally this is achieved by calling setValidator after setValue, but
|
||||
// this is not a possibility with variable fields.
|
||||
@@ -257,20 +257,20 @@ Blockly.FieldVariable.prototype.getValidator = function() {
|
||||
* @return {?string} The validated ID, or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
FieldVariable.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
if (opt_newValue === null) {
|
||||
return null;
|
||||
}
|
||||
var newId = /** @type {string} */ (opt_newValue);
|
||||
var variable = Blockly.Variables.getVariable(
|
||||
this.sourceBlock_.workspace, newId);
|
||||
const newId = /** @type {string} */ (opt_newValue);
|
||||
const variable = Variables.getVariable(this.sourceBlock_.workspace, newId);
|
||||
if (!variable) {
|
||||
console.warn('Variable id doesn\'t point to a real variable! ' +
|
||||
console.warn(
|
||||
'Variable id doesn\'t point to a real variable! ' +
|
||||
'ID was ' + newId);
|
||||
return null;
|
||||
}
|
||||
// Type Checks.
|
||||
var type = variable.type;
|
||||
const type = variable.type;
|
||||
if (!this.typeIsAllowed_(type)) {
|
||||
console.warn('Variable type doesn\'t match this field! Type was ' + type);
|
||||
return null;
|
||||
@@ -286,10 +286,10 @@ Blockly.FieldVariable.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
* @param {*} newId The value to be saved.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.doValueUpdate_ = function(newId) {
|
||||
this.variable_ = Blockly.Variables.getVariable(
|
||||
FieldVariable.prototype.doValueUpdate_ = function(newId) {
|
||||
this.variable_ = Variables.getVariable(
|
||||
this.sourceBlock_.workspace, /** @type {string} */ (newId));
|
||||
Blockly.FieldVariable.superClass_.doValueUpdate_.call(this, newId);
|
||||
FieldVariable.superClass_.doValueUpdate_.call(this, newId);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -298,12 +298,12 @@ Blockly.FieldVariable.prototype.doValueUpdate_ = function(newId) {
|
||||
* @return {boolean} True if the type is in the list of allowed types.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.typeIsAllowed_ = function(type) {
|
||||
var typeList = this.getVariableTypes_();
|
||||
FieldVariable.prototype.typeIsAllowed_ = function(type) {
|
||||
const typeList = this.getVariableTypes_();
|
||||
if (!typeList) {
|
||||
return true; // If it's null, all types are valid.
|
||||
}
|
||||
for (var i = 0; i < typeList.length; i++) {
|
||||
for (let i = 0; i < typeList.length; i++) {
|
||||
if (type == typeList[i]) {
|
||||
return true;
|
||||
}
|
||||
@@ -317,9 +317,9 @@ Blockly.FieldVariable.prototype.typeIsAllowed_ = function(type) {
|
||||
* @throws {Error} if variableTypes is an empty array.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.getVariableTypes_ = function() {
|
||||
FieldVariable.prototype.getVariableTypes_ = function() {
|
||||
// TODO (#1513): Try to avoid calling this every time the field is edited.
|
||||
var variableTypes = this.variableTypes;
|
||||
let variableTypes = this.variableTypes;
|
||||
if (variableTypes === null) {
|
||||
// If variableTypes is null, return all variable types.
|
||||
if (this.sourceBlock_ && this.sourceBlock_.workspace) {
|
||||
@@ -329,9 +329,9 @@ Blockly.FieldVariable.prototype.getVariableTypes_ = function() {
|
||||
variableTypes = variableTypes || [''];
|
||||
if (variableTypes.length == 0) {
|
||||
// Throw an error if variableTypes is an empty list.
|
||||
var name = this.getText();
|
||||
throw Error('\'variableTypes\' of field variable ' +
|
||||
name + ' was an empty list');
|
||||
const name = this.getText();
|
||||
throw Error(
|
||||
'\'variableTypes\' of field variable ' + name + ' was an empty list');
|
||||
}
|
||||
return variableTypes;
|
||||
};
|
||||
@@ -346,29 +346,32 @@ Blockly.FieldVariable.prototype.getVariableTypes_ = function() {
|
||||
* field's value is not explicitly set. Defaults to ''.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.setTypes_ = function(opt_variableTypes,
|
||||
opt_defaultType) {
|
||||
FieldVariable.prototype.setTypes_ = function(
|
||||
opt_variableTypes, opt_defaultType) {
|
||||
// If you expected that the default type would be the same as the only entry
|
||||
// in the variable types array, tell the Blockly team by commenting on #1499.
|
||||
var defaultType = opt_defaultType || '';
|
||||
const defaultType = opt_defaultType || '';
|
||||
let variableTypes;
|
||||
// Set the allowable variable types. Null means all types on the workspace.
|
||||
if (opt_variableTypes == null || opt_variableTypes == undefined) {
|
||||
var variableTypes = null;
|
||||
variableTypes = null;
|
||||
} else if (Array.isArray(opt_variableTypes)) {
|
||||
var variableTypes = opt_variableTypes;
|
||||
variableTypes = opt_variableTypes;
|
||||
// Make sure the default type is valid.
|
||||
var isInArray = false;
|
||||
for (var i = 0; i < variableTypes.length; i++) {
|
||||
let isInArray = false;
|
||||
for (let i = 0; i < variableTypes.length; i++) {
|
||||
if (variableTypes[i] == defaultType) {
|
||||
isInArray = true;
|
||||
}
|
||||
}
|
||||
if (!isInArray) {
|
||||
throw Error('Invalid default type \'' + defaultType + '\' in ' +
|
||||
throw Error(
|
||||
'Invalid default type \'' + defaultType + '\' in ' +
|
||||
'the definition of a FieldVariable');
|
||||
}
|
||||
} else {
|
||||
throw Error('\'variableTypes\' was not an array in the definition of ' +
|
||||
throw Error(
|
||||
'\'variableTypes\' was not an array in the definition of ' +
|
||||
'a FieldVariable');
|
||||
}
|
||||
// Only update the field once all checks pass.
|
||||
@@ -382,7 +385,7 @@ Blockly.FieldVariable.prototype.setTypes_ = function(opt_variableTypes,
|
||||
* be called by the block.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.refreshVariableName = function() {
|
||||
FieldVariable.prototype.refreshVariableName = function() {
|
||||
this.forceRerender();
|
||||
};
|
||||
|
||||
@@ -390,41 +393,40 @@ Blockly.FieldVariable.prototype.refreshVariableName = function() {
|
||||
* Return a sorted list of variable names for variable dropdown menus.
|
||||
* Include a special option at the end for creating a new variable name.
|
||||
* @return {!Array<!Array>} Array of variable names/id tuples.
|
||||
* @this {Blockly.FieldVariable}
|
||||
* @this {FieldVariable}
|
||||
*/
|
||||
Blockly.FieldVariable.dropdownCreate = function() {
|
||||
FieldVariable.dropdownCreate = function() {
|
||||
if (!this.variable_) {
|
||||
throw Error('Tried to call dropdownCreate on a variable field with no' +
|
||||
throw Error(
|
||||
'Tried to call dropdownCreate on a variable field with no' +
|
||||
' variable selected.');
|
||||
}
|
||||
var name = this.getText();
|
||||
var variableModelList = [];
|
||||
const name = this.getText();
|
||||
let variableModelList = [];
|
||||
if (this.sourceBlock_ && this.sourceBlock_.workspace) {
|
||||
var variableTypes = this.getVariableTypes_();
|
||||
const variableTypes = this.getVariableTypes_();
|
||||
// Get a copy of the list, so that adding rename and new variable options
|
||||
// doesn't modify the workspace's list.
|
||||
for (var i = 0; i < variableTypes.length; i++) {
|
||||
var variableType = variableTypes[i];
|
||||
var variables =
|
||||
this.sourceBlock_.workspace.getVariablesOfType(variableType);
|
||||
for (let i = 0; i < variableTypes.length; i++) {
|
||||
const variableType = variableTypes[i];
|
||||
const variables =
|
||||
this.sourceBlock_.workspace.getVariablesOfType(variableType);
|
||||
variableModelList = variableModelList.concat(variables);
|
||||
}
|
||||
}
|
||||
variableModelList.sort(Blockly.VariableModel.compareByName);
|
||||
variableModelList.sort(VariableModel.compareByName);
|
||||
|
||||
var options = [];
|
||||
for (var i = 0; i < variableModelList.length; i++) {
|
||||
const options = [];
|
||||
for (let i = 0; i < variableModelList.length; i++) {
|
||||
// Set the UUID as the internal representation of the variable.
|
||||
options[i] = [variableModelList[i].name, variableModelList[i].getId()];
|
||||
}
|
||||
options.push([Blockly.Msg['RENAME_VARIABLE'], Blockly.RENAME_VARIABLE_ID]);
|
||||
if (Blockly.Msg['DELETE_VARIABLE']) {
|
||||
options.push(
|
||||
[
|
||||
Blockly.Msg['DELETE_VARIABLE'].replace('%1', name),
|
||||
Blockly.DELETE_VARIABLE_ID
|
||||
]
|
||||
);
|
||||
options.push([Msg['RENAME_VARIABLE'], internalConstants.RENAME_VARIABLE_ID]);
|
||||
if (Msg['DELETE_VARIABLE']) {
|
||||
options.push([
|
||||
Msg['DELETE_VARIABLE'].replace('%1', name),
|
||||
internalConstants.DELETE_VARIABLE_ID
|
||||
]);
|
||||
}
|
||||
|
||||
return options;
|
||||
@@ -434,20 +436,19 @@ Blockly.FieldVariable.dropdownCreate = function() {
|
||||
* Handle the selection of an item in the variable dropdown menu.
|
||||
* Special case the 'Rename variable...' and 'Delete variable...' options.
|
||||
* In the rename case, prompt the user for a new name.
|
||||
* @param {!Blockly.Menu} menu The Menu component clicked.
|
||||
* @param {!Blockly.MenuItem} menuItem The MenuItem selected within menu.
|
||||
* @param {!Menu} menu The Menu component clicked.
|
||||
* @param {!MenuItem} menuItem The MenuItem selected within menu.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.onItemSelected_ = function(menu, menuItem) {
|
||||
var id = menuItem.getValue();
|
||||
FieldVariable.prototype.onItemSelected_ = function(menu, menuItem) {
|
||||
const id = menuItem.getValue();
|
||||
// Handle special cases.
|
||||
if (this.sourceBlock_ && this.sourceBlock_.workspace) {
|
||||
if (id == Blockly.RENAME_VARIABLE_ID) {
|
||||
if (id == internalConstants.RENAME_VARIABLE_ID) {
|
||||
// Rename variable.
|
||||
Blockly.Variables.renameVariable(
|
||||
this.sourceBlock_.workspace, this.variable_);
|
||||
Variables.renameVariable(this.sourceBlock_.workspace, this.variable_);
|
||||
return;
|
||||
} else if (id == Blockly.DELETE_VARIABLE_ID) {
|
||||
} else if (id == internalConstants.DELETE_VARIABLE_ID) {
|
||||
// Delete variable.
|
||||
this.sourceBlock_.workspace.deleteVariableById(this.variable_.getId());
|
||||
return;
|
||||
@@ -463,8 +464,10 @@ Blockly.FieldVariable.prototype.onItemSelected_ = function(menu, menuItem) {
|
||||
* @package
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.referencesVariables = function() {
|
||||
FieldVariable.prototype.referencesVariables = function() {
|
||||
return true;
|
||||
};
|
||||
|
||||
Blockly.fieldRegistry.register('field_variable', Blockly.FieldVariable);
|
||||
fieldRegistry.register('field_variable', FieldVariable);
|
||||
|
||||
exports = FieldVariable;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,38 +10,36 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.HorizontalFlyout');
|
||||
goog.module('Blockly.HorizontalFlyout');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Block');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.DropDownDiv');
|
||||
goog.require('Blockly.Flyout');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.Scrollbar');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.utils.Rect');
|
||||
goog.require('Blockly.utils.toolbox');
|
||||
goog.require('Blockly.WidgetDiv');
|
||||
|
||||
goog.requireType('Blockly.Options');
|
||||
goog.requireType('Blockly.utils.Coordinate');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Coordinate = goog.requireType('Blockly.utils.Coordinate');
|
||||
const DropDownDiv = goog.require('Blockly.DropDownDiv');
|
||||
const Flyout = goog.require('Blockly.Flyout');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Options = goog.requireType('Blockly.Options');
|
||||
const Rect = goog.require('Blockly.utils.Rect');
|
||||
const Scrollbar = goog.require('Blockly.Scrollbar');
|
||||
const WidgetDiv = goog.require('Blockly.WidgetDiv');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
const {Position} = goog.require('Blockly.utils.toolbox');
|
||||
const {getScrollDeltaPixels} = goog.require('Blockly.utils');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a flyout.
|
||||
* @param {!Blockly.Options} workspaceOptions Dictionary of options for the
|
||||
* @param {!Options} workspaceOptions Dictionary of options for the
|
||||
* workspace.
|
||||
* @extends {Blockly.Flyout}
|
||||
* @extends {Flyout}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.HorizontalFlyout = function(workspaceOptions) {
|
||||
Blockly.HorizontalFlyout.superClass_.constructor.call(this, workspaceOptions);
|
||||
const HorizontalFlyout = function(workspaceOptions) {
|
||||
HorizontalFlyout.superClass_.constructor.call(this, workspaceOptions);
|
||||
this.horizontalLayout = true;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.HorizontalFlyout, Blockly.Flyout);
|
||||
inherits(HorizontalFlyout, Flyout);
|
||||
|
||||
/**
|
||||
* Sets the translation of the flyout to match the scrollbars.
|
||||
@@ -50,23 +48,24 @@ Blockly.utils.object.inherits(Blockly.HorizontalFlyout, Blockly.Flyout);
|
||||
* similar x property.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.setMetrics_ = function(xyRatio) {
|
||||
HorizontalFlyout.prototype.setMetrics_ = function(xyRatio) {
|
||||
if (!this.isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var metricsManager = this.workspace_.getMetricsManager();
|
||||
var scrollMetrics = metricsManager.getScrollMetrics();
|
||||
var viewMetrics = metricsManager.getViewMetrics();
|
||||
var absoluteMetrics = metricsManager.getAbsoluteMetrics();
|
||||
const metricsManager = this.workspace_.getMetricsManager();
|
||||
const scrollMetrics = metricsManager.getScrollMetrics();
|
||||
const viewMetrics = metricsManager.getViewMetrics();
|
||||
const absoluteMetrics = metricsManager.getAbsoluteMetrics();
|
||||
|
||||
if (typeof xyRatio.x == 'number') {
|
||||
this.workspace_.scrollX =
|
||||
-(scrollMetrics.left +
|
||||
(scrollMetrics.width - viewMetrics.width) * xyRatio.x);
|
||||
(scrollMetrics.width - viewMetrics.width) * xyRatio.x);
|
||||
}
|
||||
|
||||
this.workspace_.translate(this.workspace_.scrollX + absoluteMetrics.left,
|
||||
this.workspace_.translate(
|
||||
this.workspace_.scrollX + absoluteMetrics.left,
|
||||
this.workspace_.scrollY + absoluteMetrics.top);
|
||||
};
|
||||
|
||||
@@ -74,7 +73,7 @@ Blockly.HorizontalFlyout.prototype.setMetrics_ = function(xyRatio) {
|
||||
* Calculates the x coordinate for the flyout position.
|
||||
* @return {number} X coordinate.
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.getX = function() {
|
||||
HorizontalFlyout.prototype.getX = function() {
|
||||
// X is always 0 since this is a horizontal flyout.
|
||||
return 0;
|
||||
};
|
||||
@@ -83,17 +82,17 @@ Blockly.HorizontalFlyout.prototype.getX = function() {
|
||||
* Calculates the y coordinate for the flyout position.
|
||||
* @return {number} Y coordinate.
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.getY = function() {
|
||||
HorizontalFlyout.prototype.getY = function() {
|
||||
if (!this.isVisible()) {
|
||||
return 0;
|
||||
}
|
||||
var metricsManager = this.targetWorkspace.getMetricsManager();
|
||||
var absoluteMetrics = metricsManager.getAbsoluteMetrics();
|
||||
var viewMetrics = metricsManager.getViewMetrics();
|
||||
var toolboxMetrics = metricsManager.getToolboxMetrics();
|
||||
const metricsManager = this.targetWorkspace.getMetricsManager();
|
||||
const absoluteMetrics = metricsManager.getAbsoluteMetrics();
|
||||
const viewMetrics = metricsManager.getViewMetrics();
|
||||
const toolboxMetrics = metricsManager.getToolboxMetrics();
|
||||
|
||||
var y = 0;
|
||||
var atTop = this.toolboxPosition_ == Blockly.utils.toolbox.Position.TOP;
|
||||
let y = 0;
|
||||
const atTop = this.toolboxPosition_ == Position.TOP;
|
||||
// If this flyout is not the trashcan flyout (e.g. toolbox or mutator).
|
||||
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_) {
|
||||
// If there is a category toolbox.
|
||||
@@ -131,22 +130,22 @@ Blockly.HorizontalFlyout.prototype.getY = function() {
|
||||
/**
|
||||
* Move the flyout to the edge of the workspace.
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.position = function() {
|
||||
HorizontalFlyout.prototype.position = function() {
|
||||
if (!this.isVisible() || !this.targetWorkspace.isVisible()) {
|
||||
return;
|
||||
}
|
||||
var metricsManager = this.targetWorkspace.getMetricsManager();
|
||||
var targetWorkspaceViewMetrics = metricsManager.getViewMetrics();
|
||||
const metricsManager = this.targetWorkspace.getMetricsManager();
|
||||
const targetWorkspaceViewMetrics = metricsManager.getViewMetrics();
|
||||
|
||||
// Record the width for workspace metrics.
|
||||
this.width_ = targetWorkspaceViewMetrics.width;
|
||||
|
||||
var edgeWidth = targetWorkspaceViewMetrics.width - 2 * this.CORNER_RADIUS;
|
||||
var edgeHeight = this.height_ - this.CORNER_RADIUS;
|
||||
const edgeWidth = targetWorkspaceViewMetrics.width - 2 * this.CORNER_RADIUS;
|
||||
const edgeHeight = this.height_ - this.CORNER_RADIUS;
|
||||
this.setBackgroundPath_(edgeWidth, edgeHeight);
|
||||
|
||||
var x = this.getX();
|
||||
var y = this.getY();
|
||||
const x = this.getX();
|
||||
const y = this.getY();
|
||||
|
||||
this.positionAt_(this.width_, this.height_, x, y);
|
||||
};
|
||||
@@ -159,11 +158,10 @@ Blockly.HorizontalFlyout.prototype.position = function() {
|
||||
* rounded corners.
|
||||
* @private
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.setBackgroundPath_ = function(
|
||||
width, height) {
|
||||
var atTop = this.toolboxPosition_ == Blockly.utils.toolbox.Position.TOP;
|
||||
HorizontalFlyout.prototype.setBackgroundPath_ = function(width, height) {
|
||||
const atTop = this.toolboxPosition_ == Position.TOP;
|
||||
// Start at top left.
|
||||
var path = ['M 0,' + (atTop ? 0 : this.CORNER_RADIUS)];
|
||||
const path = ['M 0,' + (atTop ? 0 : this.CORNER_RADIUS)];
|
||||
|
||||
if (atTop) {
|
||||
// Top.
|
||||
@@ -171,20 +169,24 @@ Blockly.HorizontalFlyout.prototype.setBackgroundPath_ = function(
|
||||
// Right.
|
||||
path.push('v', height);
|
||||
// Bottom.
|
||||
path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
|
||||
path.push(
|
||||
'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
|
||||
-this.CORNER_RADIUS, this.CORNER_RADIUS);
|
||||
path.push('h', -width);
|
||||
// Left.
|
||||
path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
|
||||
path.push(
|
||||
'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
|
||||
-this.CORNER_RADIUS, -this.CORNER_RADIUS);
|
||||
path.push('z');
|
||||
} else {
|
||||
// Top.
|
||||
path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
|
||||
path.push(
|
||||
'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
|
||||
this.CORNER_RADIUS, -this.CORNER_RADIUS);
|
||||
path.push('h', width);
|
||||
// Right.
|
||||
path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
|
||||
path.push(
|
||||
'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
|
||||
this.CORNER_RADIUS, this.CORNER_RADIUS);
|
||||
path.push('v', height);
|
||||
// Bottom.
|
||||
@@ -198,7 +200,7 @@ Blockly.HorizontalFlyout.prototype.setBackgroundPath_ = function(
|
||||
/**
|
||||
* Scroll the flyout to the top.
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.scrollToStart = function() {
|
||||
HorizontalFlyout.prototype.scrollToStart = function() {
|
||||
this.workspace_.scrollbar.setX(this.RTL ? Infinity : 0);
|
||||
};
|
||||
|
||||
@@ -207,20 +209,20 @@ Blockly.HorizontalFlyout.prototype.scrollToStart = function() {
|
||||
* @param {!Event} e Mouse wheel scroll event.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.wheel_ = function(e) {
|
||||
var scrollDelta = Blockly.utils.getScrollDeltaPixels(e);
|
||||
var delta = scrollDelta.x || scrollDelta.y;
|
||||
HorizontalFlyout.prototype.wheel_ = function(e) {
|
||||
const scrollDelta = getScrollDeltaPixels(e);
|
||||
const delta = scrollDelta.x || scrollDelta.y;
|
||||
|
||||
if (delta) {
|
||||
var metricsManager = this.workspace_.getMetricsManager();
|
||||
var scrollMetrics = metricsManager.getScrollMetrics();
|
||||
var viewMetrics = metricsManager.getViewMetrics();
|
||||
const metricsManager = this.workspace_.getMetricsManager();
|
||||
const scrollMetrics = metricsManager.getScrollMetrics();
|
||||
const viewMetrics = metricsManager.getViewMetrics();
|
||||
|
||||
var pos = (viewMetrics.left - scrollMetrics.left) + delta;
|
||||
const pos = (viewMetrics.left - scrollMetrics.left) + delta;
|
||||
this.workspace_.scrollbar.setX(pos);
|
||||
// When the flyout moves from a wheel event, hide WidgetDiv and DropDownDiv.
|
||||
Blockly.WidgetDiv.hide();
|
||||
Blockly.DropDownDiv.hideWithoutAnimation();
|
||||
WidgetDiv.hide();
|
||||
DropDownDiv.hideWithoutAnimation();
|
||||
}
|
||||
|
||||
// Don't scroll the page.
|
||||
@@ -235,39 +237,40 @@ Blockly.HorizontalFlyout.prototype.wheel_ = function(e) {
|
||||
* @param {!Array<number>} gaps The visible gaps between blocks.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.layout_ = function(contents, gaps) {
|
||||
HorizontalFlyout.prototype.layout_ = function(contents, gaps) {
|
||||
this.workspace_.scale = this.targetWorkspace.scale;
|
||||
var margin = this.MARGIN;
|
||||
var cursorX = margin + this.tabWidth_;
|
||||
var cursorY = margin;
|
||||
const margin = this.MARGIN;
|
||||
let cursorX = margin + this.tabWidth_;
|
||||
const cursorY = margin;
|
||||
if (this.RTL) {
|
||||
contents = contents.reverse();
|
||||
}
|
||||
|
||||
for (var i = 0, item; (item = contents[i]); i++) {
|
||||
for (let i = 0, item; (item = contents[i]); i++) {
|
||||
if (item.type == 'block') {
|
||||
var block = item.block;
|
||||
var allBlocks = block.getDescendants(false);
|
||||
for (var j = 0, child; (child = allBlocks[j]); j++) {
|
||||
const block = item.block;
|
||||
const allBlocks = block.getDescendants(false);
|
||||
for (let j = 0, child; (child = allBlocks[j]); j++) {
|
||||
// Mark blocks as being inside a flyout. This is used to detect and
|
||||
// prevent the closure of the flyout if the user right-clicks on such a
|
||||
// block.
|
||||
child.isInFlyout = true;
|
||||
}
|
||||
block.render();
|
||||
var root = block.getSvgRoot();
|
||||
var blockHW = block.getHeightWidth();
|
||||
const root = block.getSvgRoot();
|
||||
const blockHW = block.getHeightWidth();
|
||||
|
||||
// Figure out where to place the block.
|
||||
var tab = block.outputConnection ? this.tabWidth_ : 0;
|
||||
const tab = block.outputConnection ? this.tabWidth_ : 0;
|
||||
let moveX;
|
||||
if (this.RTL) {
|
||||
var moveX = cursorX + blockHW.width;
|
||||
moveX = cursorX + blockHW.width;
|
||||
} else {
|
||||
var moveX = cursorX - tab;
|
||||
moveX = cursorX - tab;
|
||||
}
|
||||
block.moveBy(moveX, cursorY);
|
||||
|
||||
var rect = this.createRect_(block, moveX, cursorY, blockHW, i);
|
||||
const rect = this.createRect_(block, moveX, cursorY, blockHW, i);
|
||||
cursorX += (blockHW.width + gaps[i]);
|
||||
|
||||
this.addBlockListeners_(root, block, rect);
|
||||
@@ -282,19 +285,19 @@ Blockly.HorizontalFlyout.prototype.layout_ = function(contents, gaps) {
|
||||
* Determine if a drag delta is toward the workspace, based on the position
|
||||
* and orientation of the flyout. This is used in determineDragIntention_ to
|
||||
* determine if a new block should be created or if the flyout should scroll.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the position at mouse down, in pixel units.
|
||||
* @return {boolean} True if the drag is toward the workspace.
|
||||
* @package
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.isDragTowardWorkspace = function(
|
||||
HorizontalFlyout.prototype.isDragTowardWorkspace = function(
|
||||
currentDragDeltaXY) {
|
||||
var dx = currentDragDeltaXY.x;
|
||||
var dy = currentDragDeltaXY.y;
|
||||
const dx = currentDragDeltaXY.x;
|
||||
const dy = currentDragDeltaXY.y;
|
||||
// Direction goes from -180 to 180, with 0 toward the right and 90 on top.
|
||||
var dragDirection = Math.atan2(dy, dx) / Math.PI * 180;
|
||||
const dragDirection = Math.atan2(dy, dx) / Math.PI * 180;
|
||||
|
||||
var range = this.dragAngleRange_;
|
||||
const range = this.dragAngleRange_;
|
||||
// Check for up or down dragging.
|
||||
if ((dragDirection < 90 + range && dragDirection > 90 - range) ||
|
||||
(dragDirection > -90 - range && dragDirection < -90 + range)) {
|
||||
@@ -306,28 +309,28 @@ Blockly.HorizontalFlyout.prototype.isDragTowardWorkspace = function(
|
||||
/**
|
||||
* Returns the bounding rectangle of the drag target area in pixel units
|
||||
* relative to viewport.
|
||||
* @return {?Blockly.utils.Rect} The component's bounding box. Null if drag
|
||||
* @return {?Rect} The component's bounding box. Null if drag
|
||||
* target area should be ignored.
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.getClientRect = function() {
|
||||
HorizontalFlyout.prototype.getClientRect = function() {
|
||||
if (!this.svgGroup_ || this.autoClose || !this.isVisible()) {
|
||||
// The bounding rectangle won't compute correctly if the flyout is closed
|
||||
// and auto-close flyouts aren't valid drag targets (or delete areas).
|
||||
return null;
|
||||
}
|
||||
|
||||
var flyoutRect = this.svgGroup_.getBoundingClientRect();
|
||||
const flyoutRect = this.svgGroup_.getBoundingClientRect();
|
||||
// BIG_NUM is offscreen padding so that blocks dragged beyond the shown flyout
|
||||
// area are still deleted. Must be larger than the largest screen size,
|
||||
// but be smaller than half Number.MAX_SAFE_INTEGER (not available on IE).
|
||||
var BIG_NUM = 1000000000;
|
||||
var top = flyoutRect.top;
|
||||
const BIG_NUM = 1000000000;
|
||||
const top = flyoutRect.top;
|
||||
|
||||
if (this.toolboxPosition_ == Blockly.utils.toolbox.Position.TOP) {
|
||||
var height = flyoutRect.height;
|
||||
return new Blockly.utils.Rect(-BIG_NUM, top + height, -BIG_NUM, BIG_NUM);
|
||||
if (this.toolboxPosition_ == Position.TOP) {
|
||||
const height = flyoutRect.height;
|
||||
return new Rect(-BIG_NUM, top + height, -BIG_NUM, BIG_NUM);
|
||||
} else { // Bottom.
|
||||
return new Blockly.utils.Rect(top, BIG_NUM, -BIG_NUM, BIG_NUM);
|
||||
return new Rect(top, BIG_NUM, -BIG_NUM, BIG_NUM);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -336,36 +339,37 @@ Blockly.HorizontalFlyout.prototype.getClientRect = function() {
|
||||
* For RTL: Lay out the blocks right-aligned.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.reflowInternal_ = function() {
|
||||
HorizontalFlyout.prototype.reflowInternal_ = function() {
|
||||
this.workspace_.scale = this.getFlyoutScale();
|
||||
var flyoutHeight = 0;
|
||||
var blocks = this.workspace_.getTopBlocks(false);
|
||||
for (var i = 0, block; (block = blocks[i]); i++) {
|
||||
let flyoutHeight = 0;
|
||||
const blocks = this.workspace_.getTopBlocks(false);
|
||||
for (let i = 0, block; (block = blocks[i]); i++) {
|
||||
flyoutHeight = Math.max(flyoutHeight, block.getHeightWidth().height);
|
||||
}
|
||||
var buttons = this.buttons_;
|
||||
for (var i = 0, button; (button = buttons[i]); i++) {
|
||||
const buttons = this.buttons_;
|
||||
for (let i = 0, button; (button = buttons[i]); i++) {
|
||||
flyoutHeight = Math.max(flyoutHeight, button.height);
|
||||
}
|
||||
flyoutHeight += this.MARGIN * 1.5;
|
||||
flyoutHeight *= this.workspace_.scale;
|
||||
flyoutHeight += Blockly.Scrollbar.scrollbarThickness;
|
||||
flyoutHeight += Scrollbar.scrollbarThickness;
|
||||
|
||||
if (this.height_ != flyoutHeight) {
|
||||
for (var i = 0, block; (block = blocks[i]); i++) {
|
||||
for (let i = 0, block; (block = blocks[i]); i++) {
|
||||
if (block.flyoutRect_) {
|
||||
this.moveRectToBlock_(block.flyoutRect_, block);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_ &&
|
||||
this.toolboxPosition_ == Blockly.utils.toolbox.Position.TOP &&
|
||||
this.toolboxPosition_ == Position.TOP &&
|
||||
!this.targetWorkspace.getToolbox()) {
|
||||
// This flyout is a simple toolbox. Reposition the workspace so that (0,0)
|
||||
// is in the correct position relative to the new absolute edge (ie
|
||||
// toolbox edge).
|
||||
this.targetWorkspace.translate(
|
||||
this.targetWorkspace.scrollX, this.targetWorkspace.scrollY + flyoutHeight);
|
||||
this.targetWorkspace.scrollX,
|
||||
this.targetWorkspace.scrollY + flyoutHeight);
|
||||
}
|
||||
|
||||
// Record the height for workspace metrics and .position.
|
||||
@@ -375,5 +379,8 @@ Blockly.HorizontalFlyout.prototype.reflowInternal_ = function() {
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.registry.register(Blockly.registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX,
|
||||
Blockly.registry.DEFAULT, Blockly.HorizontalFlyout);
|
||||
registry.register(
|
||||
registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX, registry.DEFAULT,
|
||||
HorizontalFlyout);
|
||||
|
||||
exports = HorizontalFlyout;
|
||||
|
||||
@@ -10,43 +10,45 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.VerticalFlyout');
|
||||
goog.module('Blockly.VerticalFlyout');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Coordinate = goog.requireType('Blockly.utils.Coordinate');
|
||||
const DropDownDiv = goog.require('Blockly.DropDownDiv');
|
||||
const Flyout = goog.require('Blockly.Flyout');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Options = goog.requireType('Blockly.Options');
|
||||
const Rect = goog.require('Blockly.utils.Rect');
|
||||
const Scrollbar = goog.require('Blockly.Scrollbar');
|
||||
const WidgetDiv = goog.require('Blockly.WidgetDiv');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
const {Position} = goog.require('Blockly.utils.toolbox');
|
||||
const {getScrollDeltaPixels} = goog.require('Blockly.utils');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Block');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.DropDownDiv');
|
||||
goog.require('Blockly.Flyout');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.Scrollbar');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.utils.Rect');
|
||||
goog.require('Blockly.utils.toolbox');
|
||||
goog.require('Blockly.WidgetDiv');
|
||||
|
||||
goog.requireType('Blockly.Options');
|
||||
goog.requireType('Blockly.utils.Coordinate');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a flyout.
|
||||
* @param {!Blockly.Options} workspaceOptions Dictionary of options for the
|
||||
* @param {!Options} workspaceOptions Dictionary of options for the
|
||||
* workspace.
|
||||
* @extends {Blockly.Flyout}
|
||||
* @extends {Flyout}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.VerticalFlyout = function(workspaceOptions) {
|
||||
Blockly.VerticalFlyout.superClass_.constructor.call(this, workspaceOptions);
|
||||
const VerticalFlyout = function(workspaceOptions) {
|
||||
VerticalFlyout.superClass_.constructor.call(this, workspaceOptions);
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.VerticalFlyout, Blockly.Flyout);
|
||||
inherits(VerticalFlyout, Flyout);
|
||||
|
||||
/**
|
||||
* The name of the vertical flyout in the registry.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.VerticalFlyout.registryName = 'verticalFlyout';
|
||||
VerticalFlyout.registryName = 'verticalFlyout';
|
||||
|
||||
/**
|
||||
* Sets the translation of the flyout to match the scrollbars.
|
||||
@@ -55,21 +57,22 @@ Blockly.VerticalFlyout.registryName = 'verticalFlyout';
|
||||
* similar x property.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.VerticalFlyout.prototype.setMetrics_ = function(xyRatio) {
|
||||
VerticalFlyout.prototype.setMetrics_ = function(xyRatio) {
|
||||
if (!this.isVisible()) {
|
||||
return;
|
||||
}
|
||||
var metricsManager = this.workspace_.getMetricsManager();
|
||||
var scrollMetrics = metricsManager.getScrollMetrics();
|
||||
var viewMetrics = metricsManager.getViewMetrics();
|
||||
var absoluteMetrics = metricsManager.getAbsoluteMetrics();
|
||||
const metricsManager = this.workspace_.getMetricsManager();
|
||||
const scrollMetrics = metricsManager.getScrollMetrics();
|
||||
const viewMetrics = metricsManager.getViewMetrics();
|
||||
const absoluteMetrics = metricsManager.getAbsoluteMetrics();
|
||||
|
||||
if (typeof xyRatio.y == 'number') {
|
||||
this.workspace_.scrollY =
|
||||
-(scrollMetrics.top +
|
||||
(scrollMetrics.height - viewMetrics.height) * xyRatio.y);
|
||||
(scrollMetrics.height - viewMetrics.height) * xyRatio.y);
|
||||
}
|
||||
this.workspace_.translate(this.workspace_.scrollX + absoluteMetrics.left,
|
||||
this.workspace_.translate(
|
||||
this.workspace_.scrollX + absoluteMetrics.left,
|
||||
this.workspace_.scrollY + absoluteMetrics.top);
|
||||
};
|
||||
|
||||
@@ -77,28 +80,28 @@ Blockly.VerticalFlyout.prototype.setMetrics_ = function(xyRatio) {
|
||||
* Calculates the x coordinate for the flyout position.
|
||||
* @return {number} X coordinate.
|
||||
*/
|
||||
Blockly.VerticalFlyout.prototype.getX = function() {
|
||||
VerticalFlyout.prototype.getX = function() {
|
||||
if (!this.isVisible()) {
|
||||
return 0;
|
||||
}
|
||||
var metricsManager = this.targetWorkspace.getMetricsManager();
|
||||
var absoluteMetrics = metricsManager.getAbsoluteMetrics();
|
||||
var viewMetrics = metricsManager.getViewMetrics();
|
||||
var toolboxMetrics = metricsManager.getToolboxMetrics();
|
||||
var x = 0;
|
||||
const metricsManager = this.targetWorkspace.getMetricsManager();
|
||||
const absoluteMetrics = metricsManager.getAbsoluteMetrics();
|
||||
const viewMetrics = metricsManager.getViewMetrics();
|
||||
const toolboxMetrics = metricsManager.getToolboxMetrics();
|
||||
let x = 0;
|
||||
|
||||
// If this flyout is not the trashcan flyout (e.g. toolbox or mutator).
|
||||
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_) {
|
||||
// If there is a category toolbox.
|
||||
if (this.targetWorkspace.getToolbox()) {
|
||||
if (this.toolboxPosition_ == Blockly.utils.toolbox.Position.LEFT) {
|
||||
if (this.toolboxPosition_ == Position.LEFT) {
|
||||
x = toolboxMetrics.width;
|
||||
} else {
|
||||
x = viewMetrics.width - this.width_;
|
||||
}
|
||||
// Simple (flyout-only) toolbox.
|
||||
} else {
|
||||
if (this.toolboxPosition_ == Blockly.utils.toolbox.Position.LEFT) {
|
||||
if (this.toolboxPosition_ == Position.LEFT) {
|
||||
x = 0;
|
||||
} else {
|
||||
// The simple flyout does not cover the workspace.
|
||||
@@ -107,7 +110,7 @@ Blockly.VerticalFlyout.prototype.getX = function() {
|
||||
}
|
||||
// Trashcan flyout is opposite the main flyout.
|
||||
} else {
|
||||
if (this.toolboxPosition_ == Blockly.utils.toolbox.Position.LEFT) {
|
||||
if (this.toolboxPosition_ == Position.LEFT) {
|
||||
x = 0;
|
||||
} else {
|
||||
// Because the anchor point of the flyout is on the left, but we want
|
||||
@@ -125,7 +128,7 @@ Blockly.VerticalFlyout.prototype.getX = function() {
|
||||
* Calculates the y coordinate for the flyout position.
|
||||
* @return {number} Y coordinate.
|
||||
*/
|
||||
Blockly.VerticalFlyout.prototype.getY = function() {
|
||||
VerticalFlyout.prototype.getY = function() {
|
||||
// Y is always 0 since this is a vertical flyout.
|
||||
return 0;
|
||||
};
|
||||
@@ -133,22 +136,22 @@ Blockly.VerticalFlyout.prototype.getY = function() {
|
||||
/**
|
||||
* Move the flyout to the edge of the workspace.
|
||||
*/
|
||||
Blockly.VerticalFlyout.prototype.position = function() {
|
||||
VerticalFlyout.prototype.position = function() {
|
||||
if (!this.isVisible() || !this.targetWorkspace.isVisible()) {
|
||||
return;
|
||||
}
|
||||
var metricsManager = this.targetWorkspace.getMetricsManager();
|
||||
var targetWorkspaceViewMetrics = metricsManager.getViewMetrics();
|
||||
const metricsManager = this.targetWorkspace.getMetricsManager();
|
||||
const targetWorkspaceViewMetrics = metricsManager.getViewMetrics();
|
||||
|
||||
// Record the height for workspace metrics.
|
||||
this.height_ = targetWorkspaceViewMetrics.height;
|
||||
|
||||
var edgeWidth = this.width_ - this.CORNER_RADIUS;
|
||||
var edgeHeight = targetWorkspaceViewMetrics.height - 2 * this.CORNER_RADIUS;
|
||||
const edgeWidth = this.width_ - this.CORNER_RADIUS;
|
||||
const edgeHeight = targetWorkspaceViewMetrics.height - 2 * this.CORNER_RADIUS;
|
||||
this.setBackgroundPath_(edgeWidth, edgeHeight);
|
||||
|
||||
var x = this.getX();
|
||||
var y = this.getY();
|
||||
const x = this.getX();
|
||||
const y = this.getY();
|
||||
|
||||
this.positionAt_(this.width_, this.height_, x, y);
|
||||
};
|
||||
@@ -161,26 +164,24 @@ Blockly.VerticalFlyout.prototype.position = function() {
|
||||
* rounded corners.
|
||||
* @private
|
||||
*/
|
||||
Blockly.VerticalFlyout.prototype.setBackgroundPath_ = function(width, height) {
|
||||
var atRight = this.toolboxPosition_ == Blockly.utils.toolbox.Position.RIGHT;
|
||||
var totalWidth = width + this.CORNER_RADIUS;
|
||||
VerticalFlyout.prototype.setBackgroundPath_ = function(width, height) {
|
||||
const atRight = this.toolboxPosition_ == Position.RIGHT;
|
||||
const totalWidth = width + this.CORNER_RADIUS;
|
||||
|
||||
// Decide whether to start on the left or right.
|
||||
var path = ['M ' + (atRight ? totalWidth : 0) + ',0'];
|
||||
const path = ['M ' + (atRight ? totalWidth : 0) + ',0'];
|
||||
// Top.
|
||||
path.push('h', atRight ? -width : width);
|
||||
// Rounded corner.
|
||||
path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0,
|
||||
atRight ? 0 : 1,
|
||||
atRight ? -this.CORNER_RADIUS : this.CORNER_RADIUS,
|
||||
this.CORNER_RADIUS);
|
||||
path.push(
|
||||
'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, atRight ? 0 : 1,
|
||||
atRight ? -this.CORNER_RADIUS : this.CORNER_RADIUS, this.CORNER_RADIUS);
|
||||
// Side closest to workspace.
|
||||
path.push('v', Math.max(0, height));
|
||||
// Rounded corner.
|
||||
path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0,
|
||||
atRight ? 0 : 1,
|
||||
atRight ? this.CORNER_RADIUS : -this.CORNER_RADIUS,
|
||||
this.CORNER_RADIUS);
|
||||
path.push(
|
||||
'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, atRight ? 0 : 1,
|
||||
atRight ? this.CORNER_RADIUS : -this.CORNER_RADIUS, this.CORNER_RADIUS);
|
||||
// Bottom.
|
||||
path.push('h', atRight ? width : -width);
|
||||
path.push('z');
|
||||
@@ -190,7 +191,7 @@ Blockly.VerticalFlyout.prototype.setBackgroundPath_ = function(width, height) {
|
||||
/**
|
||||
* Scroll the flyout to the top.
|
||||
*/
|
||||
Blockly.VerticalFlyout.prototype.scrollToStart = function() {
|
||||
VerticalFlyout.prototype.scrollToStart = function() {
|
||||
this.workspace_.scrollbar.setY(0);
|
||||
};
|
||||
|
||||
@@ -199,19 +200,19 @@ Blockly.VerticalFlyout.prototype.scrollToStart = function() {
|
||||
* @param {!Event} e Mouse wheel scroll event.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.VerticalFlyout.prototype.wheel_ = function(e) {
|
||||
var scrollDelta = Blockly.utils.getScrollDeltaPixels(e);
|
||||
VerticalFlyout.prototype.wheel_ = function(e) {
|
||||
const scrollDelta = getScrollDeltaPixels(e);
|
||||
|
||||
if (scrollDelta.y) {
|
||||
var metricsManager = this.workspace_.getMetricsManager();
|
||||
var scrollMetrics = metricsManager.getScrollMetrics();
|
||||
var viewMetrics = metricsManager.getViewMetrics();
|
||||
var pos = (viewMetrics.top - scrollMetrics.top) + scrollDelta.y;
|
||||
const metricsManager = this.workspace_.getMetricsManager();
|
||||
const scrollMetrics = metricsManager.getScrollMetrics();
|
||||
const viewMetrics = metricsManager.getViewMetrics();
|
||||
const pos = (viewMetrics.top - scrollMetrics.top) + scrollDelta.y;
|
||||
|
||||
this.workspace_.scrollbar.setY(pos);
|
||||
// When the flyout moves from a wheel event, hide WidgetDiv and DropDownDiv.
|
||||
Blockly.WidgetDiv.hide();
|
||||
Blockly.DropDownDiv.hideWithoutAnimation();
|
||||
WidgetDiv.hide();
|
||||
DropDownDiv.hideWithoutAnimation();
|
||||
}
|
||||
|
||||
// Don't scroll the page.
|
||||
@@ -226,30 +227,30 @@ Blockly.VerticalFlyout.prototype.wheel_ = function(e) {
|
||||
* @param {!Array<number>} gaps The visible gaps between blocks.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.VerticalFlyout.prototype.layout_ = function(contents, gaps) {
|
||||
VerticalFlyout.prototype.layout_ = function(contents, gaps) {
|
||||
this.workspace_.scale = this.targetWorkspace.scale;
|
||||
var margin = this.MARGIN;
|
||||
var cursorX = this.RTL ? margin : margin + this.tabWidth_;
|
||||
var cursorY = margin;
|
||||
const margin = this.MARGIN;
|
||||
const cursorX = this.RTL ? margin : margin + this.tabWidth_;
|
||||
let cursorY = margin;
|
||||
|
||||
for (var i = 0, item; (item = contents[i]); i++) {
|
||||
for (let i = 0, item; (item = contents[i]); i++) {
|
||||
if (item.type == 'block') {
|
||||
var block = item.block;
|
||||
var allBlocks = block.getDescendants(false);
|
||||
for (var j = 0, child; (child = allBlocks[j]); j++) {
|
||||
const block = item.block;
|
||||
const allBlocks = block.getDescendants(false);
|
||||
for (let j = 0, child; (child = allBlocks[j]); j++) {
|
||||
// Mark blocks as being inside a flyout. This is used to detect and
|
||||
// prevent the closure of the flyout if the user right-clicks on such a
|
||||
// block.
|
||||
child.isInFlyout = true;
|
||||
}
|
||||
block.render();
|
||||
var root = block.getSvgRoot();
|
||||
var blockHW = block.getHeightWidth();
|
||||
var moveX = block.outputConnection ? cursorX - this.tabWidth_ : cursorX;
|
||||
const root = block.getSvgRoot();
|
||||
const blockHW = block.getHeightWidth();
|
||||
const moveX = block.outputConnection ? cursorX - this.tabWidth_ : cursorX;
|
||||
block.moveBy(moveX, cursorY);
|
||||
|
||||
var rect = this.createRect_(block,
|
||||
this.RTL ? moveX - blockHW.width : moveX, cursorY, blockHW, i);
|
||||
const rect = this.createRect_(
|
||||
block, this.RTL ? moveX - blockHW.width : moveX, cursorY, blockHW, i);
|
||||
|
||||
this.addBlockListeners_(root, block, rect);
|
||||
|
||||
@@ -265,19 +266,18 @@ Blockly.VerticalFlyout.prototype.layout_ = function(contents, gaps) {
|
||||
* Determine if a drag delta is toward the workspace, based on the position
|
||||
* and orientation of the flyout. This is used in determineDragIntention_ to
|
||||
* determine if a new block should be created or if the flyout should scroll.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the position at mouse down, in pixel units.
|
||||
* @return {boolean} True if the drag is toward the workspace.
|
||||
* @package
|
||||
*/
|
||||
Blockly.VerticalFlyout.prototype.isDragTowardWorkspace = function(
|
||||
currentDragDeltaXY) {
|
||||
var dx = currentDragDeltaXY.x;
|
||||
var dy = currentDragDeltaXY.y;
|
||||
VerticalFlyout.prototype.isDragTowardWorkspace = function(currentDragDeltaXY) {
|
||||
const dx = currentDragDeltaXY.x;
|
||||
const dy = currentDragDeltaXY.y;
|
||||
// Direction goes from -180 to 180, with 0 toward the right and 90 on top.
|
||||
var dragDirection = Math.atan2(dy, dx) / Math.PI * 180;
|
||||
const dragDirection = Math.atan2(dy, dx) / Math.PI * 180;
|
||||
|
||||
var range = this.dragAngleRange_;
|
||||
const range = this.dragAngleRange_;
|
||||
// Check for left or right dragging.
|
||||
if ((dragDirection < range && dragDirection > -range) ||
|
||||
(dragDirection < -180 + range || dragDirection > 180 - range)) {
|
||||
@@ -289,28 +289,28 @@ Blockly.VerticalFlyout.prototype.isDragTowardWorkspace = function(
|
||||
/**
|
||||
* Returns the bounding rectangle of the drag target area in pixel units
|
||||
* relative to viewport.
|
||||
* @return {?Blockly.utils.Rect} The component's bounding box. Null if drag
|
||||
* @return {?Rect} The component's bounding box. Null if drag
|
||||
* target area should be ignored.
|
||||
*/
|
||||
Blockly.VerticalFlyout.prototype.getClientRect = function() {
|
||||
VerticalFlyout.prototype.getClientRect = function() {
|
||||
if (!this.svgGroup_ || this.autoClose || !this.isVisible()) {
|
||||
// The bounding rectangle won't compute correctly if the flyout is closed
|
||||
// and auto-close flyouts aren't valid drag targets (or delete areas).
|
||||
return null;
|
||||
}
|
||||
|
||||
var flyoutRect = this.svgGroup_.getBoundingClientRect();
|
||||
const flyoutRect = this.svgGroup_.getBoundingClientRect();
|
||||
// BIG_NUM is offscreen padding so that blocks dragged beyond the shown flyout
|
||||
// area are still deleted. Must be larger than the largest screen size,
|
||||
// but be smaller than half Number.MAX_SAFE_INTEGER (not available on IE).
|
||||
var BIG_NUM = 1000000000;
|
||||
var left = flyoutRect.left;
|
||||
const BIG_NUM = 1000000000;
|
||||
const left = flyoutRect.left;
|
||||
|
||||
if (this.toolboxPosition_ == Blockly.utils.toolbox.Position.LEFT) {
|
||||
var width = flyoutRect.width;
|
||||
return new Blockly.utils.Rect(-BIG_NUM, BIG_NUM, -BIG_NUM, left + width);
|
||||
if (this.toolboxPosition_ == Position.LEFT) {
|
||||
const width = flyoutRect.width;
|
||||
return new Rect(-BIG_NUM, BIG_NUM, -BIG_NUM, left + width);
|
||||
} else { // Right
|
||||
return new Blockly.utils.Rect(-BIG_NUM, BIG_NUM, left, BIG_NUM);
|
||||
return new Rect(-BIG_NUM, BIG_NUM, left, BIG_NUM);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -319,30 +319,30 @@ Blockly.VerticalFlyout.prototype.getClientRect = function() {
|
||||
* For RTL: Lay out the blocks and buttons to be right-aligned.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.VerticalFlyout.prototype.reflowInternal_ = function() {
|
||||
VerticalFlyout.prototype.reflowInternal_ = function() {
|
||||
this.workspace_.scale = this.getFlyoutScale();
|
||||
var flyoutWidth = 0;
|
||||
var blocks = this.workspace_.getTopBlocks(false);
|
||||
for (var i = 0, block; (block = blocks[i]); i++) {
|
||||
var width = block.getHeightWidth().width;
|
||||
let flyoutWidth = 0;
|
||||
const blocks = this.workspace_.getTopBlocks(false);
|
||||
for (let i = 0, block; (block = blocks[i]); i++) {
|
||||
let width = block.getHeightWidth().width;
|
||||
if (block.outputConnection) {
|
||||
width -= this.tabWidth_;
|
||||
}
|
||||
flyoutWidth = Math.max(flyoutWidth, width);
|
||||
}
|
||||
for (var i = 0, button; (button = this.buttons_[i]); i++) {
|
||||
for (let i = 0, button; (button = this.buttons_[i]); i++) {
|
||||
flyoutWidth = Math.max(flyoutWidth, button.width);
|
||||
}
|
||||
flyoutWidth += this.MARGIN * 1.5 + this.tabWidth_;
|
||||
flyoutWidth *= this.workspace_.scale;
|
||||
flyoutWidth += Blockly.Scrollbar.scrollbarThickness;
|
||||
flyoutWidth += Scrollbar.scrollbarThickness;
|
||||
|
||||
if (this.width_ != flyoutWidth) {
|
||||
for (var i = 0, block; (block = blocks[i]); i++) {
|
||||
for (let i = 0, block; (block = blocks[i]); i++) {
|
||||
if (this.RTL) {
|
||||
// With the flyoutWidth known, right-align the blocks.
|
||||
var oldX = block.getRelativeToSurfaceXY().x;
|
||||
var newX = flyoutWidth / this.workspace_.scale - this.MARGIN;
|
||||
const oldX = block.getRelativeToSurfaceXY().x;
|
||||
let newX = flyoutWidth / this.workspace_.scale - this.MARGIN;
|
||||
if (!block.outputConnection) {
|
||||
newX -= this.tabWidth_;
|
||||
}
|
||||
@@ -354,22 +354,23 @@ Blockly.VerticalFlyout.prototype.reflowInternal_ = function() {
|
||||
}
|
||||
if (this.RTL) {
|
||||
// With the flyoutWidth known, right-align the buttons.
|
||||
for (var i = 0, button; (button = this.buttons_[i]); i++) {
|
||||
var y = button.getPosition().y;
|
||||
var x = flyoutWidth / this.workspace_.scale - button.width -
|
||||
for (let i = 0, button; (button = this.buttons_[i]); i++) {
|
||||
const y = button.getPosition().y;
|
||||
const x = flyoutWidth / this.workspace_.scale - button.width -
|
||||
this.MARGIN - this.tabWidth_;
|
||||
button.moveTo(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_ &&
|
||||
this.toolboxPosition_ == Blockly.utils.toolbox.Position.LEFT &&
|
||||
this.toolboxPosition_ == Position.LEFT &&
|
||||
!this.targetWorkspace.getToolbox()) {
|
||||
// This flyout is a simple toolbox. Reposition the workspace so that (0,0)
|
||||
// is in the correct position relative to the new absolute edge (ie
|
||||
// toolbox edge).
|
||||
this.targetWorkspace.translate(
|
||||
this.targetWorkspace.scrollX + flyoutWidth, this.targetWorkspace.scrollY);
|
||||
this.targetWorkspace.scrollX + flyoutWidth,
|
||||
this.targetWorkspace.scrollY);
|
||||
}
|
||||
|
||||
// Record the width for workspace metrics and .position.
|
||||
@@ -379,5 +380,7 @@ Blockly.VerticalFlyout.prototype.reflowInternal_ = function() {
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.registry.register(Blockly.registry.Type.FLYOUTS_VERTICAL_TOOLBOX,
|
||||
Blockly.registry.DEFAULT, Blockly.VerticalFlyout);
|
||||
registry.register(
|
||||
registry.Type.FLYOUTS_VERTICAL_TOOLBOX, registry.DEFAULT, VerticalFlyout);
|
||||
|
||||
exports = VerticalFlyout;
|
||||
|
||||
@@ -11,15 +11,18 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Generator');
|
||||
goog.module('Blockly.Generator');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Block');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.utils.deprecation');
|
||||
|
||||
goog.requireType('Blockly.Names');
|
||||
goog.requireType('Blockly.Workspace');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Names = goog.requireType('Blockly.Names');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Workspace = goog.requireType('Blockly.Workspace');
|
||||
const internalConstants = goog.require('Blockly.internalConstants');
|
||||
const deprecation = goog.require('Blockly.utils.deprecation');
|
||||
const {getMainWorkspace} = goog.require('Blockly');
|
||||
|
||||
|
||||
/**
|
||||
@@ -27,7 +30,7 @@ goog.requireType('Blockly.Workspace');
|
||||
* @param {string} name Language name of this generator.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Generator = function(name) {
|
||||
const Generator = function(name) {
|
||||
this.name_ = name;
|
||||
this.FUNCTION_NAME_PLACEHOLDER_REGEXP_ =
|
||||
new RegExp(this.FUNCTION_NAME_PLACEHOLDER_, 'g');
|
||||
@@ -39,7 +42,7 @@ Blockly.Generator = function(name) {
|
||||
* E.g. ' checkTimeout(%1);\n'
|
||||
* @type {?string}
|
||||
*/
|
||||
Blockly.Generator.prototype.INFINITE_LOOP_TRAP = null;
|
||||
Generator.prototype.INFINITE_LOOP_TRAP = null;
|
||||
|
||||
/**
|
||||
* Arbitrary code to inject before every statement.
|
||||
@@ -47,7 +50,7 @@ Blockly.Generator.prototype.INFINITE_LOOP_TRAP = null;
|
||||
* E.g. 'highlight(%1);\n'
|
||||
* @type {?string}
|
||||
*/
|
||||
Blockly.Generator.prototype.STATEMENT_PREFIX = null;
|
||||
Generator.prototype.STATEMENT_PREFIX = null;
|
||||
|
||||
/**
|
||||
* Arbitrary code to inject after every statement.
|
||||
@@ -55,27 +58,27 @@ Blockly.Generator.prototype.STATEMENT_PREFIX = null;
|
||||
* E.g. 'highlight(%1);\n'
|
||||
* @type {?string}
|
||||
*/
|
||||
Blockly.Generator.prototype.STATEMENT_SUFFIX = null;
|
||||
Generator.prototype.STATEMENT_SUFFIX = null;
|
||||
|
||||
/**
|
||||
* The method of indenting. Defaults to two spaces, but language generators
|
||||
* may override this to increase indent or change to tabs.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Generator.prototype.INDENT = ' ';
|
||||
Generator.prototype.INDENT = ' ';
|
||||
|
||||
/**
|
||||
* Maximum length for a comment before wrapping. Does not account for
|
||||
* indenting level.
|
||||
* @type {number}
|
||||
*/
|
||||
Blockly.Generator.prototype.COMMENT_WRAP = 60;
|
||||
Generator.prototype.COMMENT_WRAP = 60;
|
||||
|
||||
/**
|
||||
* List of outer-inner pairings that do NOT require parentheses.
|
||||
* @type {!Array<!Array<number>>}
|
||||
*/
|
||||
Blockly.Generator.prototype.ORDER_OVERRIDES = [];
|
||||
Generator.prototype.ORDER_OVERRIDES = [];
|
||||
|
||||
/**
|
||||
* Whether the init method has been called.
|
||||
@@ -84,24 +87,24 @@ Blockly.Generator.prototype.ORDER_OVERRIDES = [];
|
||||
* initialized. If this flag is untouched, it will have no effect.
|
||||
* @type {?boolean}
|
||||
*/
|
||||
Blockly.Generator.prototype.isInitialized = null;
|
||||
Generator.prototype.isInitialized = null;
|
||||
|
||||
/**
|
||||
* Generate code for all blocks in the workspace to the specified language.
|
||||
* @param {!Blockly.Workspace=} workspace Workspace to generate code from.
|
||||
* @param {!Workspace=} workspace Workspace to generate code from.
|
||||
* @return {string} Generated code.
|
||||
*/
|
||||
Blockly.Generator.prototype.workspaceToCode = function(workspace) {
|
||||
Generator.prototype.workspaceToCode = function(workspace) {
|
||||
if (!workspace) {
|
||||
// Backwards compatibility from before there could be multiple workspaces.
|
||||
console.warn('No workspace specified in workspaceToCode call. Guessing.');
|
||||
workspace = Blockly.getMainWorkspace();
|
||||
workspace = getMainWorkspace();
|
||||
}
|
||||
var code = [];
|
||||
let code = [];
|
||||
this.init(workspace);
|
||||
var blocks = workspace.getTopBlocks(true);
|
||||
for (var i = 0, block; (block = blocks[i]); i++) {
|
||||
var line = this.blockToCode(block);
|
||||
const blocks = workspace.getTopBlocks(true);
|
||||
for (let i = 0, block; (block = blocks[i]); i++) {
|
||||
let line = this.blockToCode(block);
|
||||
if (Array.isArray(line)) {
|
||||
// Value blocks return tuples of code and operator order.
|
||||
// Top-level blocks don't care about operator order.
|
||||
@@ -141,20 +144,20 @@ Blockly.Generator.prototype.workspaceToCode = function(workspace) {
|
||||
* @param {string} prefix The common prefix.
|
||||
* @return {string} The prefixed lines of code.
|
||||
*/
|
||||
Blockly.Generator.prototype.prefixLines = function(text, prefix) {
|
||||
Generator.prototype.prefixLines = function(text, prefix) {
|
||||
return prefix + text.replace(/(?!\n$)\n/g, '\n' + prefix);
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively spider a tree of blocks, returning all their comments.
|
||||
* @param {!Blockly.Block} block The block from which to start spidering.
|
||||
* @param {!Block} block The block from which to start spidering.
|
||||
* @return {string} Concatenated list of comments.
|
||||
*/
|
||||
Blockly.Generator.prototype.allNestedComments = function(block) {
|
||||
var comments = [];
|
||||
var blocks = block.getDescendants(true);
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
var comment = blocks[i].getCommentText();
|
||||
Generator.prototype.allNestedComments = function(block) {
|
||||
const comments = [];
|
||||
const blocks = block.getDescendants(true);
|
||||
for (let i = 0; i < blocks.length; i++) {
|
||||
const comment = blocks[i].getCommentText();
|
||||
if (comment) {
|
||||
comments.push(comment);
|
||||
}
|
||||
@@ -169,13 +172,13 @@ Blockly.Generator.prototype.allNestedComments = function(block) {
|
||||
/**
|
||||
* Generate code for the specified block (and attached blocks).
|
||||
* The generator must be initialized before calling this function.
|
||||
* @param {Blockly.Block} block The block to generate code for.
|
||||
* @param {Block} block The block to generate code for.
|
||||
* @param {boolean=} opt_thisOnly True to generate code for only this statement.
|
||||
* @return {string|!Array} For statement blocks, the generated code.
|
||||
* For value blocks, an array containing the generated code and an
|
||||
* operator order value. Returns '' if block is null.
|
||||
*/
|
||||
Blockly.Generator.prototype.blockToCode = function(block, opt_thisOnly) {
|
||||
Generator.prototype.blockToCode = function(block, opt_thisOnly) {
|
||||
if (this.isInitialized === false) {
|
||||
console.warn(
|
||||
'Generator init was not called before blockToCode was called.');
|
||||
@@ -192,16 +195,17 @@ Blockly.Generator.prototype.blockToCode = function(block, opt_thisOnly) {
|
||||
return opt_thisOnly ? '' : this.blockToCode(block.getChildren(false)[0]);
|
||||
}
|
||||
|
||||
var func = this[block.type];
|
||||
const func = this[block.type];
|
||||
if (typeof func != 'function') {
|
||||
throw Error('Language "' + this.name_ + '" does not know how to generate ' +
|
||||
throw Error(
|
||||
'Language "' + this.name_ + '" does not know how to generate ' +
|
||||
'code for block type "' + block.type + '".');
|
||||
}
|
||||
// First argument to func.call is the value of 'this' in the generator.
|
||||
// Prior to 24 September 2013 'this' was the only way to access the block.
|
||||
// The current preferred method of accessing the block is through the second
|
||||
// argument to func.call, which becomes the first parameter to the generator.
|
||||
var code = func.call(block, block);
|
||||
let code = func.call(block, block);
|
||||
if (Array.isArray(code)) {
|
||||
// Value blocks return tuples of code and operator order.
|
||||
if (!block.outputConnection) {
|
||||
@@ -225,22 +229,22 @@ Blockly.Generator.prototype.blockToCode = function(block, opt_thisOnly) {
|
||||
|
||||
/**
|
||||
* Generate code representing the specified value input.
|
||||
* @param {!Blockly.Block} block The block containing the input.
|
||||
* @param {!Block} block The block containing the input.
|
||||
* @param {string} name The name of the input.
|
||||
* @param {number} outerOrder The maximum binding strength (minimum order value)
|
||||
* of any operators adjacent to "block".
|
||||
* @return {string} Generated code or '' if no blocks are connected or the
|
||||
* specified input does not exist.
|
||||
*/
|
||||
Blockly.Generator.prototype.valueToCode = function(block, name, outerOrder) {
|
||||
Generator.prototype.valueToCode = function(block, name, outerOrder) {
|
||||
if (isNaN(outerOrder)) {
|
||||
throw TypeError('Expecting valid order from block: ' + block.type);
|
||||
}
|
||||
var targetBlock = block.getInputTargetBlock(name);
|
||||
const targetBlock = block.getInputTargetBlock(name);
|
||||
if (!targetBlock) {
|
||||
return '';
|
||||
}
|
||||
var tuple = this.blockToCode(targetBlock);
|
||||
const tuple = this.blockToCode(targetBlock);
|
||||
if (tuple === '') {
|
||||
// Disabled block.
|
||||
return '';
|
||||
@@ -250,20 +254,20 @@ Blockly.Generator.prototype.valueToCode = function(block, name, outerOrder) {
|
||||
if (!Array.isArray(tuple)) {
|
||||
throw TypeError('Expecting tuple from value block: ' + targetBlock.type);
|
||||
}
|
||||
var code = tuple[0];
|
||||
var innerOrder = tuple[1];
|
||||
let code = tuple[0];
|
||||
const innerOrder = tuple[1];
|
||||
if (isNaN(innerOrder)) {
|
||||
throw TypeError('Expecting valid order from value block: ' +
|
||||
targetBlock.type);
|
||||
throw TypeError(
|
||||
'Expecting valid order from value block: ' + targetBlock.type);
|
||||
}
|
||||
if (!code) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Add parentheses if needed.
|
||||
var parensNeeded = false;
|
||||
var outerOrderClass = Math.floor(outerOrder);
|
||||
var innerOrderClass = Math.floor(innerOrder);
|
||||
let parensNeeded = false;
|
||||
const outerOrderClass = Math.floor(outerOrder);
|
||||
const innerOrderClass = Math.floor(innerOrder);
|
||||
if (outerOrderClass <= innerOrderClass) {
|
||||
if (outerOrderClass == innerOrderClass &&
|
||||
(outerOrderClass == 0 || outerOrderClass == 99)) {
|
||||
@@ -277,7 +281,7 @@ Blockly.Generator.prototype.valueToCode = function(block, name, outerOrder) {
|
||||
// wrap the code in parentheses.
|
||||
parensNeeded = true;
|
||||
// Check for special exceptions.
|
||||
for (var i = 0; i < this.ORDER_OVERRIDES.length; i++) {
|
||||
for (let i = 0; i < this.ORDER_OVERRIDES.length; i++) {
|
||||
if (this.ORDER_OVERRIDES[i][0] == outerOrder &&
|
||||
this.ORDER_OVERRIDES[i][1] == innerOrder) {
|
||||
parensNeeded = false;
|
||||
@@ -299,17 +303,18 @@ Blockly.Generator.prototype.valueToCode = function(block, name, outerOrder) {
|
||||
* statement input. Indent the code.
|
||||
* This is mainly used in generators. When trying to generate code to evaluate
|
||||
* look at using workspaceToCode or blockToCode.
|
||||
* @param {!Blockly.Block} block The block containing the input.
|
||||
* @param {!Block} block The block containing the input.
|
||||
* @param {string} name The name of the input.
|
||||
* @return {string} Generated code or '' if no blocks are connected.
|
||||
*/
|
||||
Blockly.Generator.prototype.statementToCode = function(block, name) {
|
||||
var targetBlock = block.getInputTargetBlock(name);
|
||||
var code = this.blockToCode(targetBlock);
|
||||
Generator.prototype.statementToCode = function(block, name) {
|
||||
const targetBlock = block.getInputTargetBlock(name);
|
||||
let code = this.blockToCode(targetBlock);
|
||||
// Value blocks must return code and order of operations info.
|
||||
// Statement blocks must only return code.
|
||||
if (typeof code != 'string') {
|
||||
throw TypeError('Expecting code from statement block: ' +
|
||||
throw TypeError(
|
||||
'Expecting code from statement block: ' +
|
||||
(targetBlock && targetBlock.type));
|
||||
}
|
||||
if (code) {
|
||||
@@ -324,21 +329,24 @@ Blockly.Generator.prototype.statementToCode = function(block, name) {
|
||||
* statement executes), and a statement prefix to the end of the loop block
|
||||
* (right before the loop statement executes).
|
||||
* @param {string} branch Code for loop contents.
|
||||
* @param {!Blockly.Block} block Enclosing block.
|
||||
* @param {!Block} block Enclosing block.
|
||||
* @return {string} Loop contents, with infinite loop trap added.
|
||||
*/
|
||||
Blockly.Generator.prototype.addLoopTrap = function(branch, block) {
|
||||
Generator.prototype.addLoopTrap = function(branch, block) {
|
||||
if (this.INFINITE_LOOP_TRAP) {
|
||||
branch = this.prefixLines(this.injectId(this.INFINITE_LOOP_TRAP, block),
|
||||
this.INDENT) + branch;
|
||||
branch = this.prefixLines(
|
||||
this.injectId(this.INFINITE_LOOP_TRAP, block), this.INDENT) +
|
||||
branch;
|
||||
}
|
||||
if (this.STATEMENT_SUFFIX && !block.suppressPrefixSuffix) {
|
||||
branch = this.prefixLines(this.injectId(this.STATEMENT_SUFFIX, block),
|
||||
this.INDENT) + branch;
|
||||
branch = this.prefixLines(
|
||||
this.injectId(this.STATEMENT_SUFFIX, block), this.INDENT) +
|
||||
branch;
|
||||
}
|
||||
if (this.STATEMENT_PREFIX && !block.suppressPrefixSuffix) {
|
||||
branch = branch + this.prefixLines(this.injectId(this.STATEMENT_PREFIX,
|
||||
block), this.INDENT);
|
||||
branch = branch +
|
||||
this.prefixLines(
|
||||
this.injectId(this.STATEMENT_PREFIX, block), this.INDENT);
|
||||
}
|
||||
return branch;
|
||||
};
|
||||
@@ -347,11 +355,11 @@ Blockly.Generator.prototype.addLoopTrap = function(branch, block) {
|
||||
* Inject a block ID into a message to replace '%1'.
|
||||
* Used for STATEMENT_PREFIX, STATEMENT_SUFFIX, and INFINITE_LOOP_TRAP.
|
||||
* @param {string} msg Code snippet with '%1'.
|
||||
* @param {!Blockly.Block} block Block which has an ID.
|
||||
* @param {!Block} block Block which has an ID.
|
||||
* @return {string} Code snippet with ID.
|
||||
*/
|
||||
Blockly.Generator.prototype.injectId = function(msg, block) {
|
||||
var id = block.id.replace(/\$/g, '$$$$'); // Issue 251.
|
||||
Generator.prototype.injectId = function(msg, block) {
|
||||
const id = block.id.replace(/\$/g, '$$$$'); // Issue 251.
|
||||
return msg.replace(/%1/g, '\'' + id + '\'');
|
||||
};
|
||||
|
||||
@@ -360,33 +368,33 @@ Blockly.Generator.prototype.injectId = function(msg, block) {
|
||||
* @type {string}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Generator.prototype.RESERVED_WORDS_ = '';
|
||||
Generator.prototype.RESERVED_WORDS_ = '';
|
||||
|
||||
/**
|
||||
* Add one or more words to the list of reserved words for this language.
|
||||
* @param {string} words Comma-separated list of words to add to the list.
|
||||
* No spaces. Duplicates are ok.
|
||||
*/
|
||||
Blockly.Generator.prototype.addReservedWords = function(words) {
|
||||
Generator.prototype.addReservedWords = function(words) {
|
||||
this.RESERVED_WORDS_ += words + ',';
|
||||
};
|
||||
|
||||
/**
|
||||
* This is used as a placeholder in functions defined using
|
||||
* Blockly.Generator.provideFunction_. It must not be legal code that could
|
||||
* Generator.provideFunction_. It must not be legal code that could
|
||||
* legitimately appear in a function definition (or comment), and it must
|
||||
* not confuse the regular expression parser.
|
||||
* @type {string}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Generator.prototype.FUNCTION_NAME_PLACEHOLDER_ = '{leCUI8hutHZI4480Dc}';
|
||||
Generator.prototype.FUNCTION_NAME_PLACEHOLDER_ = '{leCUI8hutHZI4480Dc}';
|
||||
|
||||
/**
|
||||
* A dictionary of definitions to be printed before the code.
|
||||
* @type {!Object|undefined}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Generator.prototype.definitions_;
|
||||
Generator.prototype.definitions_;
|
||||
|
||||
/**
|
||||
* A dictionary mapping desired function names in definitions_ to actual
|
||||
@@ -394,36 +402,34 @@ Blockly.Generator.prototype.definitions_;
|
||||
* @type {!Object|undefined}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Generator.prototype.functionNames_;
|
||||
Generator.prototype.functionNames_;
|
||||
|
||||
/**
|
||||
* A database of variable and procedure names.
|
||||
* @type {!Blockly.Names|undefined}
|
||||
* @type {!Names|undefined}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Generator.prototype.nameDB_;
|
||||
Generator.prototype.nameDB_;
|
||||
|
||||
Object.defineProperty(Blockly.Generator.prototype, 'variableDB_', {
|
||||
Object.defineProperty(Generator.prototype, 'variableDB_', {
|
||||
/**
|
||||
* Getter.
|
||||
* @deprecated 'variableDB_' was renamed to 'nameDB_' (May 2021).
|
||||
* @this {Blockly.Generator}
|
||||
* @return {!Blockly.Names|undefined} Name database.
|
||||
* @this {Generator}
|
||||
* @return {!Names|undefined} Name database.
|
||||
*/
|
||||
get: function() {
|
||||
Blockly.utils.deprecation.warn(
|
||||
'variableDB_', 'May 2021', 'May 2026', 'nameDB_');
|
||||
deprecation.warn('variableDB_', 'May 2021', 'May 2026', 'nameDB_');
|
||||
return this.nameDB_;
|
||||
},
|
||||
/**
|
||||
* Setter.
|
||||
* @deprecated 'variableDB_' was renamed to 'nameDB_' (May 2021).
|
||||
* @this {Blockly.Generator}
|
||||
* @param {!Blockly.Names|undefined} nameDb New name database.
|
||||
* @this {Generator}
|
||||
* @param {!Names|undefined} nameDb New name database.
|
||||
*/
|
||||
set: function(nameDb) {
|
||||
Blockly.utils.deprecation.warn(
|
||||
'variableDB_', 'May 2021', 'May 2026', 'nameDB_');
|
||||
deprecation.warn('variableDB_', 'May 2021', 'May 2026', 'nameDB_');
|
||||
this.nameDB_ = nameDb;
|
||||
}
|
||||
});
|
||||
@@ -440,7 +446,7 @@ Object.defineProperty(Blockly.Generator.prototype, 'variableDB_', {
|
||||
* "listRandom", not "random"). There is no danger of colliding with reserved
|
||||
* words, or user-defined variable or procedure names.
|
||||
*
|
||||
* The code gets output when Blockly.Generator.finish() is called.
|
||||
* The code gets output when Generator.finish() is called.
|
||||
*
|
||||
* @param {string} desiredName The desired name of the function
|
||||
* (e.g. mathIsPrime).
|
||||
@@ -449,18 +455,18 @@ Object.defineProperty(Blockly.Generator.prototype, 'variableDB_', {
|
||||
* from desiredName if the former has already been taken by the user.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Generator.prototype.provideFunction_ = function(desiredName, code) {
|
||||
Generator.prototype.provideFunction_ = function(desiredName, code) {
|
||||
if (!this.definitions_[desiredName]) {
|
||||
var functionName = this.nameDB_.getDistinctName(desiredName,
|
||||
Blockly.PROCEDURE_CATEGORY_NAME);
|
||||
const functionName = this.nameDB_.getDistinctName(
|
||||
desiredName, internalConstants.PROCEDURE_CATEGORY_NAME);
|
||||
this.functionNames_[desiredName] = functionName;
|
||||
var codeText = code.join('\n').replace(
|
||||
let codeText = code.join('\n').replace(
|
||||
this.FUNCTION_NAME_PLACEHOLDER_REGEXP_, functionName);
|
||||
// Change all ' ' indents into the desired indent.
|
||||
// To avoid an infinite loop of replacements, change all indents to '\0'
|
||||
// character first, then replace them all with the indent.
|
||||
// We are assuming that no provided functions contain a literal null char.
|
||||
var oldCodeText;
|
||||
let oldCodeText;
|
||||
while (oldCodeText != codeText) {
|
||||
oldCodeText = codeText;
|
||||
codeText = codeText.replace(/^(( {2})*) {2}/gm, '$1\0');
|
||||
@@ -475,9 +481,9 @@ Blockly.Generator.prototype.provideFunction_ = function(desiredName, code) {
|
||||
* Hook for code to run before code generation starts.
|
||||
* Subclasses may override this, e.g. to initialise the database of variable
|
||||
* names.
|
||||
* @param {!Blockly.Workspace} _workspace Workspace to generate code from.
|
||||
* @param {!Workspace} _workspace Workspace to generate code from.
|
||||
*/
|
||||
Blockly.Generator.prototype.init = function(_workspace) {
|
||||
Generator.prototype.init = function(_workspace) {
|
||||
// Optionally override
|
||||
// Create a dictionary of definitions to be printed before the code.
|
||||
this.definitions_ = Object.create(null);
|
||||
@@ -493,14 +499,14 @@ Blockly.Generator.prototype.init = function(_workspace) {
|
||||
* Subclasses may override this, e.g. to generate code for statements following
|
||||
* the block, or to handle comments for the specified block and any connected
|
||||
* value blocks.
|
||||
* @param {!Blockly.Block} _block The current block.
|
||||
* @param {!Block} _block The current block.
|
||||
* @param {string} code The code created for this block.
|
||||
* @param {boolean=} _opt_thisOnly True to generate code for only this
|
||||
* statement.
|
||||
* @return {string} Code with comments and subsequent blocks added.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Generator.prototype.scrub_ = function(_block, code, _opt_thisOnly) {
|
||||
Generator.prototype.scrub_ = function(_block, code, _opt_thisOnly) {
|
||||
// Optionally override
|
||||
return code;
|
||||
};
|
||||
@@ -512,7 +518,7 @@ Blockly.Generator.prototype.scrub_ = function(_block, code, _opt_thisOnly) {
|
||||
* @param {string} code Generated code.
|
||||
* @return {string} Completed code.
|
||||
*/
|
||||
Blockly.Generator.prototype.finish = function(code) {
|
||||
Generator.prototype.finish = function(code) {
|
||||
// Optionally override
|
||||
// Clean up temporary data.
|
||||
delete this.definitions_;
|
||||
@@ -528,7 +534,9 @@ Blockly.Generator.prototype.finish = function(code) {
|
||||
* @param {string} line Line of generated code.
|
||||
* @return {string} Legal line of code.
|
||||
*/
|
||||
Blockly.Generator.prototype.scrubNakedValue = function(line) {
|
||||
Generator.prototype.scrubNakedValue = function(line) {
|
||||
// Optionally override
|
||||
return line;
|
||||
};
|
||||
|
||||
exports = Generator;
|
||||
|
||||
292
core/gesture.js
292
core/gesture.js
@@ -11,31 +11,39 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Gesture');
|
||||
goog.module('Blockly.Gesture');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.blockAnimations');
|
||||
// TODO(#5073): Add Blockly require after fixing circular dependency.
|
||||
// goog.require('Blockly');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
const BubbleDragger = goog.require('Blockly.BubbleDragger');
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const Field = goog.requireType('Blockly.Field');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IBlockDragger = goog.requireType('Blockly.IBlockDragger');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IBubble = goog.requireType('Blockly.IBubble');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IFlyout = goog.requireType('Blockly.IFlyout');
|
||||
const Tooltip = goog.require('Blockly.Tooltip');
|
||||
const Touch = goog.require('Blockly.Touch');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Workspace = goog.require('Blockly.Workspace');
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const WorkspaceDragger = goog.require('Blockly.WorkspaceDragger');
|
||||
const blockAnimations = goog.require('Blockly.blockAnimations');
|
||||
const browserEvents = goog.require('Blockly.browserEvents');
|
||||
const internalConstants = goog.require('Blockly.internalConstants');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.BlockDragger');
|
||||
goog.require('Blockly.browserEvents');
|
||||
goog.require('Blockly.BubbleDragger');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.Events');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.Click');
|
||||
goog.require('Blockly.Tooltip');
|
||||
goog.require('Blockly.Touch');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.Workspace');
|
||||
goog.require('Blockly.WorkspaceDragger');
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.Field');
|
||||
goog.requireType('Blockly.IBlockDragger');
|
||||
goog.requireType('Blockly.IBubble');
|
||||
goog.requireType('Blockly.IFlyout');
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
|
||||
|
||||
/**
|
||||
@@ -47,15 +55,15 @@ goog.requireType('Blockly.WorkspaceSvg');
|
||||
/**
|
||||
* Class for one gesture.
|
||||
* @param {!Event} e The event that kicked off this gesture.
|
||||
* @param {!Blockly.WorkspaceSvg} creatorWorkspace The workspace that created
|
||||
* @param {!WorkspaceSvg} creatorWorkspace The workspace that created
|
||||
* this gesture and has a reference to it.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Gesture = function(e, creatorWorkspace) {
|
||||
const Gesture = function(e, creatorWorkspace) {
|
||||
/**
|
||||
* The position of the mouse when the gesture started. Units are CSS pixels,
|
||||
* with (0, 0) at the top left of the browser window (mouseEvent clientX/Y).
|
||||
* @type {Blockly.utils.Coordinate}
|
||||
* @type {Coordinate}
|
||||
* @private
|
||||
*/
|
||||
this.mouseDownXY_ = null;
|
||||
@@ -63,15 +71,15 @@ Blockly.Gesture = function(e, creatorWorkspace) {
|
||||
/**
|
||||
* How far the mouse has moved during this drag, in pixel units.
|
||||
* (0, 0) is at this.mouseDownXY_.
|
||||
* @type {!Blockly.utils.Coordinate}
|
||||
* @type {!Coordinate}
|
||||
* @private
|
||||
*/
|
||||
this.currentDragDeltaXY_ = new Blockly.utils.Coordinate(0, 0);
|
||||
this.currentDragDeltaXY_ = new Coordinate(0, 0);
|
||||
|
||||
/**
|
||||
* The bubble that the gesture started on, or null if it did not start on a
|
||||
* bubble.
|
||||
* @type {Blockly.IBubble}
|
||||
* @type {IBubble}
|
||||
* @private
|
||||
*/
|
||||
this.startBubble_ = null;
|
||||
@@ -79,7 +87,7 @@ Blockly.Gesture = function(e, creatorWorkspace) {
|
||||
/**
|
||||
* The field that the gesture started on, or null if it did not start on a
|
||||
* field.
|
||||
* @type {Blockly.Field}
|
||||
* @type {Field}
|
||||
* @private
|
||||
*/
|
||||
this.startField_ = null;
|
||||
@@ -87,7 +95,7 @@ Blockly.Gesture = function(e, creatorWorkspace) {
|
||||
/**
|
||||
* The block that the gesture started on, or null if it did not start on a
|
||||
* block.
|
||||
* @type {Blockly.BlockSvg}
|
||||
* @type {BlockSvg}
|
||||
* @private
|
||||
*/
|
||||
this.startBlock_ = null;
|
||||
@@ -97,7 +105,7 @@ Blockly.Gesture = function(e, creatorWorkspace) {
|
||||
* shadow block, this is the first non-shadow parent of the block. If the
|
||||
* gesture started in the flyout, this is the root block of the block group
|
||||
* that was clicked or dragged.
|
||||
* @type {Blockly.BlockSvg}
|
||||
* @type {BlockSvg}
|
||||
* @private
|
||||
*/
|
||||
this.targetBlock_ = null;
|
||||
@@ -106,7 +114,7 @@ Blockly.Gesture = function(e, creatorWorkspace) {
|
||||
* The workspace that the gesture started on. There may be multiple
|
||||
* workspaces on a page; this is more accurate than using
|
||||
* Blockly.getMainWorkspace().
|
||||
* @type {Blockly.WorkspaceSvg}
|
||||
* @type {WorkspaceSvg}
|
||||
* @protected
|
||||
*/
|
||||
this.startWorkspace_ = null;
|
||||
@@ -116,7 +124,7 @@ Blockly.Gesture = function(e, creatorWorkspace) {
|
||||
* to the gesture, which will need to be cleared at deletion.
|
||||
* This may be different from the start workspace. For instance, a flyout is
|
||||
* a workspace, but its parent workspace manages gestures for it.
|
||||
* @type {!Blockly.WorkspaceSvg}
|
||||
* @type {!WorkspaceSvg}
|
||||
* @private
|
||||
*/
|
||||
this.creatorWorkspace_ = creatorWorkspace;
|
||||
@@ -161,7 +169,7 @@ Blockly.Gesture = function(e, creatorWorkspace) {
|
||||
/**
|
||||
* A handle to use to unbind a mouse move listener at the end of a drag.
|
||||
* Opaque data returned from Blockly.bindEventWithChecks_.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @protected
|
||||
*/
|
||||
this.onMoveWrapper_ = null;
|
||||
@@ -169,21 +177,21 @@ Blockly.Gesture = function(e, creatorWorkspace) {
|
||||
/**
|
||||
* A handle to use to unbind a mouse up listener at the end of a drag.
|
||||
* Opaque data returned from Blockly.bindEventWithChecks_.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @protected
|
||||
*/
|
||||
this.onUpWrapper_ = null;
|
||||
|
||||
/**
|
||||
* The object tracking a bubble drag, or null if none is in progress.
|
||||
* @type {Blockly.BubbleDragger}
|
||||
* @type {BubbleDragger}
|
||||
* @private
|
||||
*/
|
||||
this.bubbleDragger_ = null;
|
||||
|
||||
/**
|
||||
* The object tracking a block drag, or null if none is in progress.
|
||||
* @type {?Blockly.IBlockDragger}
|
||||
* @type {?IBlockDragger}
|
||||
* @private
|
||||
*/
|
||||
this.blockDragger_ = null;
|
||||
@@ -191,14 +199,14 @@ Blockly.Gesture = function(e, creatorWorkspace) {
|
||||
/**
|
||||
* The object tracking a workspace or flyout workspace drag, or null if none
|
||||
* is in progress.
|
||||
* @type {Blockly.WorkspaceDragger}
|
||||
* @type {WorkspaceDragger}
|
||||
* @private
|
||||
*/
|
||||
this.workspaceDragger_ = null;
|
||||
|
||||
/**
|
||||
* The flyout a gesture started in, if any.
|
||||
* @type {Blockly.IFlyout}
|
||||
* @type {IFlyout}
|
||||
* @private
|
||||
*/
|
||||
this.flyout_ = null;
|
||||
@@ -230,24 +238,24 @@ Blockly.Gesture = function(e, creatorWorkspace) {
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.healStack_ = !Blockly.DRAG_STACK;
|
||||
this.healStack_ = !internalConstants.DRAG_STACK;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sever all links from this object.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.dispose = function() {
|
||||
Blockly.Touch.clearTouchIdentifier();
|
||||
Blockly.Tooltip.unblock();
|
||||
Gesture.prototype.dispose = function() {
|
||||
Touch.clearTouchIdentifier();
|
||||
Tooltip.unblock();
|
||||
// Clear the owner's reference to this gesture.
|
||||
this.creatorWorkspace_.clearGesture();
|
||||
|
||||
if (this.onMoveWrapper_) {
|
||||
Blockly.browserEvents.unbind(this.onMoveWrapper_);
|
||||
browserEvents.unbind(this.onMoveWrapper_);
|
||||
}
|
||||
if (this.onUpWrapper_) {
|
||||
Blockly.browserEvents.unbind(this.onUpWrapper_);
|
||||
browserEvents.unbind(this.onUpWrapper_);
|
||||
}
|
||||
|
||||
if (this.blockDragger_) {
|
||||
@@ -266,9 +274,9 @@ Blockly.Gesture.prototype.dispose = function() {
|
||||
* @param {!Event} e The most recent mouse or touch event.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.updateFromEvent_ = function(e) {
|
||||
var currentXY = new Blockly.utils.Coordinate(e.clientX, e.clientY);
|
||||
var changed = this.updateDragDelta_(currentXY);
|
||||
Gesture.prototype.updateFromEvent_ = function(e) {
|
||||
const currentXY = new Coordinate(e.clientX, e.clientY);
|
||||
const changed = this.updateDragDelta_(currentXY);
|
||||
// Exceeded the drag radius for the first time.
|
||||
if (changed) {
|
||||
this.updateIsDragging_();
|
||||
@@ -279,24 +287,23 @@ Blockly.Gesture.prototype.updateFromEvent_ = function(e) {
|
||||
|
||||
/**
|
||||
* DO MATH to set currentDragDeltaXY_ based on the most recent mouse position.
|
||||
* @param {!Blockly.utils.Coordinate} currentXY The most recent mouse/pointer
|
||||
* @param {!Coordinate} currentXY The most recent mouse/pointer
|
||||
* position, in pixel units, with (0, 0) at the window's top left corner.
|
||||
* @return {boolean} True if the drag just exceeded the drag radius for the
|
||||
* first time.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.updateDragDelta_ = function(currentXY) {
|
||||
this.currentDragDeltaXY_ = Blockly.utils.Coordinate.difference(
|
||||
Gesture.prototype.updateDragDelta_ = function(currentXY) {
|
||||
this.currentDragDeltaXY_ = Coordinate.difference(
|
||||
currentXY,
|
||||
/** @type {!Blockly.utils.Coordinate} */ (this.mouseDownXY_));
|
||||
/** @type {!Coordinate} */ (this.mouseDownXY_));
|
||||
|
||||
if (!this.hasExceededDragRadius_) {
|
||||
var currentDragDelta =
|
||||
Blockly.utils.Coordinate.magnitude(this.currentDragDeltaXY_);
|
||||
const currentDragDelta = Coordinate.magnitude(this.currentDragDeltaXY_);
|
||||
|
||||
// The flyout has a different drag radius from the rest of Blockly.
|
||||
var limitRadius =
|
||||
this.flyout_ ? Blockly.FLYOUT_DRAG_RADIUS : Blockly.DRAG_RADIUS;
|
||||
const limitRadius = this.flyout_ ? internalConstants.FLYOUT_DRAG_RADIUS :
|
||||
internalConstants.DRAG_RADIUS;
|
||||
|
||||
this.hasExceededDragRadius_ = currentDragDelta > limitRadius;
|
||||
return this.hasExceededDragRadius_;
|
||||
@@ -314,7 +321,7 @@ Blockly.Gesture.prototype.updateDragDelta_ = function(currentXY) {
|
||||
* @return {boolean} True if a block is being dragged from the flyout.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.updateIsDraggingFromFlyout_ = function() {
|
||||
Gesture.prototype.updateIsDraggingFromFlyout_ = function() {
|
||||
if (!this.targetBlock_) {
|
||||
return false;
|
||||
}
|
||||
@@ -327,8 +334,8 @@ Blockly.Gesture.prototype.updateIsDraggingFromFlyout_ = function() {
|
||||
this.startWorkspace_.updateScreenCalculationsIfScrolled();
|
||||
// Start the event group now, so that the same event group is used for block
|
||||
// creation and block dragging.
|
||||
if (!Blockly.Events.getGroup()) {
|
||||
Blockly.Events.setGroup(true);
|
||||
if (!Events.getGroup()) {
|
||||
Events.setGroup(true);
|
||||
}
|
||||
// The start block is no longer relevant, because this is a drag.
|
||||
this.startBlock_ = null;
|
||||
@@ -348,7 +355,7 @@ Blockly.Gesture.prototype.updateIsDraggingFromFlyout_ = function() {
|
||||
* @return {boolean} True if a bubble is being dragged.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.updateIsDraggingBubble_ = function() {
|
||||
Gesture.prototype.updateIsDraggingBubble_ = function() {
|
||||
if (!this.startBubble_) {
|
||||
return false;
|
||||
}
|
||||
@@ -367,7 +374,7 @@ Blockly.Gesture.prototype.updateIsDraggingBubble_ = function() {
|
||||
* @return {boolean} True if a block is being dragged.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.updateIsDraggingBlock_ = function() {
|
||||
Gesture.prototype.updateIsDraggingBlock_ = function() {
|
||||
if (!this.targetBlock_) {
|
||||
return false;
|
||||
}
|
||||
@@ -393,8 +400,8 @@ Blockly.Gesture.prototype.updateIsDraggingBlock_ = function() {
|
||||
* WorkspaceDragger and starts the drag.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.updateIsDraggingWorkspace_ = function() {
|
||||
var wsMovable = this.flyout_ ?
|
||||
Gesture.prototype.updateIsDraggingWorkspace_ = function() {
|
||||
const wsMovable = this.flyout_ ?
|
||||
this.flyout_.isScrollable() :
|
||||
this.startWorkspace_ && this.startWorkspace_.isDraggable();
|
||||
|
||||
@@ -402,8 +409,8 @@ Blockly.Gesture.prototype.updateIsDraggingWorkspace_ = function() {
|
||||
return;
|
||||
}
|
||||
|
||||
this.workspaceDragger_ = new Blockly.WorkspaceDragger(
|
||||
/** @type {!Blockly.WorkspaceSvg} */ (this.startWorkspace_));
|
||||
this.workspaceDragger_ = new WorkspaceDragger(
|
||||
/** @type {!WorkspaceSvg} */ (this.startWorkspace_));
|
||||
|
||||
this.isDraggingWorkspace_ = true;
|
||||
this.workspaceDragger_.startDrag();
|
||||
@@ -415,7 +422,7 @@ Blockly.Gesture.prototype.updateIsDraggingWorkspace_ = function() {
|
||||
* drag radius is exceeded. It should be called no more than once per gesture.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.updateIsDragging_ = function() {
|
||||
Gesture.prototype.updateIsDragging_ = function() {
|
||||
// Sanity check.
|
||||
if (this.calledUpdateIsDragging_) {
|
||||
throw Error('updateIsDragging_ should only be called once per gesture.');
|
||||
@@ -438,13 +445,13 @@ Blockly.Gesture.prototype.updateIsDragging_ = function() {
|
||||
* Create a block dragger and start dragging the selected block.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.startDraggingBlock_ = function() {
|
||||
var BlockDraggerClass = Blockly.registry.getClassFromOptions(
|
||||
Blockly.registry.Type.BLOCK_DRAGGER, this.creatorWorkspace_.options, true);
|
||||
Gesture.prototype.startDraggingBlock_ = function() {
|
||||
const BlockDraggerClass = registry.getClassFromOptions(
|
||||
registry.Type.BLOCK_DRAGGER, this.creatorWorkspace_.options, true);
|
||||
|
||||
this.blockDragger_ = new BlockDraggerClass(
|
||||
/** @type {!Blockly.BlockSvg} */ (this.targetBlock_),
|
||||
/** @type {!Blockly.WorkspaceSvg} */ (this.startWorkspace_));
|
||||
/** @type {!BlockSvg} */ (this.targetBlock_),
|
||||
/** @type {!WorkspaceSvg} */ (this.startWorkspace_));
|
||||
this.blockDragger_.startDrag(this.currentDragDeltaXY_, this.healStack_);
|
||||
this.blockDragger_.drag(this.mostRecentEvent_, this.currentDragDeltaXY_);
|
||||
};
|
||||
@@ -454,10 +461,10 @@ Blockly.Gesture.prototype.startDraggingBlock_ = function() {
|
||||
* @private
|
||||
*/
|
||||
// TODO (fenichel): Possibly combine this and startDraggingBlock_.
|
||||
Blockly.Gesture.prototype.startDraggingBubble_ = function() {
|
||||
this.bubbleDragger_ = new Blockly.BubbleDragger(
|
||||
/** @type {!Blockly.IBubble} */ (this.startBubble_),
|
||||
/** @type {!Blockly.WorkspaceSvg} */ (this.startWorkspace_));
|
||||
Gesture.prototype.startDraggingBubble_ = function() {
|
||||
this.bubbleDragger_ = new BubbleDragger(
|
||||
/** @type {!IBubble} */ (this.startBubble_),
|
||||
/** @type {!WorkspaceSvg} */ (this.startWorkspace_));
|
||||
this.bubbleDragger_.startBubbleDrag();
|
||||
this.bubbleDragger_.dragBubble(
|
||||
this.mostRecentEvent_, this.currentDragDeltaXY_);
|
||||
@@ -468,14 +475,14 @@ Blockly.Gesture.prototype.startDraggingBubble_ = function() {
|
||||
* @param {!Event} e A mouse down or touch start event.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.doStart = function(e) {
|
||||
if (Blockly.utils.isTargetInput(e)) {
|
||||
Gesture.prototype.doStart = function(e) {
|
||||
if (utils.isTargetInput(e)) {
|
||||
this.cancel();
|
||||
return;
|
||||
}
|
||||
this.hasStarted_ = true;
|
||||
|
||||
Blockly.blockAnimations.disconnectUiStop();
|
||||
blockAnimations.disconnectUiStop();
|
||||
this.startWorkspace_.updateScreenCalculationsIfScrolled();
|
||||
if (this.startWorkspace_.isMutator) {
|
||||
// Mutator's coordinate system could be out of date because the bubble was
|
||||
@@ -490,13 +497,13 @@ Blockly.Gesture.prototype.doStart = function(e) {
|
||||
this.startWorkspace_.markFocused();
|
||||
this.mostRecentEvent_ = e;
|
||||
|
||||
Blockly.Tooltip.block();
|
||||
Tooltip.block();
|
||||
|
||||
if (this.targetBlock_) {
|
||||
this.targetBlock_.select();
|
||||
}
|
||||
|
||||
if (Blockly.utils.isRightButton(e)) {
|
||||
if (utils.isRightButton(e)) {
|
||||
this.handleRightClick(e);
|
||||
return;
|
||||
}
|
||||
@@ -507,7 +514,7 @@ Blockly.Gesture.prototype.doStart = function(e) {
|
||||
Blockly.longStart(e, this);
|
||||
}
|
||||
|
||||
this.mouseDownXY_ = new Blockly.utils.Coordinate(e.clientX, e.clientY);
|
||||
this.mouseDownXY_ = new Coordinate(e.clientX, e.clientY);
|
||||
this.healStack_ = e.altKey || e.ctrlKey || e.metaKey;
|
||||
|
||||
this.bindMouseEvents(e);
|
||||
@@ -518,10 +525,10 @@ Blockly.Gesture.prototype.doStart = function(e) {
|
||||
* @param {!Event} e A mouse down or touch start event.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.bindMouseEvents = function(e) {
|
||||
this.onMoveWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
Gesture.prototype.bindMouseEvents = function(e) {
|
||||
this.onMoveWrapper_ = browserEvents.conditionalBind(
|
||||
document, 'mousemove', null, this.handleMove.bind(this));
|
||||
this.onUpWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
this.onUpWrapper_ = browserEvents.conditionalBind(
|
||||
document, 'mouseup', null, this.handleUp.bind(this));
|
||||
|
||||
e.preventDefault();
|
||||
@@ -533,13 +540,12 @@ Blockly.Gesture.prototype.bindMouseEvents = function(e) {
|
||||
* @param {!Event} e A mouse move or touch move event.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.handleMove = function(e) {
|
||||
Gesture.prototype.handleMove = function(e) {
|
||||
this.updateFromEvent_(e);
|
||||
if (this.isDraggingWorkspace_) {
|
||||
this.workspaceDragger_.drag(this.currentDragDeltaXY_);
|
||||
} else if (this.isDraggingBlock_) {
|
||||
this.blockDragger_.drag(
|
||||
this.mostRecentEvent_, this.currentDragDeltaXY_);
|
||||
this.blockDragger_.drag(this.mostRecentEvent_, this.currentDragDeltaXY_);
|
||||
} else if (this.isDraggingBubble_) {
|
||||
this.bubbleDragger_.dragBubble(
|
||||
this.mostRecentEvent_, this.currentDragDeltaXY_);
|
||||
@@ -553,7 +559,7 @@ Blockly.Gesture.prototype.handleMove = function(e) {
|
||||
* @param {!Event} e A mouse up or touch end event.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.handleUp = function(e) {
|
||||
Gesture.prototype.handleUp = function(e) {
|
||||
this.updateFromEvent_(e);
|
||||
Blockly.longStop_();
|
||||
|
||||
@@ -595,7 +601,7 @@ Blockly.Gesture.prototype.handleUp = function(e) {
|
||||
* end the drag at the most recent location.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.cancel = function() {
|
||||
Gesture.prototype.cancel = function() {
|
||||
// Disposing of a block cancels in-progress drags, but dragging to a delete
|
||||
// area disposes of a block and leads to recursive disposal. Break that cycle.
|
||||
if (this.isEnding_) {
|
||||
@@ -606,8 +612,7 @@ Blockly.Gesture.prototype.cancel = function() {
|
||||
this.bubbleDragger_.endBubbleDrag(
|
||||
this.mostRecentEvent_, this.currentDragDeltaXY_);
|
||||
} else if (this.isDraggingBlock_) {
|
||||
this.blockDragger_.endDrag(
|
||||
this.mostRecentEvent_, this.currentDragDeltaXY_);
|
||||
this.blockDragger_.endDrag(this.mostRecentEvent_, this.currentDragDeltaXY_);
|
||||
} else if (this.isDraggingWorkspace_) {
|
||||
this.workspaceDragger_.endDrag(this.currentDragDeltaXY_);
|
||||
}
|
||||
@@ -619,7 +624,7 @@ Blockly.Gesture.prototype.cancel = function() {
|
||||
* @param {!Event} e A mouse move or touch move event.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.handleRightClick = function(e) {
|
||||
Gesture.prototype.handleRightClick = function(e) {
|
||||
if (this.targetBlock_) {
|
||||
this.bringBlockToFront_();
|
||||
Blockly.hideChaff(!!this.flyout_);
|
||||
@@ -641,10 +646,10 @@ Blockly.Gesture.prototype.handleRightClick = function(e) {
|
||||
/**
|
||||
* Handle a mousedown/touchstart event on a workspace.
|
||||
* @param {!Event} e A mouse down or touch start event.
|
||||
* @param {!Blockly.WorkspaceSvg} ws The workspace the event hit.
|
||||
* @param {!WorkspaceSvg} ws The workspace the event hit.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.handleWsStart = function(e, ws) {
|
||||
Gesture.prototype.handleWsStart = function(e, ws) {
|
||||
if (this.hasStarted_) {
|
||||
throw Error(
|
||||
'Tried to call gesture.handleWsStart, ' +
|
||||
@@ -657,21 +662,20 @@ Blockly.Gesture.prototype.handleWsStart = function(e, ws) {
|
||||
|
||||
/**
|
||||
* Fires a workspace click event.
|
||||
* @param {!Blockly.WorkspaceSvg} ws The workspace that a user clicks on.
|
||||
* @param {!WorkspaceSvg} ws The workspace that a user clicks on.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.fireWorkspaceClick_ = function(ws) {
|
||||
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.CLICK))(
|
||||
null, ws.id, 'workspace'));
|
||||
Gesture.prototype.fireWorkspaceClick_ = function(ws) {
|
||||
Events.fire(new (Events.get(Events.CLICK))(null, ws.id, 'workspace'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle a mousedown/touchstart event on a flyout.
|
||||
* @param {!Event} e A mouse down or touch start event.
|
||||
* @param {!Blockly.IFlyout} flyout The flyout the event hit.
|
||||
* @param {!IFlyout} flyout The flyout the event hit.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.handleFlyoutStart = function(e, flyout) {
|
||||
Gesture.prototype.handleFlyoutStart = function(e, flyout) {
|
||||
if (this.hasStarted_) {
|
||||
throw Error(
|
||||
'Tried to call gesture.handleFlyoutStart, ' +
|
||||
@@ -684,10 +688,10 @@ Blockly.Gesture.prototype.handleFlyoutStart = function(e, flyout) {
|
||||
/**
|
||||
* Handle a mousedown/touchstart event on a block.
|
||||
* @param {!Event} e A mouse down or touch start event.
|
||||
* @param {!Blockly.BlockSvg} block The block the event hit.
|
||||
* @param {!BlockSvg} block The block the event hit.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.handleBlockStart = function(e, block) {
|
||||
Gesture.prototype.handleBlockStart = function(e, block) {
|
||||
if (this.hasStarted_) {
|
||||
throw Error(
|
||||
'Tried to call gesture.handleBlockStart, ' +
|
||||
@@ -700,10 +704,10 @@ Blockly.Gesture.prototype.handleBlockStart = function(e, block) {
|
||||
/**
|
||||
* Handle a mousedown/touchstart event on a bubble.
|
||||
* @param {!Event} e A mouse down or touch start event.
|
||||
* @param {!Blockly.IBubble} bubble The bubble the event hit.
|
||||
* @param {!IBubble} bubble The bubble the event hit.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.handleBubbleStart = function(e, bubble) {
|
||||
Gesture.prototype.handleBubbleStart = function(e, bubble) {
|
||||
if (this.hasStarted_) {
|
||||
throw Error(
|
||||
'Tried to call gesture.handleBubbleStart, ' +
|
||||
@@ -721,7 +725,7 @@ Blockly.Gesture.prototype.handleBubbleStart = function(e, bubble) {
|
||||
* Execute a bubble click.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.doBubbleClick_ = function() {
|
||||
Gesture.prototype.doBubbleClick_ = function() {
|
||||
// TODO (#1673): Consistent handling of single clicks.
|
||||
this.startBubble_.setFocus && this.startBubble_.setFocus();
|
||||
this.startBubble_.select && this.startBubble_.select();
|
||||
@@ -731,7 +735,7 @@ Blockly.Gesture.prototype.doBubbleClick_ = function() {
|
||||
* Execute a field click.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.doFieldClick_ = function() {
|
||||
Gesture.prototype.doFieldClick_ = function() {
|
||||
this.startField_.showEditor(this.mostRecentEvent_);
|
||||
this.bringBlockToFront_();
|
||||
};
|
||||
@@ -740,24 +744,24 @@ Blockly.Gesture.prototype.doFieldClick_ = function() {
|
||||
* Execute a block click.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.doBlockClick_ = function() {
|
||||
Gesture.prototype.doBlockClick_ = function() {
|
||||
// Block click in an autoclosing flyout.
|
||||
if (this.flyout_ && this.flyout_.autoClose) {
|
||||
if (this.targetBlock_.isEnabled()) {
|
||||
if (!Blockly.Events.getGroup()) {
|
||||
Blockly.Events.setGroup(true);
|
||||
if (!Events.getGroup()) {
|
||||
Events.setGroup(true);
|
||||
}
|
||||
var newBlock = this.flyout_.createBlock(this.targetBlock_);
|
||||
const newBlock = this.flyout_.createBlock(this.targetBlock_);
|
||||
newBlock.scheduleSnapAndBump();
|
||||
}
|
||||
} else {
|
||||
// Clicks events are on the start block, even if it was a shadow.
|
||||
var event = new (Blockly.Events.get(Blockly.Events.CLICK))(
|
||||
const event = new (Events.get(Events.CLICK))(
|
||||
this.startBlock_, this.startWorkspace_.id, 'block');
|
||||
Blockly.Events.fire(event);
|
||||
Events.fire(event);
|
||||
}
|
||||
this.bringBlockToFront_();
|
||||
Blockly.Events.setGroup(false);
|
||||
Events.setGroup(false);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -766,8 +770,8 @@ Blockly.Gesture.prototype.doBlockClick_ = function() {
|
||||
* @param {!Event} _e A mouse up or touch end event.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.doWorkspaceClick_ = function(_e) {
|
||||
var ws = this.creatorWorkspace_;
|
||||
Gesture.prototype.doWorkspaceClick_ = function(_e) {
|
||||
const ws = this.creatorWorkspace_;
|
||||
if (Blockly.selected) {
|
||||
Blockly.selected.unselect();
|
||||
}
|
||||
@@ -783,7 +787,7 @@ Blockly.Gesture.prototype.doWorkspaceClick_ = function(_e) {
|
||||
* not occluded by other blocks.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.bringBlockToFront_ = function() {
|
||||
Gesture.prototype.bringBlockToFront_ = function() {
|
||||
// Blocks in the flyout don't overlap, so skip the work.
|
||||
if (this.targetBlock_ && !this.flyout_) {
|
||||
this.targetBlock_.bringToFront();
|
||||
@@ -794,10 +798,10 @@ Blockly.Gesture.prototype.bringBlockToFront_ = function() {
|
||||
|
||||
/**
|
||||
* Record the field that a gesture started on.
|
||||
* @param {Blockly.Field} field The field the gesture started on.
|
||||
* @param {Field} field The field the gesture started on.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.setStartField = function(field) {
|
||||
Gesture.prototype.setStartField = function(field) {
|
||||
if (this.hasStarted_) {
|
||||
throw Error(
|
||||
'Tried to call gesture.setStartField, ' +
|
||||
@@ -810,10 +814,10 @@ Blockly.Gesture.prototype.setStartField = function(field) {
|
||||
|
||||
/**
|
||||
* Record the bubble that a gesture started on
|
||||
* @param {Blockly.IBubble} bubble The bubble the gesture started on.
|
||||
* @param {IBubble} bubble The bubble the gesture started on.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.setStartBubble = function(bubble) {
|
||||
Gesture.prototype.setStartBubble = function(bubble) {
|
||||
if (!this.startBubble_) {
|
||||
this.startBubble_ = bubble;
|
||||
}
|
||||
@@ -822,10 +826,10 @@ Blockly.Gesture.prototype.setStartBubble = function(bubble) {
|
||||
/**
|
||||
* Record the block that a gesture started on, and set the target block
|
||||
* appropriately.
|
||||
* @param {Blockly.BlockSvg} block The block the gesture started on.
|
||||
* @param {BlockSvg} block The block the gesture started on.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.setStartBlock = function(block) {
|
||||
Gesture.prototype.setStartBlock = function(block) {
|
||||
// If the gesture already went through a bubble, don't set the start block.
|
||||
if (!this.startBlock_ && !this.startBubble_) {
|
||||
this.startBlock_ = block;
|
||||
@@ -841,10 +845,10 @@ Blockly.Gesture.prototype.setStartBlock = function(block) {
|
||||
* Record the block that a gesture targets, meaning the block that will be
|
||||
* dragged if this turns into a drag. If this block is a shadow, that will be
|
||||
* its first non-shadow parent.
|
||||
* @param {Blockly.BlockSvg} block The block the gesture targets.
|
||||
* @param {BlockSvg} block The block the gesture targets.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.setTargetBlock_ = function(block) {
|
||||
Gesture.prototype.setTargetBlock_ = function(block) {
|
||||
if (block.isShadow()) {
|
||||
this.setTargetBlock_(block.getParent());
|
||||
} else {
|
||||
@@ -854,10 +858,10 @@ Blockly.Gesture.prototype.setTargetBlock_ = function(block) {
|
||||
|
||||
/**
|
||||
* Record the workspace that a gesture started on.
|
||||
* @param {Blockly.WorkspaceSvg} ws The workspace the gesture started on.
|
||||
* @param {WorkspaceSvg} ws The workspace the gesture started on.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.setStartWorkspace_ = function(ws) {
|
||||
Gesture.prototype.setStartWorkspace_ = function(ws) {
|
||||
if (!this.startWorkspace_) {
|
||||
this.startWorkspace_ = ws;
|
||||
}
|
||||
@@ -865,10 +869,10 @@ Blockly.Gesture.prototype.setStartWorkspace_ = function(ws) {
|
||||
|
||||
/**
|
||||
* Record the flyout that a gesture started on.
|
||||
* @param {Blockly.IFlyout} flyout The flyout the gesture started on.
|
||||
* @param {IFlyout} flyout The flyout the gesture started on.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.setStartFlyout_ = function(flyout) {
|
||||
Gesture.prototype.setStartFlyout_ = function(flyout) {
|
||||
if (!this.flyout_) {
|
||||
this.flyout_ = flyout;
|
||||
}
|
||||
@@ -886,9 +890,9 @@ Blockly.Gesture.prototype.setStartFlyout_ = function(flyout) {
|
||||
* @return {boolean} Whether this gesture was a click on a bubble.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.isBubbleClick_ = function() {
|
||||
Gesture.prototype.isBubbleClick_ = function() {
|
||||
// A bubble click starts on a bubble and never escapes the drag radius.
|
||||
var hasStartBubble = !!this.startBubble_;
|
||||
const hasStartBubble = !!this.startBubble_;
|
||||
return hasStartBubble && !this.hasExceededDragRadius_;
|
||||
};
|
||||
|
||||
@@ -898,10 +902,10 @@ Blockly.Gesture.prototype.isBubbleClick_ = function() {
|
||||
* @return {boolean} Whether this gesture was a click on a block.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.isBlockClick_ = function() {
|
||||
Gesture.prototype.isBlockClick_ = function() {
|
||||
// A block click starts on a block, never escapes the drag radius, and is not
|
||||
// a field click.
|
||||
var hasStartBlock = !!this.startBlock_;
|
||||
const hasStartBlock = !!this.startBlock_;
|
||||
return hasStartBlock && !this.hasExceededDragRadius_ && !this.isFieldClick_();
|
||||
};
|
||||
|
||||
@@ -911,8 +915,8 @@ Blockly.Gesture.prototype.isBlockClick_ = function() {
|
||||
* @return {boolean} Whether this gesture was a click on a field.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.isFieldClick_ = function() {
|
||||
var fieldClickable =
|
||||
Gesture.prototype.isFieldClick_ = function() {
|
||||
const fieldClickable =
|
||||
this.startField_ ? this.startField_.isClickable() : false;
|
||||
return fieldClickable && !this.hasExceededDragRadius_ &&
|
||||
(!this.flyout_ || !this.flyout_.autoClose);
|
||||
@@ -924,8 +928,8 @@ Blockly.Gesture.prototype.isFieldClick_ = function() {
|
||||
* @return {boolean} Whether this gesture was a click on a workspace.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.isWorkspaceClick_ = function() {
|
||||
var onlyTouchedWorkspace =
|
||||
Gesture.prototype.isWorkspaceClick_ = function() {
|
||||
const onlyTouchedWorkspace =
|
||||
!this.startBlock_ && !this.startBubble_ && !this.startField_;
|
||||
return onlyTouchedWorkspace && !this.hasExceededDragRadius_;
|
||||
};
|
||||
@@ -939,7 +943,7 @@ Blockly.Gesture.prototype.isWorkspaceClick_ = function() {
|
||||
* @return {boolean} True if this gesture is a drag of a workspace or block.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.isDragging = function() {
|
||||
Gesture.prototype.isDragging = function() {
|
||||
return this.isDraggingWorkspace_ || this.isDraggingBlock_ ||
|
||||
this.isDraggingBubble_;
|
||||
};
|
||||
@@ -951,18 +955,18 @@ Blockly.Gesture.prototype.isDragging = function() {
|
||||
* @return {boolean} Whether this gesture was a click on a workspace.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.hasStarted = function() {
|
||||
Gesture.prototype.hasStarted = function() {
|
||||
return this.hasStarted_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a list of the insertion markers that currently exist. Block drags have
|
||||
* 0, 1, or 2 insertion markers.
|
||||
* @return {!Array<!Blockly.BlockSvg>} A possibly empty list of insertion
|
||||
* @return {!Array<!BlockSvg>} A possibly empty list of insertion
|
||||
* marker blocks.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.getInsertionMarkers = function() {
|
||||
Gesture.prototype.getInsertionMarkers = function() {
|
||||
if (this.blockDragger_) {
|
||||
return this.blockDragger_.getInsertionMarkers();
|
||||
}
|
||||
@@ -972,10 +976,10 @@ Blockly.Gesture.prototype.getInsertionMarkers = function() {
|
||||
/**
|
||||
* Gets the current dragger if an item is being dragged. Null if nothing is
|
||||
* being dragged.
|
||||
* @return {!Blockly.WorkspaceDragger|!Blockly.BubbleDragger|!Blockly.IBlockDragger|null}
|
||||
* @return {!WorkspaceDragger|!BubbleDragger|!IBlockDragger|null}
|
||||
* The dragger that is currently in use or null if no drag is in progress.
|
||||
*/
|
||||
Blockly.Gesture.prototype.getCurrentDragger = function() {
|
||||
Gesture.prototype.getCurrentDragger = function() {
|
||||
if (this.isDraggingBlock_) {
|
||||
return this.blockDragger_;
|
||||
} else if (this.isDraggingWorkspace_) {
|
||||
@@ -990,12 +994,14 @@ Blockly.Gesture.prototype.getCurrentDragger = function() {
|
||||
* Is a drag or other gesture currently in progress on any workspace?
|
||||
* @return {boolean} True if gesture is occurring.
|
||||
*/
|
||||
Blockly.Gesture.inProgress = function() {
|
||||
var workspaces = Blockly.Workspace.getAll();
|
||||
for (var i = 0, workspace; (workspace = workspaces[i]); i++) {
|
||||
Gesture.inProgress = function() {
|
||||
const workspaces = Workspace.getAll();
|
||||
for (let i = 0, workspace; (workspace = workspaces[i]); i++) {
|
||||
if (workspace.currentGesture_) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
exports = Gesture;
|
||||
|
||||
69
core/grid.js
69
core/grid.js
@@ -11,11 +11,12 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Grid');
|
||||
goog.module('Blockly.Grid');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
goog.require('Blockly.utils.userAgent');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const userAgent = goog.require('Blockly.utils.userAgent');
|
||||
|
||||
|
||||
/**
|
||||
@@ -27,7 +28,7 @@ goog.require('Blockly.utils.userAgent');
|
||||
* https://developers.google.com/blockly/guides/configure/web/grid
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Grid = function(pattern, options) {
|
||||
const Grid = function(pattern, options) {
|
||||
/**
|
||||
* The grid's SVG pattern, created during injection.
|
||||
* @type {!SVGElement}
|
||||
@@ -61,8 +62,8 @@ Blockly.Grid = function(pattern, options) {
|
||||
* @type {SVGElement}
|
||||
* @private
|
||||
*/
|
||||
this.line2_ = this.line1_ &&
|
||||
(/** @type {SVGElement} */ (this.line1_.nextSibling));
|
||||
this.line2_ =
|
||||
this.line1_ && (/** @type {SVGElement} */ (this.line1_.nextSibling));
|
||||
|
||||
/**
|
||||
* Whether blocks should snap to the grid.
|
||||
@@ -78,14 +79,14 @@ Blockly.Grid = function(pattern, options) {
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
Blockly.Grid.prototype.scale_ = 1;
|
||||
Grid.prototype.scale_ = 1;
|
||||
|
||||
/**
|
||||
* Dispose of this grid and unlink from the DOM.
|
||||
* @package
|
||||
* @suppress {checkTypes}
|
||||
*/
|
||||
Blockly.Grid.prototype.dispose = function() {
|
||||
Grid.prototype.dispose = function() {
|
||||
this.gridPattern_ = null;
|
||||
};
|
||||
|
||||
@@ -94,7 +95,7 @@ Blockly.Grid.prototype.dispose = function() {
|
||||
* @return {boolean} True if blocks should snap, false otherwise.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Grid.prototype.shouldSnap = function() {
|
||||
Grid.prototype.shouldSnap = function() {
|
||||
return this.snapToGrid_;
|
||||
};
|
||||
|
||||
@@ -103,7 +104,7 @@ Blockly.Grid.prototype.shouldSnap = function() {
|
||||
* @return {number} The spacing of the grid points.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Grid.prototype.getSpacing = function() {
|
||||
Grid.prototype.getSpacing = function() {
|
||||
return this.spacing_;
|
||||
};
|
||||
|
||||
@@ -113,7 +114,7 @@ Blockly.Grid.prototype.getSpacing = function() {
|
||||
* @return {string} The pattern ID.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Grid.prototype.getPatternId = function() {
|
||||
Grid.prototype.getPatternId = function() {
|
||||
return this.gridPattern_.id;
|
||||
};
|
||||
|
||||
@@ -122,17 +123,17 @@ Blockly.Grid.prototype.getPatternId = function() {
|
||||
* @param {number} scale The new workspace scale.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Grid.prototype.update = function(scale) {
|
||||
Grid.prototype.update = function(scale) {
|
||||
this.scale_ = scale;
|
||||
// MSIE freaks if it sees a 0x0 pattern, so set empty patterns to 100x100.
|
||||
var safeSpacing = (this.spacing_ * scale) || 100;
|
||||
const safeSpacing = (this.spacing_ * scale) || 100;
|
||||
|
||||
this.gridPattern_.setAttribute('width', safeSpacing);
|
||||
this.gridPattern_.setAttribute('height', safeSpacing);
|
||||
|
||||
var half = Math.floor(this.spacing_ / 2) + 0.5;
|
||||
var start = half - this.length_ / 2;
|
||||
var end = half + this.length_ / 2;
|
||||
let half = Math.floor(this.spacing_ / 2) + 0.5;
|
||||
let start = half - this.length_ / 2;
|
||||
let end = half + this.length_ / 2;
|
||||
|
||||
half *= scale;
|
||||
start *= scale;
|
||||
@@ -153,8 +154,7 @@ Blockly.Grid.prototype.update = function(scale) {
|
||||
* @param {number} y2 The new y end position of the line (in px).
|
||||
* @private
|
||||
*/
|
||||
Blockly.Grid.prototype.setLineAttributes_ = function(line, width,
|
||||
x1, x2, y1, y2) {
|
||||
Grid.prototype.setLineAttributes_ = function(line, width, x1, x2, y1, y2) {
|
||||
if (line) {
|
||||
line.setAttribute('stroke-width', width);
|
||||
line.setAttribute('x1', x1);
|
||||
@@ -171,11 +171,11 @@ Blockly.Grid.prototype.setLineAttributes_ = function(line, width,
|
||||
* @param {number} y The new y position of the grid (in px).
|
||||
* @package
|
||||
*/
|
||||
Blockly.Grid.prototype.moveTo = function(x, y) {
|
||||
Grid.prototype.moveTo = function(x, y) {
|
||||
this.gridPattern_.setAttribute('x', x);
|
||||
this.gridPattern_.setAttribute('y', y);
|
||||
|
||||
if (Blockly.utils.userAgent.IE || Blockly.utils.userAgent.EDGE) {
|
||||
if (userAgent.IE || userAgent.EDGE) {
|
||||
// IE/Edge doesn't notice that the x/y offsets have changed.
|
||||
// Force an update.
|
||||
this.update(this.scale_);
|
||||
@@ -190,33 +190,30 @@ Blockly.Grid.prototype.moveTo = function(x, y) {
|
||||
* @return {!SVGElement} The SVG element for the grid pattern.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Grid.createDom = function(rnd, gridOptions, defs) {
|
||||
Grid.createDom = function(rnd, gridOptions, defs) {
|
||||
/*
|
||||
<pattern id="blocklyGridPattern837493" patternUnits="userSpaceOnUse">
|
||||
<rect stroke="#888" />
|
||||
<rect stroke="#888" />
|
||||
</pattern>
|
||||
*/
|
||||
var gridPattern = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.PATTERN,
|
||||
{
|
||||
'id': 'blocklyGridPattern' + rnd,
|
||||
'patternUnits': 'userSpaceOnUse'
|
||||
}, defs);
|
||||
const gridPattern = dom.createSvgElement(
|
||||
Svg.PATTERN,
|
||||
{'id': 'blocklyGridPattern' + rnd, 'patternUnits': 'userSpaceOnUse'},
|
||||
defs);
|
||||
if (gridOptions['length'] > 0 && gridOptions['spacing'] > 0) {
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.LINE,
|
||||
{'stroke': gridOptions['colour']}, gridPattern);
|
||||
dom.createSvgElement(
|
||||
Svg.LINE, {'stroke': gridOptions['colour']}, gridPattern);
|
||||
if (gridOptions['length'] > 1) {
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.LINE,
|
||||
{'stroke': gridOptions['colour']}, gridPattern);
|
||||
dom.createSvgElement(
|
||||
Svg.LINE, {'stroke': gridOptions['colour']}, gridPattern);
|
||||
}
|
||||
// x1, y1, x1, x2 properties will be set later in update.
|
||||
} else {
|
||||
// Edge 16 doesn't handle empty patterns
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.LINE, {}, gridPattern);
|
||||
dom.createSvgElement(Svg.LINE, {}, gridPattern);
|
||||
}
|
||||
return gridPattern;
|
||||
};
|
||||
|
||||
exports = Grid;
|
||||
|
||||
97
core/icon.js
97
core/icon.js
@@ -10,29 +10,31 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Icon');
|
||||
goog.module('Blockly.Icon');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.browserEvents');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.Size');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.Bubble');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Bubble = goog.requireType('Blockly.Bubble');
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
const Size = goog.require('Blockly.utils.Size');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
const browserEvents = goog.require('Blockly.browserEvents');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const {getRelativeXY, isRightButton} = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
* Class for an icon.
|
||||
* @param {Blockly.BlockSvg} block The block associated with this icon.
|
||||
* @param {BlockSvg} block The block associated with this icon.
|
||||
* @constructor
|
||||
* @abstract
|
||||
*/
|
||||
Blockly.Icon = function(block) {
|
||||
const Icon = function(block) {
|
||||
/**
|
||||
* The block this icon is attached to.
|
||||
* @type {Blockly.BlockSvg}
|
||||
* @type {BlockSvg}
|
||||
* @protected
|
||||
*/
|
||||
this.block_ = block;
|
||||
@@ -47,31 +49,32 @@ Blockly.Icon = function(block) {
|
||||
/**
|
||||
* Does this icon get hidden when the block is collapsed.
|
||||
*/
|
||||
Blockly.Icon.prototype.collapseHidden = true;
|
||||
Icon.prototype.collapseHidden = true;
|
||||
|
||||
/**
|
||||
* Height and width of icons.
|
||||
* @const
|
||||
*/
|
||||
Blockly.Icon.prototype.SIZE = 17;
|
||||
Icon.prototype.SIZE = 17;
|
||||
|
||||
/**
|
||||
* Bubble UI (if visible).
|
||||
* @type {?Blockly.Bubble}
|
||||
* @type {?Bubble}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Icon.prototype.bubble_ = null;
|
||||
Icon.prototype.bubble_ = null;
|
||||
|
||||
/**
|
||||
* Absolute coordinate of icon's center.
|
||||
* @type {?Blockly.utils.Coordinate}
|
||||
* @type {?Coordinate}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Icon.prototype.iconXY_ = null;
|
||||
Icon.prototype.iconXY_ = null;
|
||||
|
||||
/**
|
||||
* Create the icon on the block.
|
||||
*/
|
||||
Blockly.Icon.prototype.createIcon = function() {
|
||||
Icon.prototype.createIcon = function() {
|
||||
if (this.iconGroup_) {
|
||||
// Icon already exists.
|
||||
return;
|
||||
@@ -81,17 +84,16 @@ Blockly.Icon.prototype.createIcon = function() {
|
||||
...
|
||||
</g>
|
||||
*/
|
||||
this.iconGroup_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.G,
|
||||
{'class': 'blocklyIconGroup'}, null);
|
||||
this.iconGroup_ =
|
||||
dom.createSvgElement(Svg.G, {'class': 'blocklyIconGroup'}, null);
|
||||
if (this.block_.isInFlyout) {
|
||||
Blockly.utils.dom.addClass(
|
||||
dom.addClass(
|
||||
/** @type {!Element} */ (this.iconGroup_), 'blocklyIconGroupReadonly');
|
||||
}
|
||||
this.drawIcon_(this.iconGroup_);
|
||||
|
||||
this.block_.getSvgRoot().appendChild(this.iconGroup_);
|
||||
Blockly.browserEvents.conditionalBind(
|
||||
browserEvents.conditionalBind(
|
||||
this.iconGroup_, 'mouseup', this, this.iconClick_);
|
||||
this.updateEditable();
|
||||
};
|
||||
@@ -99,9 +101,9 @@ Blockly.Icon.prototype.createIcon = function() {
|
||||
/**
|
||||
* Dispose of this icon.
|
||||
*/
|
||||
Blockly.Icon.prototype.dispose = function() {
|
||||
Icon.prototype.dispose = function() {
|
||||
// Dispose of and unlink the icon.
|
||||
Blockly.utils.dom.removeNode(this.iconGroup_);
|
||||
dom.removeNode(this.iconGroup_);
|
||||
this.iconGroup_ = null;
|
||||
// Dispose of and unlink the bubble.
|
||||
this.setVisible(false);
|
||||
@@ -111,7 +113,7 @@ Blockly.Icon.prototype.dispose = function() {
|
||||
/**
|
||||
* Add or remove the UI indicating if this icon may be clicked or not.
|
||||
*/
|
||||
Blockly.Icon.prototype.updateEditable = function() {
|
||||
Icon.prototype.updateEditable = function() {
|
||||
// No-op on the base class.
|
||||
};
|
||||
|
||||
@@ -119,7 +121,7 @@ Blockly.Icon.prototype.updateEditable = function() {
|
||||
* Is the associated bubble visible?
|
||||
* @return {boolean} True if the bubble is visible.
|
||||
*/
|
||||
Blockly.Icon.prototype.isVisible = function() {
|
||||
Icon.prototype.isVisible = function() {
|
||||
return !!this.bubble_;
|
||||
};
|
||||
|
||||
@@ -128,12 +130,12 @@ Blockly.Icon.prototype.isVisible = function() {
|
||||
* @param {!Event} e Mouse click event.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Icon.prototype.iconClick_ = function(e) {
|
||||
Icon.prototype.iconClick_ = function(e) {
|
||||
if (this.block_.workspace.isDragging()) {
|
||||
// Drag operation is concluding. Don't open the editor.
|
||||
return;
|
||||
}
|
||||
if (!this.block_.isInFlyout && !Blockly.utils.isRightButton(e)) {
|
||||
if (!this.block_.isInFlyout && !isRightButton(e)) {
|
||||
this.setVisible(!this.isVisible());
|
||||
}
|
||||
};
|
||||
@@ -141,7 +143,7 @@ Blockly.Icon.prototype.iconClick_ = function(e) {
|
||||
/**
|
||||
* Change the colour of the associated bubble to match its block.
|
||||
*/
|
||||
Blockly.Icon.prototype.applyColour = function() {
|
||||
Icon.prototype.applyColour = function() {
|
||||
if (this.isVisible()) {
|
||||
this.bubble_.setColour(this.block_.style.colourPrimary);
|
||||
}
|
||||
@@ -149,9 +151,9 @@ Blockly.Icon.prototype.applyColour = function() {
|
||||
|
||||
/**
|
||||
* Notification that the icon has moved. Update the arrow accordingly.
|
||||
* @param {!Blockly.utils.Coordinate} xy Absolute location in workspace coordinates.
|
||||
* @param {!Coordinate} xy Absolute location in workspace coordinates.
|
||||
*/
|
||||
Blockly.Icon.prototype.setIconLocation = function(xy) {
|
||||
Icon.prototype.setIconLocation = function(xy) {
|
||||
this.iconXY_ = xy;
|
||||
if (this.isVisible()) {
|
||||
this.bubble_.setAnchorLocation(xy);
|
||||
@@ -162,25 +164,25 @@ Blockly.Icon.prototype.setIconLocation = function(xy) {
|
||||
* Notification that the icon has moved, but we don't really know where.
|
||||
* Recompute the icon's location from scratch.
|
||||
*/
|
||||
Blockly.Icon.prototype.computeIconLocation = function() {
|
||||
Icon.prototype.computeIconLocation = function() {
|
||||
// Find coordinates for the centre of the icon and update the arrow.
|
||||
var blockXY = this.block_.getRelativeToSurfaceXY();
|
||||
var iconXY = Blockly.utils.getRelativeXY(
|
||||
const blockXY = this.block_.getRelativeToSurfaceXY();
|
||||
const iconXY = getRelativeXY(
|
||||
/** @type {!SVGElement} */ (this.iconGroup_));
|
||||
var newXY = new Blockly.utils.Coordinate(
|
||||
const newXY = new Coordinate(
|
||||
blockXY.x + iconXY.x + this.SIZE / 2,
|
||||
blockXY.y + iconXY.y + this.SIZE / 2);
|
||||
if (!Blockly.utils.Coordinate.equals(this.getIconLocation(), newXY)) {
|
||||
if (!Coordinate.equals(this.getIconLocation(), newXY)) {
|
||||
this.setIconLocation(newXY);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the center of the block's icon relative to the surface.
|
||||
* @return {?Blockly.utils.Coordinate} Object with x and y properties in
|
||||
* @return {?Coordinate} Object with x and y properties in
|
||||
* workspace coordinates.
|
||||
*/
|
||||
Blockly.Icon.prototype.getIconLocation = function() {
|
||||
Icon.prototype.getIconLocation = function() {
|
||||
return this.iconXY_;
|
||||
};
|
||||
|
||||
@@ -188,12 +190,11 @@ Blockly.Icon.prototype.getIconLocation = function() {
|
||||
* Get the size of the icon as used for rendering.
|
||||
* This differs from the actual size of the icon, because it bulges slightly
|
||||
* out of its row rather than increasing the height of its row.
|
||||
* @return {!Blockly.utils.Size} Height and width.
|
||||
* @return {!Size} Height and width.
|
||||
*/
|
||||
// TODO (#2562): Remove getCorrectedSize.
|
||||
Blockly.Icon.prototype.getCorrectedSize = function() {
|
||||
return new Blockly.utils.Size(
|
||||
Blockly.Icon.prototype.SIZE, Blockly.Icon.prototype.SIZE - 2);
|
||||
Icon.prototype.getCorrectedSize = function() {
|
||||
return new Size(Icon.prototype.SIZE, Icon.prototype.SIZE - 2);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -201,10 +202,12 @@ Blockly.Icon.prototype.getCorrectedSize = function() {
|
||||
* @param {!Element} group The icon group.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Icon.prototype.drawIcon_;
|
||||
Icon.prototype.drawIcon_;
|
||||
|
||||
/**
|
||||
* Show or hide the icon.
|
||||
* @param {boolean} visible True if the icon should be visible.
|
||||
*/
|
||||
Blockly.Icon.prototype.setVisible;
|
||||
Icon.prototype.setVisible;
|
||||
|
||||
exports = Icon;
|
||||
|
||||
115
core/input.js
115
core/input.js
@@ -10,33 +10,36 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Input');
|
||||
goog.module('Blockly.Input');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Connection');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.fieldRegistry');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Connection = goog.require('Blockly.Connection');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Field = goog.requireType('Blockly.Field');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const RenderedConnection = goog.requireType('Blockly.RenderedConnection');
|
||||
const constants = goog.require('Blockly.constants');
|
||||
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
||||
const inputTypes = goog.require('Blockly.inputTypes');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.FieldLabel');
|
||||
goog.require('Blockly.inputTypes');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.Field');
|
||||
goog.requireType('Blockly.RenderedConnection');
|
||||
|
||||
|
||||
/**
|
||||
* Class for an input with an optional field.
|
||||
* @param {number} type The type of the input.
|
||||
* @param {string} name Language-neutral identifier which may used to find this
|
||||
* input again.
|
||||
* @param {!Blockly.Block} block The block containing this input.
|
||||
* @param {Blockly.Connection} connection Optional connection for this input.
|
||||
* @param {!Block} block The block containing this input.
|
||||
* @param {Connection} connection Optional connection for this input.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Input = function(type, name, block, connection) {
|
||||
if (type != Blockly.inputTypes.DUMMY && !name) {
|
||||
const Input = function(type, name, block, connection) {
|
||||
if (type != inputTypes.DUMMY && !name) {
|
||||
throw Error('Value inputs and statement inputs must have non-empty name.');
|
||||
}
|
||||
/** @type {number} */
|
||||
@@ -44,13 +47,13 @@ Blockly.Input = function(type, name, block, connection) {
|
||||
/** @type {string} */
|
||||
this.name = name;
|
||||
/**
|
||||
* @type {!Blockly.Block}
|
||||
* @type {!Block}
|
||||
* @private
|
||||
*/
|
||||
this.sourceBlock_ = block;
|
||||
/** @type {Blockly.Connection} */
|
||||
/** @type {Connection} */
|
||||
this.connection = connection;
|
||||
/** @type {!Array<!Blockly.Field>} */
|
||||
/** @type {!Array<!Field>} */
|
||||
this.fieldRow = [];
|
||||
};
|
||||
|
||||
@@ -58,32 +61,32 @@ Blockly.Input = function(type, name, block, connection) {
|
||||
* Alignment of input's fields (left, right or centre).
|
||||
* @type {number}
|
||||
*/
|
||||
Blockly.Input.prototype.align = Blockly.constants.ALIGN.LEFT;
|
||||
Input.prototype.align = constants.ALIGN.LEFT;
|
||||
|
||||
/**
|
||||
* Is the input visible?
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
Blockly.Input.prototype.visible_ = true;
|
||||
Input.prototype.visible_ = true;
|
||||
|
||||
/**
|
||||
* Get the source block for this input.
|
||||
* @return {?Blockly.Block} The source block, or null if there is none.
|
||||
* @return {?Block} The source block, or null if there is none.
|
||||
*/
|
||||
Blockly.Input.prototype.getSourceBlock = function() {
|
||||
Input.prototype.getSourceBlock = function() {
|
||||
return this.sourceBlock_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a field (or label from string), and all prefix and suffix fields, to the
|
||||
* end of the input's field row.
|
||||
* @param {string|!Blockly.Field} field Something to add as a field.
|
||||
* @param {string|!Field} field Something to add as a field.
|
||||
* @param {string=} opt_name Language-neutral identifier which may used to find
|
||||
* this field again. Should be unique to the host block.
|
||||
* @return {!Blockly.Input} The input being append to (to allow chaining).
|
||||
* @return {!Input} The input being append to (to allow chaining).
|
||||
*/
|
||||
Blockly.Input.prototype.appendField = function(field, opt_name) {
|
||||
Input.prototype.appendField = function(field, opt_name) {
|
||||
this.insertFieldAt(this.fieldRow.length, field, opt_name);
|
||||
return this;
|
||||
};
|
||||
@@ -92,12 +95,12 @@ Blockly.Input.prototype.appendField = function(field, opt_name) {
|
||||
* Inserts a field (or label from string), and all prefix and suffix fields, at
|
||||
* the location of the input's field row.
|
||||
* @param {number} index The index at which to insert field.
|
||||
* @param {string|!Blockly.Field} field Something to add as a field.
|
||||
* @param {string|!Field} field Something to add as a field.
|
||||
* @param {string=} opt_name Language-neutral identifier which may used to find
|
||||
* this field again. Should be unique to the host block.
|
||||
* @return {number} The index following the last inserted field.
|
||||
*/
|
||||
Blockly.Input.prototype.insertFieldAt = function(index, field, opt_name) {
|
||||
Input.prototype.insertFieldAt = function(index, field, opt_name) {
|
||||
if (index < 0 || index > this.fieldRow.length) {
|
||||
throw Error('index ' + index + ' out of bounds.');
|
||||
}
|
||||
@@ -109,7 +112,7 @@ Blockly.Input.prototype.insertFieldAt = function(index, field, opt_name) {
|
||||
|
||||
// Generate a FieldLabel when given a plain text field.
|
||||
if (typeof field == 'string') {
|
||||
field = /** @type {!Blockly.Field} **/ (Blockly.fieldRegistry.fromJson({
|
||||
field = /** @type {!Field} **/ (fieldRegistry.fromJson({
|
||||
'type': 'field_label',
|
||||
'text': field,
|
||||
}));
|
||||
@@ -136,7 +139,7 @@ Blockly.Input.prototype.insertFieldAt = function(index, field, opt_name) {
|
||||
}
|
||||
|
||||
if (this.sourceBlock_.rendered) {
|
||||
this.sourceBlock_ = /** @type {!Blockly.BlockSvg} */ (this.sourceBlock_);
|
||||
this.sourceBlock_ = /** @type {!BlockSvg} */ (this.sourceBlock_);
|
||||
this.sourceBlock_.render();
|
||||
// Adding a field will cause the block to change shape.
|
||||
this.sourceBlock_.bumpNeighbours();
|
||||
@@ -152,13 +155,13 @@ Blockly.Input.prototype.insertFieldAt = function(index, field, opt_name) {
|
||||
* and opt_quiet is true.
|
||||
* @throws {Error} if the field is not present and opt_quiet is false.
|
||||
*/
|
||||
Blockly.Input.prototype.removeField = function(name, opt_quiet) {
|
||||
for (var i = 0, field; (field = this.fieldRow[i]); i++) {
|
||||
Input.prototype.removeField = function(name, opt_quiet) {
|
||||
for (let i = 0, field; (field = this.fieldRow[i]); i++) {
|
||||
if (field.name === name) {
|
||||
field.dispose();
|
||||
this.fieldRow.splice(i, 1);
|
||||
if (this.sourceBlock_.rendered) {
|
||||
this.sourceBlock_ = /** @type {!Blockly.BlockSvg} */ (this.sourceBlock_);
|
||||
this.sourceBlock_ = /** @type {!BlockSvg} */ (this.sourceBlock_);
|
||||
this.sourceBlock_.render();
|
||||
// Removing a field will cause the block to change shape.
|
||||
this.sourceBlock_.bumpNeighbours();
|
||||
@@ -176,7 +179,7 @@ Blockly.Input.prototype.removeField = function(name, opt_quiet) {
|
||||
* Gets whether this input is visible or not.
|
||||
* @return {boolean} True if visible.
|
||||
*/
|
||||
Blockly.Input.prototype.isVisible = function() {
|
||||
Input.prototype.isVisible = function() {
|
||||
return this.visible_;
|
||||
};
|
||||
|
||||
@@ -184,32 +187,32 @@ Blockly.Input.prototype.isVisible = function() {
|
||||
* Sets whether this input is visible or not.
|
||||
* Should only be used to collapse/uncollapse a block.
|
||||
* @param {boolean} visible True if visible.
|
||||
* @return {!Array<!Blockly.BlockSvg>} List of blocks to render.
|
||||
* @return {!Array<!BlockSvg>} List of blocks to render.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Input.prototype.setVisible = function(visible) {
|
||||
Input.prototype.setVisible = function(visible) {
|
||||
// Note: Currently there are only unit tests for block.setCollapsed()
|
||||
// because this function is package. If this function goes back to being a
|
||||
// public API tests (lots of tests) should be added.
|
||||
var renderList = [];
|
||||
let renderList = [];
|
||||
if (this.visible_ == visible) {
|
||||
return renderList;
|
||||
}
|
||||
this.visible_ = visible;
|
||||
|
||||
for (var y = 0, field; (field = this.fieldRow[y]); y++) {
|
||||
for (let y = 0, field; (field = this.fieldRow[y]); y++) {
|
||||
field.setVisible(visible);
|
||||
}
|
||||
if (this.connection) {
|
||||
this.connection =
|
||||
/** @type {!Blockly.RenderedConnection} */ (this.connection);
|
||||
/** @type {!RenderedConnection} */ (this.connection);
|
||||
// Has a connection.
|
||||
if (visible) {
|
||||
renderList = this.connection.startTrackingAll();
|
||||
} else {
|
||||
this.connection.stopTrackingAll();
|
||||
}
|
||||
var child = this.connection.targetBlock();
|
||||
const child = this.connection.targetBlock();
|
||||
if (child) {
|
||||
child.getSvgRoot().style.display = visible ? 'block' : 'none';
|
||||
}
|
||||
@@ -221,8 +224,8 @@ Blockly.Input.prototype.setVisible = function(visible) {
|
||||
* Mark all fields on this input as dirty.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Input.prototype.markDirty = function() {
|
||||
for (var y = 0, field; (field = this.fieldRow[y]); y++) {
|
||||
Input.prototype.markDirty = function() {
|
||||
for (let y = 0, field; (field = this.fieldRow[y]); y++) {
|
||||
field.markDirty();
|
||||
}
|
||||
};
|
||||
@@ -231,9 +234,9 @@ Blockly.Input.prototype.markDirty = function() {
|
||||
* Change a connection's compatibility.
|
||||
* @param {string|Array<string>|null} check Compatible value type or
|
||||
* list of value types. Null if all types are compatible.
|
||||
* @return {!Blockly.Input} The input being modified (to allow chaining).
|
||||
* @return {!Input} The input being modified (to allow chaining).
|
||||
*/
|
||||
Blockly.Input.prototype.setCheck = function(check) {
|
||||
Input.prototype.setCheck = function(check) {
|
||||
if (!this.connection) {
|
||||
throw Error('This input does not have a connection.');
|
||||
}
|
||||
@@ -243,14 +246,14 @@ Blockly.Input.prototype.setCheck = function(check) {
|
||||
|
||||
/**
|
||||
* Change the alignment of the connection's field(s).
|
||||
* @param {number} align One of the values of Blockly.constants.ALIGN.
|
||||
* @param {number} align One of the values of constants.ALIGN.
|
||||
* In RTL mode directions are reversed, and ALIGN.RIGHT aligns to the left.
|
||||
* @return {!Blockly.Input} The input being modified (to allow chaining).
|
||||
* @return {!Input} The input being modified (to allow chaining).
|
||||
*/
|
||||
Blockly.Input.prototype.setAlign = function(align) {
|
||||
Input.prototype.setAlign = function(align) {
|
||||
this.align = align;
|
||||
if (this.sourceBlock_.rendered) {
|
||||
this.sourceBlock_ = /** @type {!Blockly.BlockSvg} */ (this.sourceBlock_);
|
||||
this.sourceBlock_ = /** @type {!BlockSvg} */ (this.sourceBlock_);
|
||||
this.sourceBlock_.render();
|
||||
}
|
||||
return this;
|
||||
@@ -259,9 +262,9 @@ Blockly.Input.prototype.setAlign = function(align) {
|
||||
/**
|
||||
* Changes the connection's shadow block.
|
||||
* @param {?Element} shadow DOM representation of a block or null.
|
||||
* @return {!Blockly.Input} The input being modified (to allow chaining).
|
||||
* @return {!Input} The input being modified (to allow chaining).
|
||||
*/
|
||||
Blockly.Input.prototype.setShadowDom = function(shadow) {
|
||||
Input.prototype.setShadowDom = function(shadow) {
|
||||
if (!this.connection) {
|
||||
throw Error('This input does not have a connection.');
|
||||
}
|
||||
@@ -273,7 +276,7 @@ Blockly.Input.prototype.setShadowDom = function(shadow) {
|
||||
* Returns the XML representation of the connection's shadow block.
|
||||
* @return {?Element} Shadow DOM representation of a block or null.
|
||||
*/
|
||||
Blockly.Input.prototype.getShadowDom = function() {
|
||||
Input.prototype.getShadowDom = function() {
|
||||
if (!this.connection) {
|
||||
throw Error('This input does not have a connection.');
|
||||
}
|
||||
@@ -283,11 +286,11 @@ Blockly.Input.prototype.getShadowDom = function() {
|
||||
/**
|
||||
* Initialize the fields on this input.
|
||||
*/
|
||||
Blockly.Input.prototype.init = function() {
|
||||
Input.prototype.init = function() {
|
||||
if (!this.sourceBlock_.workspace.rendered) {
|
||||
return; // Headless blocks don't need fields initialized.
|
||||
}
|
||||
for (var i = 0; i < this.fieldRow.length; i++) {
|
||||
for (let i = 0; i < this.fieldRow.length; i++) {
|
||||
this.fieldRow[i].init();
|
||||
}
|
||||
};
|
||||
@@ -296,8 +299,8 @@ Blockly.Input.prototype.init = function() {
|
||||
* Sever all links to this input.
|
||||
* @suppress {checkTypes}
|
||||
*/
|
||||
Blockly.Input.prototype.dispose = function() {
|
||||
for (var i = 0, field; (field = this.fieldRow[i]); i++) {
|
||||
Input.prototype.dispose = function() {
|
||||
for (let i = 0, field; (field = this.fieldRow[i]); i++) {
|
||||
field.dispose();
|
||||
}
|
||||
if (this.connection) {
|
||||
@@ -305,3 +308,5 @@ Blockly.Input.prototype.dispose = function() {
|
||||
}
|
||||
this.sourceBlock_ = null;
|
||||
};
|
||||
|
||||
exports = Input;
|
||||
|
||||
@@ -15,9 +15,8 @@ goog.provide('Blockly.InsertionMarkerManager');
|
||||
goog.require('Blockly.blockAnimations');
|
||||
goog.require('Blockly.ComponentManager');
|
||||
goog.require('Blockly.connectionTypes');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.internalConstants');
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.RenderedConnection');
|
||||
@@ -378,8 +377,10 @@ Blockly.InsertionMarkerManager.prototype.shouldUpdatePreviews_ = function(
|
||||
var yDiff = this.localConnection_.y + dxy.y - this.closestConnection_.y;
|
||||
var curDistance = Math.sqrt(xDiff * xDiff + yDiff * yDiff);
|
||||
// Slightly prefer the existing preview over a new preview.
|
||||
return !(candidateClosest && radius > curDistance -
|
||||
Blockly.CURRENT_CONNECTION_PREFERENCE);
|
||||
return !(
|
||||
candidateClosest &&
|
||||
radius > curDistance -
|
||||
Blockly.internalConstants.CURRENT_CONNECTION_PREFERENCE);
|
||||
} else if (!this.localConnection_ && !this.closestConnection_) {
|
||||
// We weren't showing a preview before, but we should now.
|
||||
return true;
|
||||
@@ -439,9 +440,9 @@ Blockly.InsertionMarkerManager.prototype.getStartRadius_ = function() {
|
||||
// By increasing radiusConnection when a connection already exists,
|
||||
// we never "lose" the connection from the offset.
|
||||
if (this.closestConnection_ && this.localConnection_) {
|
||||
return Blockly.CONNECTING_SNAP_RADIUS;
|
||||
return Blockly.internalConstants.CONNECTING_SNAP_RADIUS;
|
||||
}
|
||||
return Blockly.SNAP_RADIUS;
|
||||
return Blockly.internalConstants.SNAP_RADIUS;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview AST Node and keyboard navigation interfaces.
|
||||
* @author samelh@google.com (Sam El-Husseini)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IASTNodeLocation');
|
||||
goog.provide('Blockly.IASTNodeLocationSvg');
|
||||
goog.provide('Blockly.IASTNodeLocationWithBlock');
|
||||
goog.provide('Blockly.IKeyboardAccessible');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
goog.requireType('Blockly.ShortcutRegistry');
|
||||
|
||||
|
||||
/**
|
||||
* An AST node location interface.
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IASTNodeLocation = function() {};
|
||||
|
||||
/**
|
||||
* An AST node location SVG interface.
|
||||
* @interface
|
||||
* @extends {Blockly.IASTNodeLocation}
|
||||
*/
|
||||
Blockly.IASTNodeLocationSvg = function() {};
|
||||
|
||||
/**
|
||||
* Add the marker SVG to this node's SVG group.
|
||||
* @param {SVGElement} markerSvg The SVG root of the marker to be added to the
|
||||
* SVG group.
|
||||
*/
|
||||
Blockly.IASTNodeLocationSvg.prototype.setMarkerSvg;
|
||||
|
||||
/**
|
||||
* Add the cursor SVG to this node's SVG group.
|
||||
* @param {SVGElement} cursorSvg The SVG root of the cursor to be added to the
|
||||
* SVG group.
|
||||
*/
|
||||
Blockly.IASTNodeLocationSvg.prototype.setCursorSvg;
|
||||
|
||||
/**
|
||||
* An AST node location that has an associated block.
|
||||
* @interface
|
||||
* @extends {Blockly.IASTNodeLocation}
|
||||
*/
|
||||
Blockly.IASTNodeLocationWithBlock = function() {};
|
||||
|
||||
/**
|
||||
* Get the source block associated with this node.
|
||||
* @return {Blockly.Block} The source block.
|
||||
*/
|
||||
Blockly.IASTNodeLocationWithBlock.prototype.getSourceBlock;
|
||||
|
||||
|
||||
/**
|
||||
* An interface for an object that handles keyboard shortcuts.
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IKeyboardAccessible = function() {};
|
||||
|
||||
/**
|
||||
* Handles the given keyboard shortcut.
|
||||
* @param {!Blockly.ShortcutRegistry.KeyboardShortcut} shortcut The shortcut to be handled.
|
||||
* @return {boolean} True if the shortcut has been handled, false otherwise.
|
||||
*/
|
||||
Blockly.IKeyboardAccessible.prototype.onShortcut;
|
||||
23
core/interfaces/i_ast_node_location.js
Normal file
23
core/interfaces/i_ast_node_location.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The interface for an AST node location.
|
||||
* @author samelh@google.com (Sam El-Husseini)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.IASTNodeLocation');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/**
|
||||
* An AST node location interface.
|
||||
* @interface
|
||||
*/
|
||||
const IASTNodeLocation = function() {};
|
||||
|
||||
exports = IASTNodeLocation;
|
||||
42
core/interfaces/i_ast_node_location_svg.js
Normal file
42
core/interfaces/i_ast_node_location_svg.js
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The interface for an AST node location SVG.
|
||||
* @author samelh@google.com (Sam El-Husseini)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.IASTNodeLocationSvg');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IASTNodeLocation = goog.require('Blockly.IASTNodeLocation');
|
||||
|
||||
|
||||
/**
|
||||
* An AST node location SVG interface.
|
||||
* @interface
|
||||
* @extends {IASTNodeLocation}
|
||||
*/
|
||||
const IASTNodeLocationSvg = function() {};
|
||||
|
||||
/**
|
||||
* Add the marker SVG to this node's SVG group.
|
||||
* @param {SVGElement} markerSvg The SVG root of the marker to be added to the
|
||||
* SVG group.
|
||||
*/
|
||||
IASTNodeLocationSvg.prototype.setMarkerSvg;
|
||||
|
||||
/**
|
||||
* Add the cursor SVG to this node's SVG group.
|
||||
* @param {SVGElement} cursorSvg The SVG root of the cursor to be added to the
|
||||
* SVG group.
|
||||
*/
|
||||
IASTNodeLocationSvg.prototype.setCursorSvg;
|
||||
|
||||
exports = IASTNodeLocationSvg;
|
||||
37
core/interfaces/i_ast_node_location_with_block.js
Normal file
37
core/interfaces/i_ast_node_location_with_block.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The interface for an AST node location that has an associated
|
||||
* block.
|
||||
* @author samelh@google.com (Sam El-Husseini)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.IASTNodeLocationWithBlock');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IASTNodeLocation = goog.require('Blockly.IASTNodeLocation');
|
||||
|
||||
|
||||
/**
|
||||
* An AST node location that has an associated block.
|
||||
* @interface
|
||||
* @extends {IASTNodeLocation}
|
||||
*/
|
||||
const IASTNodeLocationWithBlock = function() {};
|
||||
|
||||
/**
|
||||
* Get the source block associated with this node.
|
||||
* @return {Block} The source block.
|
||||
*/
|
||||
IASTNodeLocationWithBlock.prototype.getSourceBlock;
|
||||
|
||||
exports = IASTNodeLocationWithBlock;
|
||||
@@ -12,21 +12,25 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IAutoHideable');
|
||||
goog.module('Blockly.IAutoHideable');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.IComponent');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IComponent = goog.require('Blockly.IComponent');
|
||||
|
||||
|
||||
/**
|
||||
* Interface for a component that can be automatically hidden.
|
||||
* @extends {Blockly.IComponent}
|
||||
* @extends {IComponent}
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IAutoHideable = function() {};
|
||||
const IAutoHideable = function() {};
|
||||
|
||||
/**
|
||||
* Hides the component. Called in Blockly.hideChaff.
|
||||
* @param {boolean} onlyClosePopups Whether only popups should be closed.
|
||||
* Flyouts should not be closed if this is true.
|
||||
*/
|
||||
Blockly.IAutoHideable.prototype.autoHide;
|
||||
IAutoHideable.prototype.autoHide;
|
||||
|
||||
exports = IAutoHideable;
|
||||
|
||||
@@ -11,48 +11,53 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IBlockDragger');
|
||||
goog.module('Blockly.IBlockDragger');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.utils.Coordinate');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Coordinate = goog.requireType('Blockly.utils.Coordinate');
|
||||
|
||||
|
||||
/**
|
||||
* A block dragger interface.
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IBlockDragger = function() {};
|
||||
const IBlockDragger = function() {};
|
||||
|
||||
/**
|
||||
* Start dragging a block. This includes moving it to the drag surface.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the position at mouse down, in pixel units.
|
||||
* @param {boolean} healStack Whether or not to heal the stack after
|
||||
* disconnecting.
|
||||
*/
|
||||
Blockly.IBlockDragger.prototype.startDrag;
|
||||
IBlockDragger.prototype.startDrag;
|
||||
|
||||
/**
|
||||
* Execute a step of block dragging, based on the given event. Update the
|
||||
* display accordingly.
|
||||
* @param {!Event} e The most recent move event.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the position at the start of the drag, in pixel units.
|
||||
*/
|
||||
Blockly.IBlockDragger.prototype.drag;
|
||||
IBlockDragger.prototype.drag;
|
||||
|
||||
/**
|
||||
* Finish a block drag and put the block back on the workspace.
|
||||
* @param {!Event} e The mouseup/touchend event.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the position at the start of the drag, in pixel units.
|
||||
*/
|
||||
Blockly.IBlockDragger.prototype.endDrag;
|
||||
IBlockDragger.prototype.endDrag;
|
||||
|
||||
/**
|
||||
* Get a list of the insertion markers that currently exist. Drags have 0, 1,
|
||||
* or 2 insertion markers.
|
||||
* @return {!Array.<!Blockly.BlockSvg>} A possibly empty list of insertion
|
||||
* @return {!Array.<!BlockSvg>} A possibly empty list of insertion
|
||||
* marker blocks.
|
||||
*/
|
||||
Blockly.IBlockDragger.prototype.getInsertionMarkers;
|
||||
IBlockDragger.prototype.getInsertionMarkers;
|
||||
|
||||
exports = IBlockDragger;
|
||||
|
||||
@@ -11,28 +11,32 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IBoundedElement');
|
||||
goog.module('Blockly.IBoundedElement');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.requireType('Blockly.utils.Rect');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Rect = goog.requireType('Blockly.utils.Rect');
|
||||
|
||||
|
||||
/**
|
||||
* A bounded element interface.
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IBoundedElement = function() {};
|
||||
const IBoundedElement = function() {};
|
||||
|
||||
/**
|
||||
* Returns the coordinates of a bounded element describing the dimensions of the
|
||||
* element.
|
||||
* Coordinate system: workspace coordinates.
|
||||
* @return {!Blockly.utils.Rect} Object with coordinates of the bounded element.
|
||||
* @return {!Rect} Object with coordinates of the bounded element.
|
||||
*/
|
||||
Blockly.IBoundedElement.prototype.getBoundingRectangle;
|
||||
IBoundedElement.prototype.getBoundingRectangle;
|
||||
|
||||
/**
|
||||
* Move the element by a relative offset.
|
||||
* @param {number} dx Horizontal offset in workspace units.
|
||||
* @param {number} dy Vertical offset in workspace units.
|
||||
*/
|
||||
Blockly.IBoundedElement.prototype.moveBy;
|
||||
IBoundedElement.prototype.moveBy;
|
||||
|
||||
exports = IBoundedElement;
|
||||
|
||||
@@ -11,35 +11,39 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IBubble');
|
||||
goog.module('Blockly.IBubble');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.IContextMenu');
|
||||
goog.require('Blockly.IDraggable');
|
||||
|
||||
goog.requireType('Blockly.BlockDragSurfaceSvg');
|
||||
goog.requireType('Blockly.utils.Coordinate');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockDragSurfaceSvg = goog.requireType('Blockly.BlockDragSurfaceSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Coordinate = goog.requireType('Blockly.utils.Coordinate');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IContextMenu = goog.require('Blockly.IContextMenu');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDraggable = goog.require('Blockly.IDraggable');
|
||||
|
||||
|
||||
/**
|
||||
* A bubble interface.
|
||||
* @interface
|
||||
* @extends {Blockly.IDraggable}
|
||||
* @extends {Blockly.IContextMenu}
|
||||
* @extends {IDraggable}
|
||||
* @extends {IContextMenu}
|
||||
*/
|
||||
Blockly.IBubble = function() {};
|
||||
const IBubble = function() {};
|
||||
|
||||
/**
|
||||
* Return the coordinates of the top-left corner of this bubble's body relative
|
||||
* to the drawing surface's origin (0,0), in workspace units.
|
||||
* @return {!Blockly.utils.Coordinate} Object with .x and .y properties.
|
||||
* @return {!Coordinate} Object with .x and .y properties.
|
||||
*/
|
||||
Blockly.IBubble.prototype.getRelativeToSurfaceXY;
|
||||
IBubble.prototype.getRelativeToSurfaceXY;
|
||||
|
||||
/**
|
||||
* Return the root node of the bubble's SVG group.
|
||||
* @return {!SVGElement} The root SVG node of the bubble's group.
|
||||
*/
|
||||
Blockly.IBubble.prototype.getSvgRoot;
|
||||
IBubble.prototype.getSvgRoot;
|
||||
|
||||
/**
|
||||
* Set whether auto-layout of this bubble is enabled. The first time a bubble
|
||||
@@ -48,39 +52,41 @@ Blockly.IBubble.prototype.getSvgRoot;
|
||||
* @param {boolean} enable True if auto-layout should be enabled, false
|
||||
* otherwise.
|
||||
*/
|
||||
Blockly.IBubble.prototype.setAutoLayout;
|
||||
IBubble.prototype.setAutoLayout;
|
||||
|
||||
/**
|
||||
* Triggers a move callback if one exists at the end of a drag.
|
||||
* @param {boolean} adding True if adding, false if removing.
|
||||
*/
|
||||
Blockly.IBubble.prototype.setDragging;
|
||||
IBubble.prototype.setDragging;
|
||||
|
||||
/**
|
||||
* Move this bubble during a drag, taking into account whether or not there is
|
||||
* a drag surface.
|
||||
* @param {Blockly.BlockDragSurfaceSvg} dragSurface The surface that carries
|
||||
* @param {?BlockDragSurfaceSvg} dragSurface The surface that carries
|
||||
* rendered items during a drag, or null if no drag surface is in use.
|
||||
* @param {!Blockly.utils.Coordinate} newLoc The location to translate to, in
|
||||
* @param {!Coordinate} newLoc The location to translate to, in
|
||||
* workspace coordinates.
|
||||
*/
|
||||
Blockly.IBubble.prototype.moveDuringDrag;
|
||||
IBubble.prototype.moveDuringDrag;
|
||||
|
||||
/**
|
||||
* Move the bubble to the specified location in workspace coordinates.
|
||||
* @param {number} x The x position to move to.
|
||||
* @param {number} y The y position to move to.
|
||||
*/
|
||||
Blockly.IBubble.prototype.moveTo;
|
||||
IBubble.prototype.moveTo;
|
||||
|
||||
/**
|
||||
* Update the style of this bubble when it is dragged over a delete area.
|
||||
* @param {boolean} enable True if the bubble is about to be deleted, false
|
||||
* otherwise.
|
||||
*/
|
||||
Blockly.IBubble.prototype.setDeleteStyle;
|
||||
IBubble.prototype.setDeleteStyle;
|
||||
|
||||
/**
|
||||
* Dispose of this bubble.
|
||||
*/
|
||||
Blockly.IBubble.prototype.dispose;
|
||||
IBubble.prototype.dispose;
|
||||
|
||||
exports = IBubble;
|
||||
|
||||
50
core/interfaces/i_collapsible_toolbox_item.js
Normal file
50
core/interfaces/i_collapsible_toolbox_item.js
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The interface for a collapsible toolbox item.
|
||||
* @author kozbial@google.com (Monica Kozbial)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.ICollapsibleToolboxItem');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const ISelectableToolboxItem = goog.require('Blockly.ISelectableToolboxItem');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IToolboxItem = goog.requireType('Blockly.IToolboxItem');
|
||||
|
||||
|
||||
/**
|
||||
* Interface for an item in the toolbox that can be collapsed.
|
||||
* @extends {ISelectableToolboxItem}
|
||||
* @interface
|
||||
*/
|
||||
const ICollapsibleToolboxItem = function() {};
|
||||
|
||||
/**
|
||||
* Gets any children toolbox items. (ex. Gets the subcategories)
|
||||
* @return {!Array<!IToolboxItem>} The child toolbox items.
|
||||
*/
|
||||
ICollapsibleToolboxItem.prototype.getChildToolboxItems;
|
||||
|
||||
/**
|
||||
* Whether the toolbox item is expanded to show its child subcategories.
|
||||
* @return {boolean} True if the toolbox item shows its children, false if it
|
||||
* is collapsed.
|
||||
* @public
|
||||
*/
|
||||
ICollapsibleToolboxItem.prototype.isExpanded;
|
||||
|
||||
/**
|
||||
* Toggles whether or not the toolbox item is expanded.
|
||||
* @public
|
||||
*/
|
||||
ICollapsibleToolboxItem.prototype.toggleExpanded;
|
||||
|
||||
exports = ICollapsibleToolboxItem;
|
||||
@@ -12,7 +12,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IComponent');
|
||||
goog.module('Blockly.IComponent');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
|
||||
/**
|
||||
@@ -20,11 +21,13 @@ goog.provide('Blockly.IComponent');
|
||||
* ComponentManager.
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IComponent = function() {};
|
||||
const IComponent = function() {};
|
||||
|
||||
/**
|
||||
* The unique id for this component that is used to register with the
|
||||
* ComponentManager.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.IComponent.id;
|
||||
IComponent.id;
|
||||
|
||||
exports = IComponent;
|
||||
|
||||
@@ -11,23 +11,26 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IConnectionChecker');
|
||||
goog.module('Blockly.IConnectionChecker');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.requireType('Blockly.Connection');
|
||||
goog.requireType('Blockly.RenderedConnection');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Connection = goog.requireType('Blockly.Connection');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const RenderedConnection = goog.requireType('Blockly.RenderedConnection');
|
||||
|
||||
|
||||
/**
|
||||
* Class for connection type checking logic.
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IConnectionChecker = function() {};
|
||||
const IConnectionChecker = function() {};
|
||||
|
||||
/**
|
||||
* Check whether the current connection can connect with the target
|
||||
* connection.
|
||||
* @param {Blockly.Connection} a Connection to check compatibility with.
|
||||
* @param {Blockly.Connection} b Connection to check compatibility with.
|
||||
* @param {Connection} a Connection to check compatibility with.
|
||||
* @param {Connection} b Connection to check compatibility with.
|
||||
* @param {boolean} isDragging True if the connection is being made by dragging
|
||||
* a block.
|
||||
* @param {number=} opt_distance The max allowable distance between the
|
||||
@@ -35,61 +38,63 @@ Blockly.IConnectionChecker = function() {};
|
||||
* @return {boolean} Whether the connection is legal.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IConnectionChecker.prototype.canConnect;
|
||||
IConnectionChecker.prototype.canConnect;
|
||||
|
||||
/**
|
||||
* Checks whether the current connection can connect with the target
|
||||
* connection, and return an error code if there are problems.
|
||||
* @param {Blockly.Connection} a Connection to check compatibility with.
|
||||
* @param {Blockly.Connection} b Connection to check compatibility with.
|
||||
* @param {Connection} a Connection to check compatibility with.
|
||||
* @param {Connection} b Connection to check compatibility with.
|
||||
* @param {boolean} isDragging True if the connection is being made by dragging
|
||||
* a block.
|
||||
* @param {number=} opt_distance The max allowable distance between the
|
||||
* connections for drag checks.
|
||||
* @return {number} Blockly.Connection.CAN_CONNECT if the connection is legal,
|
||||
* @return {number} Connection.CAN_CONNECT if the connection is legal,
|
||||
* an error code otherwise.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IConnectionChecker.prototype.canConnectWithReason;
|
||||
IConnectionChecker.prototype.canConnectWithReason;
|
||||
|
||||
/**
|
||||
* Helper method that translates a connection error code into a string.
|
||||
* @param {number} errorCode The error code.
|
||||
* @param {Blockly.Connection} a One of the two connections being checked.
|
||||
* @param {Blockly.Connection} b The second of the two connections being
|
||||
* @param {Connection} a One of the two connections being checked.
|
||||
* @param {Connection} b The second of the two connections being
|
||||
* checked.
|
||||
* @return {string} A developer-readable error string.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IConnectionChecker.prototype.getErrorMessage;
|
||||
IConnectionChecker.prototype.getErrorMessage;
|
||||
|
||||
/**
|
||||
* Check that connecting the given connections is safe, meaning that it would
|
||||
* not break any of Blockly's basic assumptions (e.g. no self connections).
|
||||
* @param {Blockly.Connection} a The first of the connections to check.
|
||||
* @param {Blockly.Connection} b The second of the connections to check.
|
||||
* @param {Connection} a The first of the connections to check.
|
||||
* @param {Connection} b The second of the connections to check.
|
||||
* @return {number} An enum with the reason this connection is safe or unsafe.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IConnectionChecker.prototype.doSafetyChecks;
|
||||
IConnectionChecker.prototype.doSafetyChecks;
|
||||
|
||||
/**
|
||||
* Check whether this connection is compatible with another connection with
|
||||
* respect to the value type system. E.g. square_root("Hello") is not
|
||||
* compatible.
|
||||
* @param {!Blockly.Connection} a Connection to compare.
|
||||
* @param {!Blockly.Connection} b Connection to compare against.
|
||||
* @param {!Connection} a Connection to compare.
|
||||
* @param {!Connection} b Connection to compare against.
|
||||
* @return {boolean} True if the connections share a type.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IConnectionChecker.prototype.doTypeChecks;
|
||||
IConnectionChecker.prototype.doTypeChecks;
|
||||
|
||||
/**
|
||||
* Check whether this connection can be made by dragging.
|
||||
* @param {!Blockly.RenderedConnection} a Connection to compare.
|
||||
* @param {!Blockly.RenderedConnection} b Connection to compare against.
|
||||
* @param {!RenderedConnection} a Connection to compare.
|
||||
* @param {!RenderedConnection} b Connection to compare against.
|
||||
* @param {number} distance The maximum allowable distance between connections.
|
||||
* @return {boolean} True if the connection is allowed during a drag.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IConnectionChecker.prototype.doDragChecks;
|
||||
IConnectionChecker.prototype.doDragChecks;
|
||||
|
||||
exports = IConnectionChecker;
|
||||
|
||||
@@ -11,16 +11,19 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IContextMenu');
|
||||
goog.module('Blockly.IContextMenu');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
|
||||
/**
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IContextMenu = function() {};
|
||||
const IContextMenu = function() {};
|
||||
|
||||
/**
|
||||
* Show the context menu for this object.
|
||||
* @param {!Event} e Mouse event.
|
||||
*/
|
||||
Blockly.IContextMenu.prototype.showContextMenu;
|
||||
IContextMenu.prototype.showContextMenu;
|
||||
|
||||
exports = IContextMenu;
|
||||
|
||||
@@ -11,30 +11,35 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.ICopyable');
|
||||
goog.module('Blockly.ICopyable');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.requireType('Blockly.ISelectable');
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const ISelectable = goog.requireType('Blockly.ISelectable');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
|
||||
|
||||
/**
|
||||
* @extends {Blockly.ISelectable}
|
||||
* @extends {ISelectable}
|
||||
* @interface
|
||||
*/
|
||||
Blockly.ICopyable = function() {};
|
||||
const ICopyable = function() {};
|
||||
|
||||
/**
|
||||
* Encode for copying.
|
||||
* @return {?Blockly.ICopyable.CopyData} Copy metadata.
|
||||
* @return {?ICopyable.CopyData} Copy metadata.
|
||||
*/
|
||||
Blockly.ICopyable.prototype.toCopyData;
|
||||
ICopyable.prototype.toCopyData;
|
||||
|
||||
/**
|
||||
* Copy Metadata.
|
||||
* @typedef {{
|
||||
* xml:!Element,
|
||||
* source:Blockly.WorkspaceSvg,
|
||||
* source:WorkspaceSvg,
|
||||
* typeCounts:?Object
|
||||
* }}
|
||||
*/
|
||||
Blockly.ICopyable.CopyData;
|
||||
ICopyable.CopyData;
|
||||
|
||||
exports = ICopyable;
|
||||
|
||||
@@ -11,17 +11,20 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IDeletable');
|
||||
goog.module('Blockly.IDeletable');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
|
||||
/**
|
||||
* The interface for an object that can be deleted.
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IDeletable = function() {};
|
||||
const IDeletable = function() {};
|
||||
|
||||
/**
|
||||
* Get whether this object is deletable or not.
|
||||
* @return {boolean} True if deletable.
|
||||
*/
|
||||
Blockly.IDeletable.prototype.isDeletable;
|
||||
IDeletable.prototype.isDeletable;
|
||||
|
||||
exports = IDeletable;
|
||||
|
||||
@@ -12,31 +12,35 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IDeleteArea');
|
||||
goog.module('Blockly.IDeleteArea');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.IDragTarget');
|
||||
|
||||
goog.requireType('Blockly.IDraggable');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDraggable = goog.requireType('Blockly.IDraggable');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDragTarget = goog.require('Blockly.IDragTarget');
|
||||
|
||||
|
||||
/**
|
||||
* Interface for a component that can delete a block or bubble that is dropped
|
||||
* on top of it.
|
||||
* @extends {Blockly.IDragTarget}
|
||||
* @extends {IDragTarget}
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IDeleteArea = function() {};
|
||||
const IDeleteArea = function() {};
|
||||
|
||||
/**
|
||||
* Returns whether the provided block or bubble would be deleted if dropped on
|
||||
* this area.
|
||||
* This method should check if the element is deletable and is always called
|
||||
* before onDragEnter/onDragOver/onDragExit.
|
||||
* @param {!Blockly.IDraggable} element The block or bubble currently being
|
||||
* @param {!IDraggable} element The block or bubble currently being
|
||||
* dragged.
|
||||
* @param {boolean} couldConnect Whether the element could could connect to
|
||||
* another.
|
||||
* @return {boolean} Whether the element provided would be deleted if dropped on
|
||||
* this area.
|
||||
*/
|
||||
Blockly.IDeleteArea.prototype.wouldDelete;
|
||||
IDeleteArea.prototype.wouldDelete;
|
||||
|
||||
exports = IDeleteArea;
|
||||
|
||||
@@ -12,67 +12,73 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IDragTarget');
|
||||
goog.module('Blockly.IDragTarget');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.IComponent');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IComponent = goog.require('Blockly.IComponent');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDraggable = goog.requireType('Blockly.IDraggable');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Rect = goog.requireType('Blockly.utils.Rect');
|
||||
|
||||
goog.requireType('Blockly.IDraggable');
|
||||
goog.requireType('Blockly.utils.Rect');
|
||||
|
||||
/**
|
||||
* Interface for a component with custom behaviour when a block or bubble is
|
||||
* dragged over or dropped on top of it.
|
||||
* @extends {Blockly.IComponent}
|
||||
* @extends {IComponent}
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IDragTarget = function() {};
|
||||
const IDragTarget = function() {};
|
||||
|
||||
/**
|
||||
* Returns the bounding rectangle of the drag target area in pixel units
|
||||
* relative to viewport.
|
||||
* @return {?Blockly.utils.Rect} The component's bounding box. Null if drag
|
||||
* @return {?Rect} The component's bounding box. Null if drag
|
||||
* target area should be ignored.
|
||||
*/
|
||||
Blockly.IDragTarget.prototype.getClientRect;
|
||||
IDragTarget.prototype.getClientRect;
|
||||
|
||||
/**
|
||||
* Handles when a cursor with a block or bubble enters this drag target.
|
||||
* @param {!Blockly.IDraggable} dragElement The block or bubble currently being
|
||||
* @param {!IDraggable} dragElement The block or bubble currently being
|
||||
* dragged.
|
||||
*/
|
||||
Blockly.IDragTarget.prototype.onDragEnter;
|
||||
IDragTarget.prototype.onDragEnter;
|
||||
|
||||
/**
|
||||
* Handles when a cursor with a block or bubble is dragged over this drag
|
||||
* target.
|
||||
* @param {!Blockly.IDraggable} dragElement The block or bubble currently being
|
||||
* @param {!IDraggable} dragElement The block or bubble currently being
|
||||
* dragged.
|
||||
*/
|
||||
Blockly.IDragTarget.prototype.onDragOver;
|
||||
IDragTarget.prototype.onDragOver;
|
||||
|
||||
|
||||
/**
|
||||
* Handles when a cursor with a block or bubble exits this drag target.
|
||||
* @param {!Blockly.IDraggable} dragElement The block or bubble currently being
|
||||
* @param {!IDraggable} dragElement The block or bubble currently being
|
||||
* dragged.
|
||||
*/
|
||||
Blockly.IDragTarget.prototype.onDragExit;
|
||||
IDragTarget.prototype.onDragExit;
|
||||
|
||||
/**
|
||||
* Handles when a block or bubble is dropped on this component.
|
||||
* Should not handle delete here.
|
||||
* @param {!Blockly.IDraggable} dragElement The block or bubble currently being
|
||||
* @param {!IDraggable} dragElement The block or bubble currently being
|
||||
* dragged.
|
||||
*/
|
||||
Blockly.IDragTarget.prototype.onDrop;
|
||||
IDragTarget.prototype.onDrop;
|
||||
|
||||
/**
|
||||
* Returns whether the provided block or bubble should not be moved after being
|
||||
* dropped on this component. If true, the element will return to where it was
|
||||
* when the drag started.
|
||||
* @param {!Blockly.IDraggable} dragElement The block or bubble currently being
|
||||
* @param {!IDraggable} dragElement The block or bubble currently being
|
||||
* dragged.
|
||||
* @return {boolean} Whether the block or bubble provided should be returned to
|
||||
* drag start.
|
||||
*/
|
||||
Blockly.IDragTarget.prototype.shouldPreventMove;
|
||||
IDragTarget.prototype.shouldPreventMove;
|
||||
|
||||
exports = IDragTarget;
|
||||
|
||||
@@ -11,14 +11,18 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IDraggable');
|
||||
goog.module('Blockly.IDraggable');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.IDeletable');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDeletable = goog.require('Blockly.IDeletable');
|
||||
|
||||
|
||||
/**
|
||||
* The interface for an object that can be dragged.
|
||||
* @extends {Blockly.IDeletable}
|
||||
* @extends {IDeletable}
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IDraggable = function() {};
|
||||
const IDraggable = function() {};
|
||||
|
||||
exports = IDraggable;
|
||||
|
||||
@@ -11,179 +11,188 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IFlyout');
|
||||
goog.module('Blockly.IFlyout');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.IRegistrable');
|
||||
goog.requireType('Blockly.utils.Coordinate');
|
||||
goog.requireType('Blockly.utils.Svg');
|
||||
goog.requireType('Blockly.utils.toolbox');
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Coordinate = goog.requireType('Blockly.utils.Coordinate');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IRegistrable = goog.require('Blockly.IRegistrable');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Svg = goog.requireType('Blockly.utils.Svg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const {FlyoutDefinition} = goog.requireType('Blockly.utils.toolbox');
|
||||
|
||||
|
||||
/**
|
||||
* Interface for a flyout.
|
||||
* @extends {Blockly.IRegistrable}
|
||||
* @extends {IRegistrable}
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IFlyout = function() {};
|
||||
const IFlyout = function() {};
|
||||
|
||||
/**
|
||||
* Whether the flyout is laid out horizontally or not.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.IFlyout.prototype.horizontalLayout;
|
||||
IFlyout.prototype.horizontalLayout;
|
||||
|
||||
/**
|
||||
* Is RTL vs LTR.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.IFlyout.prototype.RTL;
|
||||
IFlyout.prototype.RTL;
|
||||
|
||||
/**
|
||||
* The target workspace
|
||||
* @type {?Blockly.WorkspaceSvg}
|
||||
* @type {?WorkspaceSvg}
|
||||
*/
|
||||
Blockly.IFlyout.prototype.targetWorkspace;
|
||||
IFlyout.prototype.targetWorkspace;
|
||||
|
||||
/**
|
||||
* Margin around the edges of the blocks in the flyout.
|
||||
* @type {number}
|
||||
* @const
|
||||
*/
|
||||
Blockly.IFlyout.prototype.MARGIN;
|
||||
IFlyout.prototype.MARGIN;
|
||||
|
||||
/**
|
||||
* Does the flyout automatically close when a block is created?
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.IFlyout.prototype.autoClose;
|
||||
IFlyout.prototype.autoClose;
|
||||
|
||||
/**
|
||||
* Corner radius of the flyout background.
|
||||
* @type {number}
|
||||
* @const
|
||||
*/
|
||||
Blockly.IFlyout.prototype.CORNER_RADIUS;
|
||||
IFlyout.prototype.CORNER_RADIUS;
|
||||
|
||||
/**
|
||||
* Creates the flyout's DOM. Only needs to be called once. The flyout can
|
||||
* either exist as its own svg element or be a g element nested inside a
|
||||
* separate svg element.
|
||||
* @param {string|
|
||||
* !Blockly.utils.Svg<!SVGSVGElement>|
|
||||
* !Blockly.utils.Svg<!SVGGElement>} tagName The type of tag to
|
||||
* !Svg<!SVGSVGElement>|
|
||||
* !Svg<!SVGGElement>} tagName The type of tag to
|
||||
* put the flyout in. This should be <svg> or <g>.
|
||||
* @return {!SVGElement} The flyout's SVG group.
|
||||
*/
|
||||
Blockly.IFlyout.prototype.createDom;
|
||||
IFlyout.prototype.createDom;
|
||||
|
||||
/**
|
||||
* Initializes the flyout.
|
||||
* @param {!Blockly.WorkspaceSvg} targetWorkspace The workspace in which to
|
||||
* @param {!WorkspaceSvg} targetWorkspace The workspace in which to
|
||||
* create new blocks.
|
||||
*/
|
||||
Blockly.IFlyout.prototype.init;
|
||||
IFlyout.prototype.init;
|
||||
|
||||
/**
|
||||
* Dispose of this flyout.
|
||||
* Unlink from all DOM elements to prevent memory leaks.
|
||||
*/
|
||||
Blockly.IFlyout.prototype.dispose;
|
||||
IFlyout.prototype.dispose;
|
||||
|
||||
/**
|
||||
* Get the width of the flyout.
|
||||
* @return {number} The width of the flyout.
|
||||
*/
|
||||
Blockly.IFlyout.prototype.getWidth;
|
||||
IFlyout.prototype.getWidth;
|
||||
|
||||
/**
|
||||
* Get the height of the flyout.
|
||||
* @return {number} The width of the flyout.
|
||||
*/
|
||||
Blockly.IFlyout.prototype.getHeight;
|
||||
IFlyout.prototype.getHeight;
|
||||
|
||||
/**
|
||||
* Get the workspace inside the flyout.
|
||||
* @return {!Blockly.WorkspaceSvg} The workspace inside the flyout.
|
||||
* @return {!WorkspaceSvg} The workspace inside the flyout.
|
||||
*/
|
||||
Blockly.IFlyout.prototype.getWorkspace;
|
||||
IFlyout.prototype.getWorkspace;
|
||||
|
||||
/**
|
||||
* Is the flyout visible?
|
||||
* @return {boolean} True if visible.
|
||||
*/
|
||||
Blockly.IFlyout.prototype.isVisible;
|
||||
IFlyout.prototype.isVisible;
|
||||
|
||||
/**
|
||||
* Set whether the flyout is visible. A value of true does not necessarily mean
|
||||
* that the flyout is shown. It could be hidden because its container is hidden.
|
||||
* @param {boolean} visible True if visible.
|
||||
*/
|
||||
Blockly.IFlyout.prototype.setVisible;
|
||||
IFlyout.prototype.setVisible;
|
||||
|
||||
/**
|
||||
* Set whether this flyout's container is visible.
|
||||
* @param {boolean} visible Whether the container is visible.
|
||||
*/
|
||||
Blockly.IFlyout.prototype.setContainerVisible;
|
||||
IFlyout.prototype.setContainerVisible;
|
||||
|
||||
/**
|
||||
* Hide and empty the flyout.
|
||||
*/
|
||||
Blockly.IFlyout.prototype.hide;
|
||||
IFlyout.prototype.hide;
|
||||
|
||||
/**
|
||||
* Show and populate the flyout.
|
||||
* @param {!Blockly.utils.toolbox.FlyoutDefinition|string} flyoutDef Contents to
|
||||
* @param {!FlyoutDefinition|string} flyoutDef Contents to
|
||||
* display in the flyout. This is either an array of Nodes, a NodeList, a
|
||||
* toolbox definition, or a string with the name of the dynamic category.
|
||||
*/
|
||||
Blockly.IFlyout.prototype.show;
|
||||
IFlyout.prototype.show;
|
||||
|
||||
/**
|
||||
* Create a copy of this block on the workspace.
|
||||
* @param {!Blockly.BlockSvg} originalBlock The block to copy from the flyout.
|
||||
* @return {!Blockly.BlockSvg} The newly created block.
|
||||
* @param {!BlockSvg} originalBlock The block to copy from the flyout.
|
||||
* @return {!BlockSvg} The newly created block.
|
||||
* @throws {Error} if something went wrong with deserialization.
|
||||
*/
|
||||
Blockly.IFlyout.prototype.createBlock;
|
||||
IFlyout.prototype.createBlock;
|
||||
|
||||
/**
|
||||
* Reflow blocks and their mats.
|
||||
*/
|
||||
Blockly.IFlyout.prototype.reflow;
|
||||
IFlyout.prototype.reflow;
|
||||
|
||||
/**
|
||||
* @return {boolean} True if this flyout may be scrolled with a scrollbar or by
|
||||
* dragging.
|
||||
*/
|
||||
Blockly.IFlyout.prototype.isScrollable;
|
||||
IFlyout.prototype.isScrollable;
|
||||
|
||||
/**
|
||||
* Calculates the x coordinate for the flyout position.
|
||||
* @return {number} X coordinate.
|
||||
*/
|
||||
Blockly.IFlyout.prototype.getX;
|
||||
IFlyout.prototype.getX;
|
||||
|
||||
/**
|
||||
* Calculates the y coordinate for the flyout position.
|
||||
* @return {number} Y coordinate.
|
||||
*/
|
||||
Blockly.IFlyout.prototype.getY;
|
||||
IFlyout.prototype.getY;
|
||||
|
||||
/**
|
||||
* Position the flyout.
|
||||
* @return {void}
|
||||
*/
|
||||
Blockly.IFlyout.prototype.position;
|
||||
IFlyout.prototype.position;
|
||||
|
||||
/**
|
||||
* Determine if a drag delta is toward the workspace, based on the position
|
||||
* and orientation of the flyout. This is used in determineDragIntention_ to
|
||||
* determine if a new block should be created or if the flyout should scroll.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the position at mouse down, in pixel units.
|
||||
* @return {boolean} True if the drag is toward the workspace.
|
||||
*/
|
||||
Blockly.IFlyout.prototype.isDragTowardWorkspace;
|
||||
IFlyout.prototype.isDragTowardWorkspace;
|
||||
|
||||
exports = IFlyout;
|
||||
|
||||
35
core/interfaces/i_keyboard_accessible.js
Normal file
35
core/interfaces/i_keyboard_accessible.js
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The interface for objects that handle keyboard shortcuts.
|
||||
* @author samelh@google.com (Sam El-Husseini)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.IKeyboardAccessible');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const ShortcutRegistry = goog.requireType('Blockly.ShortcutRegistry');
|
||||
|
||||
|
||||
/**
|
||||
* An interface for an object that handles keyboard shortcuts.
|
||||
* @interface
|
||||
*/
|
||||
const IKeyboardAccessible = function() {};
|
||||
|
||||
/**
|
||||
* Handles the given keyboard shortcut.
|
||||
* @param {!ShortcutRegistry.KeyboardShortcut} shortcut The shortcut to be
|
||||
* handled.
|
||||
* @return {boolean} True if the shortcut has been handled, false otherwise.
|
||||
*/
|
||||
IKeyboardAccessible.prototype.onShortcut;
|
||||
|
||||
exports = IKeyboardAccessible;
|
||||
@@ -11,92 +11,96 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IMetricsManager');
|
||||
goog.module('Blockly.IMetricsManager');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.requireType('Blockly.MetricsManager');
|
||||
goog.requireType('Blockly.utils.Metrics');
|
||||
goog.requireType('Blockly.utils.Size');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Metrics = goog.requireType('Blockly.utils.Metrics');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Size = goog.requireType('Blockly.utils.Size');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const {AbsoluteMetrics, ContainerRegion, ToolboxMetrics} = goog.requireType('Blockly.MetricsManager');
|
||||
|
||||
|
||||
/**
|
||||
* Interface for a metrics manager.
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IMetricsManager = function() {};
|
||||
const IMetricsManager = function() {};
|
||||
|
||||
/**
|
||||
* Returns whether the scroll area has fixed edges.
|
||||
* @return {boolean} Whether the scroll area has fixed edges.
|
||||
* @package
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.hasFixedEdges;
|
||||
IMetricsManager.prototype.hasFixedEdges;
|
||||
|
||||
/**
|
||||
* Returns the metrics for the scroll area of the workspace.
|
||||
* @param {boolean=} opt_getWorkspaceCoordinates True to get the scroll metrics
|
||||
* in workspace coordinates, false to get them in pixel coordinates.
|
||||
* @param {!Blockly.MetricsManager.ContainerRegion=} opt_viewMetrics The view
|
||||
* @param {!ContainerRegion=} opt_viewMetrics The view
|
||||
* metrics if they have been previously computed. Passing in null may cause
|
||||
* the view metrics to be computed again, if it is needed.
|
||||
* @param {!Blockly.MetricsManager.ContainerRegion=} opt_contentMetrics The
|
||||
* @param {!ContainerRegion=} opt_contentMetrics The
|
||||
* content metrics if they have been previously computed. Passing in null
|
||||
* may cause the content metrics to be computed again, if it is needed.
|
||||
* @return {!Blockly.MetricsManager.ContainerRegion} The metrics for the scroll
|
||||
* @return {!ContainerRegion} The metrics for the scroll
|
||||
* container
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.getScrollMetrics;
|
||||
IMetricsManager.prototype.getScrollMetrics;
|
||||
|
||||
/**
|
||||
* Gets the width and the height of the flyout on the workspace in pixel
|
||||
* coordinates. Returns 0 for the width and height if the workspace has a
|
||||
* category toolbox instead of a simple toolbox.
|
||||
* @param {boolean=} opt_own Whether to only return the workspace's own flyout.
|
||||
* @return {!Blockly.MetricsManager.ToolboxMetrics} The width and height of the
|
||||
* @return {!ToolboxMetrics} The width and height of the
|
||||
* flyout.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.getFlyoutMetrics;
|
||||
IMetricsManager.prototype.getFlyoutMetrics;
|
||||
|
||||
/**
|
||||
* Gets the width, height and position of the toolbox on the workspace in pixel
|
||||
* coordinates. Returns 0 for the width and height if the workspace has a simple
|
||||
* toolbox instead of a category toolbox. To get the width and height of a
|
||||
* simple toolbox @see {@link getFlyoutMetrics}.
|
||||
* @return {!Blockly.MetricsManager.ToolboxMetrics} The object with the width,
|
||||
* @return {!ToolboxMetrics} The object with the width,
|
||||
* height and position of the toolbox.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.getToolboxMetrics;
|
||||
IMetricsManager.prototype.getToolboxMetrics;
|
||||
|
||||
/**
|
||||
* Gets the width and height of the workspace's parent SVG element in pixel
|
||||
* coordinates. This area includes the toolbox and the visible workspace area.
|
||||
* @return {!Blockly.utils.Size} The width and height of the workspace's parent
|
||||
* @return {!Size} The width and height of the workspace's parent
|
||||
* SVG element.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.getSvgMetrics;
|
||||
IMetricsManager.prototype.getSvgMetrics;
|
||||
|
||||
/**
|
||||
* Gets the absolute left and absolute top in pixel coordinates.
|
||||
* This is where the visible workspace starts in relation to the SVG container.
|
||||
* @return {!Blockly.MetricsManager.AbsoluteMetrics} The absolute metrics for
|
||||
* @return {!AbsoluteMetrics} The absolute metrics for
|
||||
* the workspace.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.getAbsoluteMetrics;
|
||||
IMetricsManager.prototype.getAbsoluteMetrics;
|
||||
|
||||
/**
|
||||
* Gets the metrics for the visible workspace in either pixel or workspace
|
||||
* coordinates. The visible workspace does not include the toolbox or flyout.
|
||||
* @param {boolean=} opt_getWorkspaceCoordinates True to get the view metrics in
|
||||
* workspace coordinates, false to get them in pixel coordinates.
|
||||
* @return {!Blockly.MetricsManager.ContainerRegion} The width, height, top and
|
||||
* @return {!ContainerRegion} The width, height, top and
|
||||
* left of the viewport in either workspace coordinates or pixel
|
||||
* coordinates.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.getViewMetrics;
|
||||
IMetricsManager.prototype.getViewMetrics;
|
||||
|
||||
/**
|
||||
* Gets content metrics in either pixel or workspace coordinates.
|
||||
@@ -104,11 +108,11 @@ Blockly.IMetricsManager.prototype.getViewMetrics;
|
||||
* workspace (workspace comments and blocks).
|
||||
* @param {boolean=} opt_getWorkspaceCoordinates True to get the content metrics
|
||||
* in workspace coordinates, false to get them in pixel coordinates.
|
||||
* @return {!Blockly.MetricsManager.ContainerRegion} The
|
||||
* @return {!ContainerRegion} The
|
||||
* metrics for the content container.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.getContentMetrics;
|
||||
IMetricsManager.prototype.getContentMetrics;
|
||||
|
||||
/**
|
||||
* Returns an object with all the metrics required to size scrollbars for a
|
||||
@@ -138,8 +142,10 @@ Blockly.IMetricsManager.prototype.getContentMetrics;
|
||||
* .flyoutHeight: Height of the flyout if it is always open. Otherwise zero.
|
||||
* .toolboxPosition: Top, bottom, left or right. Use TOOLBOX_AT constants to
|
||||
* compare.
|
||||
* @return {!Blockly.utils.Metrics} Contains size and position metrics of a top
|
||||
* @return {!Metrics} Contains size and position metrics of a top
|
||||
* level workspace.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.getMetrics;
|
||||
IMetricsManager.prototype.getMetrics;
|
||||
|
||||
exports = IMetricsManager;
|
||||
|
||||
@@ -11,17 +11,20 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IMovable');
|
||||
goog.module('Blockly.IMovable');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
|
||||
/**
|
||||
* The interface for an object that is movable.
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IMovable = function() {};
|
||||
const IMovable = function() {};
|
||||
|
||||
/**
|
||||
* Get whether this is movable or not.
|
||||
* @return {boolean} True if movable.
|
||||
*/
|
||||
Blockly.IMovable.prototype.isMovable;
|
||||
IMovable.prototype.isMovable;
|
||||
|
||||
exports = IMovable;
|
||||
|
||||
@@ -11,33 +11,38 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IPositionable');
|
||||
goog.module('Blockly.IPositionable');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.IComponent');
|
||||
|
||||
goog.requireType('Blockly.MetricsManager');
|
||||
goog.requireType('Blockly.utils.Rect');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IComponent = goog.require('Blockly.IComponent');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Rect = goog.requireType('Blockly.utils.Rect');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const {UiMetrics} = goog.requireType('Blockly.MetricsManager');
|
||||
|
||||
|
||||
/**
|
||||
* Interface for a component that is positioned on top of the workspace.
|
||||
* @extends {Blockly.IComponent}
|
||||
* @extends {IComponent}
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IPositionable = function() {};
|
||||
const IPositionable = function() {};
|
||||
|
||||
/**
|
||||
* Positions the element. Called when the window is resized.
|
||||
* @param {!Blockly.MetricsManager.UiMetrics} metrics The workspace metrics.
|
||||
* @param {!Array<!Blockly.utils.Rect>} savedPositions List of rectangles that
|
||||
* @param {!UiMetrics} metrics The workspace metrics.
|
||||
* @param {!Array<!Rect>} savedPositions List of rectangles that
|
||||
* are already on the workspace.
|
||||
*/
|
||||
Blockly.IPositionable.prototype.position;
|
||||
IPositionable.prototype.position;
|
||||
|
||||
/**
|
||||
* Returns the bounding rectangle of the UI element in pixel units relative to
|
||||
* the Blockly injection div.
|
||||
* @return {?Blockly.utils.Rect} The UI elements’s bounding box. Null if
|
||||
* @return {?Rect} The UI elements’s bounding box. Null if
|
||||
* bounding box should be ignored by other UI elements.
|
||||
*/
|
||||
Blockly.IPositionable.prototype.getBoundingRectangle;
|
||||
IPositionable.prototype.getBoundingRectangle;
|
||||
|
||||
exports = IPositionable;
|
||||
|
||||
@@ -12,11 +12,14 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IRegistrable');
|
||||
goog.module('Blockly.IRegistrable');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
|
||||
/**
|
||||
* The interface for a Blockly component that can be registered.
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IRegistrable = function() {};
|
||||
const IRegistrable = function() {};
|
||||
|
||||
exports = IRegistrable;
|
||||
|
||||
@@ -11,21 +11,26 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IRegistrableField');
|
||||
goog.module('Blockly.IRegistrableField');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Field = goog.requireType('Blockly.Field');
|
||||
|
||||
goog.requireType('Blockly.Field');
|
||||
|
||||
/**
|
||||
* A registrable field.
|
||||
* Note: We are not using an interface here as we are interested in defining the
|
||||
* static methods of a field rather than the instance methods.
|
||||
* @typedef {{
|
||||
* fromJson:Blockly.IRegistrableField.fromJson
|
||||
* fromJson:IRegistrableField.fromJson
|
||||
* }}
|
||||
*/
|
||||
Blockly.IRegistrableField;
|
||||
let IRegistrableField;
|
||||
|
||||
/**
|
||||
* @typedef {function(!Object): Blockly.Field}
|
||||
* @typedef {function(!Object): Field}
|
||||
*/
|
||||
Blockly.IRegistrableField.fromJson;
|
||||
IRegistrableField.fromJson;
|
||||
|
||||
exports = IRegistrableField;
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.ISelectable');
|
||||
goog.module('Blockly.ISelectable');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.requireType('Blockly.IDeletable');
|
||||
goog.requireType('Blockly.IMovable');
|
||||
@@ -23,21 +24,23 @@ goog.requireType('Blockly.IMovable');
|
||||
* @extends {Blockly.IMovable}
|
||||
* @interface
|
||||
*/
|
||||
Blockly.ISelectable = function() {};
|
||||
const ISelectable = function() {};
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.ISelectable.prototype.id;
|
||||
ISelectable.prototype.id;
|
||||
|
||||
/**
|
||||
* Select this. Highlight it visually.
|
||||
* @return {void}
|
||||
*/
|
||||
Blockly.ISelectable.prototype.select;
|
||||
ISelectable.prototype.select;
|
||||
|
||||
/**
|
||||
* Unselect this. Unhighlight it visually.
|
||||
* @return {void}
|
||||
*/
|
||||
Blockly.ISelectable.prototype.unselect;
|
||||
ISelectable.prototype.unselect;
|
||||
|
||||
exports = ISelectable;
|
||||
|
||||
70
core/interfaces/i_selectable_toolbox_item.js
Normal file
70
core/interfaces/i_selectable_toolbox_item.js
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The interface for a selectable toolbox item.
|
||||
* @author aschmiedt@google.com (Abby Schmiedt)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.ISelectableToolboxItem');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IToolboxItem = goog.require('Blockly.IToolboxItem');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const {FlyoutItemInfoArray} = goog.requireType('Blockly.utils.toolbox');
|
||||
|
||||
|
||||
/**
|
||||
* Interface for an item in the toolbox that can be selected.
|
||||
* @extends {IToolboxItem}
|
||||
* @interface
|
||||
*/
|
||||
const ISelectableToolboxItem = function() {};
|
||||
|
||||
/**
|
||||
* Gets the name of the toolbox item. Used for emitting events.
|
||||
* @return {string} The name of the toolbox item.
|
||||
* @public
|
||||
*/
|
||||
ISelectableToolboxItem.prototype.getName;
|
||||
|
||||
/**
|
||||
* Gets the contents of the toolbox item. These are items that are meant to be
|
||||
* displayed in the flyout.
|
||||
* @return {!FlyoutItemInfoArray|string} The definition
|
||||
* of items to be displayed in the flyout.
|
||||
* @public
|
||||
*/
|
||||
ISelectableToolboxItem.prototype.getContents;
|
||||
|
||||
/**
|
||||
* Sets the current toolbox item as selected.
|
||||
* @param {boolean} _isSelected True if this category is selected, false
|
||||
* otherwise.
|
||||
* @public
|
||||
*/
|
||||
ISelectableToolboxItem.prototype.setSelected;
|
||||
|
||||
/**
|
||||
* Gets the HTML element that is clickable.
|
||||
* The parent toolbox element receives clicks. The parent toolbox will add an ID
|
||||
* to this element so it can pass the onClick event to the correct toolboxItem.
|
||||
* @return {!Element} The HTML element that receives clicks.
|
||||
* @public
|
||||
*/
|
||||
ISelectableToolboxItem.prototype.getClickTarget;
|
||||
|
||||
/**
|
||||
* Handles when the toolbox item is clicked.
|
||||
* @param {!Event} _e Click event to handle.
|
||||
* @public
|
||||
*/
|
||||
ISelectableToolboxItem.prototype.onClick;
|
||||
|
||||
exports = ISelectableToolboxItem;
|
||||
@@ -11,23 +11,26 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IStyleable');
|
||||
goog.module('Blockly.IStyleable');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
|
||||
/**
|
||||
* Interface for an object that a style can be added to.
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IStyleable = function() {};
|
||||
const IStyleable = function() {};
|
||||
|
||||
/**
|
||||
* Adds a style on the toolbox. Usually used to change the cursor.
|
||||
* @param {string} style The name of the class to add.
|
||||
*/
|
||||
Blockly.IStyleable.prototype.addStyle;
|
||||
IStyleable.prototype.addStyle;
|
||||
|
||||
/**
|
||||
* Removes a style from the toolbox. Usually used to change the cursor.
|
||||
* @param {string} style The name of the class to remove.
|
||||
*/
|
||||
Blockly.IStyleable.prototype.removeStyle;
|
||||
IStyleable.prototype.removeStyle;
|
||||
|
||||
exports = IStyleable;
|
||||
|
||||
@@ -11,90 +11,96 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IToolbox');
|
||||
goog.module('Blockly.IToolbox');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.requireType('Blockly.IFlyout');
|
||||
goog.requireType('Blockly.IRegistrable');
|
||||
goog.requireType('Blockly.IToolboxItem');
|
||||
goog.requireType('Blockly.utils.toolbox');
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IFlyout = goog.requireType('Blockly.IFlyout');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IRegistrable = goog.require('Blockly.IRegistrable');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IToolboxItem = goog.requireType('Blockly.IToolboxItem');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const {ToolboxInfo} = goog.requireType('Blockly.utils.toolbox');
|
||||
|
||||
|
||||
/**
|
||||
* Interface for a toolbox.
|
||||
* @extends {Blockly.IRegistrable}
|
||||
* @extends {IRegistrable}
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IToolbox = function() {};
|
||||
const IToolbox = function() {};
|
||||
|
||||
/**
|
||||
* Initializes the toolbox.
|
||||
* @return {void}
|
||||
*/
|
||||
Blockly.IToolbox.prototype.init;
|
||||
IToolbox.prototype.init;
|
||||
|
||||
/**
|
||||
* Fills the toolbox with new toolbox items and removes any old contents.
|
||||
* @param {!Blockly.utils.toolbox.ToolboxInfo} toolboxDef Object holding information
|
||||
* @param {!ToolboxInfo} toolboxDef Object holding information
|
||||
* for creating a toolbox.
|
||||
*/
|
||||
Blockly.IToolbox.prototype.render;
|
||||
IToolbox.prototype.render;
|
||||
|
||||
/**
|
||||
* Gets the width of the toolbox.
|
||||
* @return {number} The width of the toolbox.
|
||||
*/
|
||||
Blockly.IToolbox.prototype.getWidth;
|
||||
IToolbox.prototype.getWidth;
|
||||
|
||||
/**
|
||||
* Gets the height of the toolbox.
|
||||
* @return {number} The width of the toolbox.
|
||||
*/
|
||||
Blockly.IToolbox.prototype.getHeight;
|
||||
IToolbox.prototype.getHeight;
|
||||
|
||||
/**
|
||||
* Gets the toolbox flyout.
|
||||
* @return {?Blockly.IFlyout} The toolbox flyout.
|
||||
* @return {?IFlyout} The toolbox flyout.
|
||||
*/
|
||||
Blockly.IToolbox.prototype.getFlyout;
|
||||
IToolbox.prototype.getFlyout;
|
||||
|
||||
/**
|
||||
* Gets the workspace for the toolbox.
|
||||
* @return {!Blockly.WorkspaceSvg} The parent workspace for the toolbox.
|
||||
* @return {!WorkspaceSvg} The parent workspace for the toolbox.
|
||||
*/
|
||||
Blockly.IToolbox.prototype.getWorkspace;
|
||||
IToolbox.prototype.getWorkspace;
|
||||
|
||||
/**
|
||||
* Gets whether or not the toolbox is horizontal.
|
||||
* @return {boolean} True if the toolbox is horizontal, false if the toolbox is
|
||||
* vertical.
|
||||
*/
|
||||
Blockly.IToolbox.prototype.isHorizontal;
|
||||
IToolbox.prototype.isHorizontal;
|
||||
|
||||
/**
|
||||
* Positions the toolbox based on whether it is a horizontal toolbox and whether
|
||||
* the workspace is in rtl.
|
||||
* @return {void}
|
||||
*/
|
||||
Blockly.IToolbox.prototype.position;
|
||||
IToolbox.prototype.position;
|
||||
|
||||
/**
|
||||
* Handles resizing the toolbox when a toolbox item resizes.
|
||||
* @return {void}
|
||||
*/
|
||||
Blockly.IToolbox.prototype.handleToolboxItemResize;
|
||||
IToolbox.prototype.handleToolboxItemResize;
|
||||
|
||||
/**
|
||||
* Unhighlights any previously selected item.
|
||||
* @return {void}
|
||||
*/
|
||||
Blockly.IToolbox.prototype.clearSelection;
|
||||
IToolbox.prototype.clearSelection;
|
||||
|
||||
/**
|
||||
* Updates the category colours and background colour of selected categories.
|
||||
* @return {void}
|
||||
*/
|
||||
Blockly.IToolbox.prototype.refreshTheme;
|
||||
IToolbox.prototype.refreshTheme;
|
||||
|
||||
/**
|
||||
* Updates the flyout's content without closing it. Should be used in response
|
||||
@@ -102,30 +108,32 @@ Blockly.IToolbox.prototype.refreshTheme;
|
||||
* procedures.
|
||||
* @return {void}
|
||||
*/
|
||||
Blockly.IToolbox.prototype.refreshSelection;
|
||||
IToolbox.prototype.refreshSelection;
|
||||
|
||||
/**
|
||||
* Sets the visibility of the toolbox.
|
||||
* @param {boolean} isVisible True if toolbox should be visible.
|
||||
*/
|
||||
Blockly.IToolbox.prototype.setVisible;
|
||||
IToolbox.prototype.setVisible;
|
||||
|
||||
/**
|
||||
* Selects the toolbox item by it's position in the list of toolbox items.
|
||||
* @param {number} position The position of the item to select.
|
||||
* @return {void}
|
||||
*/
|
||||
Blockly.IToolbox.prototype.selectItemByPosition;
|
||||
IToolbox.prototype.selectItemByPosition;
|
||||
|
||||
/**
|
||||
* Gets the selected item.
|
||||
* @return {?Blockly.IToolboxItem} The selected item, or null if no item is
|
||||
* @return {?IToolboxItem} The selected item, or null if no item is
|
||||
* currently selected.
|
||||
*/
|
||||
Blockly.IToolbox.prototype.getSelectedItem;
|
||||
IToolbox.prototype.getSelectedItem;
|
||||
|
||||
/**
|
||||
* Disposes of this toolbox.
|
||||
* @return {void}
|
||||
*/
|
||||
Blockly.IToolbox.prototype.dispose;
|
||||
IToolbox.prototype.dispose;
|
||||
|
||||
exports = IToolbox;
|
||||
|
||||
@@ -11,18 +11,15 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.ICollapsibleToolboxItem');
|
||||
goog.provide('Blockly.ISelectableToolboxItem');
|
||||
goog.provide('Blockly.IToolboxItem');
|
||||
|
||||
goog.requireType('Blockly.utils.toolbox');
|
||||
goog.module('Blockly.IToolboxItem');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
|
||||
/**
|
||||
* Interface for an item in the toolbox.
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IToolboxItem = function() {};
|
||||
const IToolboxItem = function() {};
|
||||
|
||||
/**
|
||||
* Initializes the toolbox item.
|
||||
@@ -31,21 +28,21 @@ Blockly.IToolboxItem = function() {};
|
||||
* @return {void}
|
||||
* @public
|
||||
*/
|
||||
Blockly.IToolboxItem.prototype.init;
|
||||
IToolboxItem.prototype.init;
|
||||
|
||||
/**
|
||||
* Gets the div for the toolbox item.
|
||||
* @return {?Element} The div for the toolbox item.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IToolboxItem.prototype.getDiv;
|
||||
IToolboxItem.prototype.getDiv;
|
||||
|
||||
/**
|
||||
* Gets a unique identifier for this toolbox item.
|
||||
* @return {string} The ID for the toolbox item.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IToolboxItem.prototype.getId;
|
||||
IToolboxItem.prototype.getId;
|
||||
|
||||
/**
|
||||
* Gets the parent if the toolbox item is nested.
|
||||
@@ -53,105 +50,33 @@ Blockly.IToolboxItem.prototype.getId;
|
||||
* this toolbox item is not nested.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IToolboxItem.prototype.getParent;
|
||||
IToolboxItem.prototype.getParent;
|
||||
|
||||
/**
|
||||
* Gets the nested level of the category.
|
||||
* @return {number} The nested level of the category.
|
||||
* @package
|
||||
*/
|
||||
Blockly.IToolboxItem.prototype.getLevel;
|
||||
IToolboxItem.prototype.getLevel;
|
||||
|
||||
/**
|
||||
* Whether the toolbox item is selectable.
|
||||
* @return {boolean} True if the toolbox item can be selected.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IToolboxItem.prototype.isSelectable;
|
||||
IToolboxItem.prototype.isSelectable;
|
||||
|
||||
/**
|
||||
* Whether the toolbox item is collapsible.
|
||||
* @return {boolean} True if the toolbox item is collapsible.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IToolboxItem.prototype.isCollapsible;
|
||||
IToolboxItem.prototype.isCollapsible;
|
||||
|
||||
/**
|
||||
* Dispose of this toolbox item. No-op by default.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IToolboxItem.prototype.dispose;
|
||||
IToolboxItem.prototype.dispose;
|
||||
|
||||
/**
|
||||
* Interface for an item in the toolbox that can be selected.
|
||||
* @extends {Blockly.IToolboxItem}
|
||||
* @interface
|
||||
*/
|
||||
Blockly.ISelectableToolboxItem = function() {};
|
||||
|
||||
/**
|
||||
* Gets the name of the toolbox item. Used for emitting events.
|
||||
* @return {string} The name of the toolbox item.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ISelectableToolboxItem.prototype.getName;
|
||||
|
||||
/**
|
||||
* Gets the contents of the toolbox item. These are items that are meant to be
|
||||
* displayed in the flyout.
|
||||
* @return {!Blockly.utils.toolbox.FlyoutItemInfoArray|string} The definition
|
||||
* of items to be displayed in the flyout.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ISelectableToolboxItem.prototype.getContents;
|
||||
|
||||
/**
|
||||
* Sets the current toolbox item as selected.
|
||||
* @param {boolean} _isSelected True if this category is selected, false
|
||||
* otherwise.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ISelectableToolboxItem.prototype.setSelected;
|
||||
|
||||
/**
|
||||
* Gets the HTML element that is clickable.
|
||||
* The parent toolbox element receives clicks. The parent toolbox will add an ID
|
||||
* to this element so it can pass the onClick event to the correct toolboxItem.
|
||||
* @return {!Element} The HTML element that receives clicks.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ISelectableToolboxItem.prototype.getClickTarget;
|
||||
|
||||
/**
|
||||
* Handles when the toolbox item is clicked.
|
||||
* @param {!Event} _e Click event to handle.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ISelectableToolboxItem.prototype.onClick;
|
||||
|
||||
/**
|
||||
* Interface for an item in the toolbox that can be collapsed.
|
||||
* @extends {Blockly.ISelectableToolboxItem}
|
||||
* @interface
|
||||
*/
|
||||
Blockly.ICollapsibleToolboxItem = function() {};
|
||||
|
||||
/**
|
||||
* Gets any children toolbox items. (ex. Gets the subcategories)
|
||||
* @return {!Array<!Blockly.IToolboxItem>} The child toolbox items.
|
||||
*/
|
||||
Blockly.ICollapsibleToolboxItem.prototype.getChildToolboxItems;
|
||||
|
||||
/**
|
||||
* Whether the toolbox item is expanded to show its child subcategories.
|
||||
* @return {boolean} True if the toolbox item shows its children, false if it
|
||||
* is collapsed.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ICollapsibleToolboxItem.prototype.isExpanded;
|
||||
|
||||
/**
|
||||
* Toggles whether or not the toolbox item is expanded.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ICollapsibleToolboxItem.prototype.toggleExpanded;
|
||||
exports = IToolboxItem;
|
||||
|
||||
218
core/internal_constants.js
Normal file
218
core/internal_constants.js
Normal file
@@ -0,0 +1,218 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2021 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Module that provides constants for use inside Blockly. Do not
|
||||
* use these constants outside of the core library.
|
||||
* @author fenichel@google.com (Rachel Fenichel)
|
||||
* @package
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.internalConstants');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
const connectionTypes = goog.require('Blockly.connectionTypes');
|
||||
|
||||
|
||||
/**
|
||||
* The multiplier for scroll wheel deltas using the line delta mode.
|
||||
* @type {number}
|
||||
*/
|
||||
const LINE_MODE_MULTIPLIER = 40;
|
||||
exports.LINE_MODE_MULTIPLIER = LINE_MODE_MULTIPLIER;
|
||||
|
||||
/**
|
||||
* The multiplier for scroll wheel deltas using the page delta mode.
|
||||
* @type {number}
|
||||
*/
|
||||
const PAGE_MODE_MULTIPLIER = 125;
|
||||
exports.PAGE_MODE_MULTIPLIER = PAGE_MODE_MULTIPLIER;
|
||||
|
||||
/**
|
||||
* Number of pixels the mouse must move before a drag starts.
|
||||
*/
|
||||
const DRAG_RADIUS = 5;
|
||||
exports.DRAG_RADIUS = DRAG_RADIUS;
|
||||
|
||||
/**
|
||||
* Number of pixels the mouse must move before a drag/scroll starts from the
|
||||
* flyout. Because the drag-intention is determined when this is reached, it is
|
||||
* larger than DRAG_RADIUS so that the drag-direction is clearer.
|
||||
*/
|
||||
const FLYOUT_DRAG_RADIUS = 10;
|
||||
exports.FLYOUT_DRAG_RADIUS = FLYOUT_DRAG_RADIUS;
|
||||
|
||||
/**
|
||||
* Maximum misalignment between connections for them to snap together.
|
||||
*/
|
||||
const SNAP_RADIUS = 28;
|
||||
exports.SNAP_RADIUS = SNAP_RADIUS;
|
||||
|
||||
/**
|
||||
* Maximum misalignment between connections for them to snap together,
|
||||
* when a connection is already highlighted.
|
||||
*/
|
||||
const CONNECTING_SNAP_RADIUS = SNAP_RADIUS;
|
||||
exports.CONNECTING_SNAP_RADIUS = CONNECTING_SNAP_RADIUS;
|
||||
|
||||
/**
|
||||
* How much to prefer staying connected to the current connection over moving to
|
||||
* a new connection. The current previewed connection is considered to be this
|
||||
* much closer to the matching connection on the block than it actually is.
|
||||
*/
|
||||
const CURRENT_CONNECTION_PREFERENCE = 8;
|
||||
exports.CURRENT_CONNECTION_PREFERENCE = CURRENT_CONNECTION_PREFERENCE;
|
||||
|
||||
/**
|
||||
* Delay in ms between trigger and bumping unconnected block out of alignment.
|
||||
*/
|
||||
const BUMP_DELAY = 250;
|
||||
exports.BUMP_DELAY = BUMP_DELAY;
|
||||
|
||||
/**
|
||||
* Maximum randomness in workspace units for bumping a block.
|
||||
*/
|
||||
const BUMP_RANDOMNESS = 10;
|
||||
exports.BUMP_RANDOMNESS = BUMP_RANDOMNESS;
|
||||
|
||||
/**
|
||||
* Number of characters to truncate a collapsed block to.
|
||||
*/
|
||||
const COLLAPSE_CHARS = 30;
|
||||
exports.COLLAPSE_CHARS = COLLAPSE_CHARS;
|
||||
|
||||
/**
|
||||
* Length in ms for a touch to become a long press.
|
||||
*/
|
||||
const LONGPRESS = 750;
|
||||
exports.LONGPRESS = LONGPRESS;
|
||||
|
||||
/**
|
||||
* Prevent a sound from playing if another sound preceded it within this many
|
||||
* milliseconds.
|
||||
*/
|
||||
const SOUND_LIMIT = 100;
|
||||
exports.SOUND_LIMIT = SOUND_LIMIT;
|
||||
|
||||
/**
|
||||
* When dragging a block out of a stack, split the stack in two (true), or drag
|
||||
* out the block healing the stack (false).
|
||||
*/
|
||||
const DRAG_STACK = true;
|
||||
exports.DRAG_STACK = DRAG_STACK;
|
||||
|
||||
/**
|
||||
* The richness of block colours, regardless of the hue.
|
||||
* Must be in the range of 0 (inclusive) to 1 (exclusive).
|
||||
*/
|
||||
const HSV_SATURATION = 0.45;
|
||||
exports.HSV_SATURATION = HSV_SATURATION;
|
||||
|
||||
/**
|
||||
* The intensity of block colours, regardless of the hue.
|
||||
* Must be in the range of 0 (inclusive) to 1 (exclusive).
|
||||
*/
|
||||
const HSV_VALUE = 0.65;
|
||||
exports.HSV_VALUE = HSV_VALUE;
|
||||
|
||||
/**
|
||||
* Sprited icons and images.
|
||||
*/
|
||||
const SPRITE = {
|
||||
width: 96,
|
||||
height: 124,
|
||||
url: 'sprites.png'
|
||||
};
|
||||
exports.SPRITE = SPRITE;
|
||||
|
||||
/**
|
||||
* ENUM for no drag operation.
|
||||
* @const
|
||||
*/
|
||||
const DRAG_NONE = 0;
|
||||
exports.DRAG_NONE = DRAG_NONE;
|
||||
|
||||
/**
|
||||
* ENUM for inside the sticky DRAG_RADIUS.
|
||||
* @const
|
||||
*/
|
||||
const DRAG_STICKY = 1;
|
||||
exports.DRAG_STICKY = DRAG_STICKY;
|
||||
|
||||
/**
|
||||
* ENUM for inside the non-sticky DRAG_RADIUS, for differentiating between
|
||||
* clicks and drags.
|
||||
* @const
|
||||
*/
|
||||
const DRAG_BEGIN = 1;
|
||||
exports.DRAG_BEGIN = DRAG_BEGIN;
|
||||
|
||||
/**
|
||||
* ENUM for freely draggable (outside the DRAG_RADIUS, if one applies).
|
||||
* @const
|
||||
*/
|
||||
const DRAG_FREE = 2;
|
||||
exports.DRAG_FREE = DRAG_FREE;
|
||||
|
||||
/**
|
||||
* Lookup table for determining the opposite type of a connection.
|
||||
* @const
|
||||
*/
|
||||
const OPPOSITE_TYPE = [];
|
||||
OPPOSITE_TYPE[connectionTypes.INPUT_VALUE] = connectionTypes.OUTPUT_VALUE;
|
||||
OPPOSITE_TYPE[connectionTypes.OUTPUT_VALUE] = connectionTypes.INPUT_VALUE;
|
||||
OPPOSITE_TYPE[connectionTypes.NEXT_STATEMENT] =
|
||||
connectionTypes.PREVIOUS_STATEMENT;
|
||||
OPPOSITE_TYPE[connectionTypes.PREVIOUS_STATEMENT] =
|
||||
connectionTypes.NEXT_STATEMENT;
|
||||
|
||||
exports.OPPOSITE_TYPE = OPPOSITE_TYPE;
|
||||
|
||||
/**
|
||||
* String for use in the "custom" attribute of a category in toolbox XML.
|
||||
* This string indicates that the category should be dynamically populated with
|
||||
* variable blocks.
|
||||
* @const {string}
|
||||
*/
|
||||
const VARIABLE_CATEGORY_NAME = 'VARIABLE';
|
||||
exports.VARIABLE_CATEGORY_NAME = VARIABLE_CATEGORY_NAME;
|
||||
|
||||
/**
|
||||
* String for use in the "custom" attribute of a category in toolbox XML.
|
||||
* This string indicates that the category should be dynamically populated with
|
||||
* variable blocks.
|
||||
* @const {string}
|
||||
*/
|
||||
const VARIABLE_DYNAMIC_CATEGORY_NAME = 'VARIABLE_DYNAMIC';
|
||||
exports.VARIABLE_DYNAMIC_CATEGORY_NAME = VARIABLE_DYNAMIC_CATEGORY_NAME;
|
||||
|
||||
/**
|
||||
* String for use in the "custom" attribute of a category in toolbox XML.
|
||||
* This string indicates that the category should be dynamically populated with
|
||||
* procedure blocks.
|
||||
* @const {string}
|
||||
*/
|
||||
const PROCEDURE_CATEGORY_NAME = 'PROCEDURE';
|
||||
exports.PROCEDURE_CATEGORY_NAME = PROCEDURE_CATEGORY_NAME;
|
||||
|
||||
/**
|
||||
* String for use in the dropdown created in field_variable.
|
||||
* This string indicates that this option in the dropdown is 'Rename
|
||||
* variable...' and if selected, should trigger the prompt to rename a variable.
|
||||
* @const {string}
|
||||
*/
|
||||
const RENAME_VARIABLE_ID = 'RENAME_VARIABLE_ID';
|
||||
exports.RENAME_VARIABLE_ID = RENAME_VARIABLE_ID;
|
||||
|
||||
/**
|
||||
* String for use in the dropdown created in field_variable.
|
||||
* This string indicates that this option in the dropdown is 'Delete the "%1"
|
||||
* variable' and if selected, should trigger the prompt to delete a variable.
|
||||
* @const {string}
|
||||
*/
|
||||
const DELETE_VARIABLE_ID = 'DELETE_VARIABLE_ID';
|
||||
exports.DELETE_VARIABLE_ID = DELETE_VARIABLE_ID;
|
||||
@@ -13,8 +13,6 @@
|
||||
goog.provide('Blockly.ASTNode');
|
||||
|
||||
goog.require('Blockly.connectionTypes');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
@@ -420,7 +418,7 @@ Blockly.ASTNode.prototype.findPrevForField_ = function() {
|
||||
*/
|
||||
Blockly.ASTNode.prototype.navigateBetweenStacks_ = function(forward) {
|
||||
var curLocation = this.getLocation();
|
||||
if (!(curLocation instanceof Blockly.Block)) {
|
||||
if (curLocation.getSourceBlock) {
|
||||
curLocation = /** @type {!Blockly.IASTNodeLocationWithBlock} */ (
|
||||
curLocation).getSourceBlock();
|
||||
}
|
||||
|
||||
@@ -11,11 +11,13 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.BasicCursor');
|
||||
goog.module('Blockly.BasicCursor');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.ASTNode');
|
||||
goog.require('Blockly.Cursor');
|
||||
goog.require('Blockly.registry');
|
||||
const ASTNode = goog.require('Blockly.ASTNode');
|
||||
const Cursor = goog.require('Blockly.Cursor');
|
||||
const {register, Type} = goog.require('Blockly.registry');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
|
||||
|
||||
/**
|
||||
@@ -23,31 +25,31 @@ goog.require('Blockly.registry');
|
||||
* This will allow the user to get to all nodes in the AST by hitting next or
|
||||
* previous.
|
||||
* @constructor
|
||||
* @extends {Blockly.Cursor}
|
||||
* @extends {Cursor}
|
||||
*/
|
||||
Blockly.BasicCursor = function() {
|
||||
Blockly.BasicCursor.superClass_.constructor.call(this);
|
||||
const BasicCursor = function() {
|
||||
BasicCursor.superClass_.constructor.call(this);
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.BasicCursor, Blockly.Cursor);
|
||||
inherits(BasicCursor, Cursor);
|
||||
|
||||
/**
|
||||
* Name used for registering a basic cursor.
|
||||
* @const {string}
|
||||
*/
|
||||
Blockly.BasicCursor.registrationName = 'basicCursor';
|
||||
BasicCursor.registrationName = 'basicCursor';
|
||||
|
||||
/**
|
||||
* Find the next node in the pre order traversal.
|
||||
* @return {Blockly.ASTNode} The next node, or null if the current node is
|
||||
* @return {?ASTNode} The next node, or null if the current node is
|
||||
* not set or there is no next value.
|
||||
* @override
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.next = function() {
|
||||
var curNode = this.getCurNode();
|
||||
BasicCursor.prototype.next = function() {
|
||||
const curNode = this.getCurNode();
|
||||
if (!curNode) {
|
||||
return null;
|
||||
}
|
||||
var newNode = this.getNextNode_(curNode, this.validNode_);
|
||||
const newNode = this.getNextNode_(curNode, this.validNode_);
|
||||
|
||||
if (newNode) {
|
||||
this.setCurNode(newNode);
|
||||
@@ -59,26 +61,26 @@ Blockly.BasicCursor.prototype.next = function() {
|
||||
* For a basic cursor we only have the ability to go next and previous, so
|
||||
* in will also allow the user to get to the next node in the pre order
|
||||
* traversal.
|
||||
* @return {Blockly.ASTNode} The next node, or null if the current node is
|
||||
* @return {?ASTNode} The next node, or null if the current node is
|
||||
* not set or there is no next value.
|
||||
* @override
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.in = function() {
|
||||
BasicCursor.prototype.in = function() {
|
||||
return this.next();
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the previous node in the pre order traversal.
|
||||
* @return {Blockly.ASTNode} The previous node, or null if the current node
|
||||
* @return {?ASTNode} The previous node, or null if the current node
|
||||
* is not set or there is no previous value.
|
||||
* @override
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.prev = function() {
|
||||
var curNode = this.getCurNode();
|
||||
BasicCursor.prototype.prev = function() {
|
||||
const curNode = this.getCurNode();
|
||||
if (!curNode) {
|
||||
return null;
|
||||
}
|
||||
var newNode = this.getPreviousNode_(curNode, this.validNode_);
|
||||
const newNode = this.getPreviousNode_(curNode, this.validNode_);
|
||||
|
||||
if (newNode) {
|
||||
this.setCurNode(newNode);
|
||||
@@ -90,11 +92,11 @@ Blockly.BasicCursor.prototype.prev = function() {
|
||||
* For a basic cursor we only have the ability to go next and previous, so
|
||||
* out will allow the user to get to the previous node in the pre order
|
||||
* traversal.
|
||||
* @return {Blockly.ASTNode} The previous node, or null if the current node is
|
||||
* @return {?ASTNode} The previous node, or null if the current node is
|
||||
* not set or there is no previous value.
|
||||
* @override
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.out = function() {
|
||||
BasicCursor.prototype.out = function() {
|
||||
return this.prev();
|
||||
};
|
||||
|
||||
@@ -102,23 +104,23 @@ Blockly.BasicCursor.prototype.out = function() {
|
||||
* Uses pre order traversal to navigate the Blockly AST. This will allow
|
||||
* a user to easily navigate the entire Blockly AST without having to go in
|
||||
* and out levels on the tree.
|
||||
* @param {Blockly.ASTNode} node The current position in the AST.
|
||||
* @param {!function(Blockly.ASTNode) : boolean} isValid A function true/false
|
||||
* @param {?ASTNode} node The current position in the AST.
|
||||
* @param {!function(ASTNode) : boolean} isValid A function true/false
|
||||
* depending on whether the given node should be traversed.
|
||||
* @return {Blockly.ASTNode} The next node in the traversal.
|
||||
* @return {?ASTNode} The next node in the traversal.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.getNextNode_ = function(node, isValid) {
|
||||
BasicCursor.prototype.getNextNode_ = function(node, isValid) {
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
var newNode = node.in() || node.next();
|
||||
const newNode = node.in() || node.next();
|
||||
if (isValid(newNode)) {
|
||||
return newNode;
|
||||
} else if (newNode) {
|
||||
return this.getNextNode_(newNode, isValid);
|
||||
}
|
||||
var siblingOrParent = this.findSiblingOrParent_(node.out());
|
||||
const siblingOrParent = this.findSiblingOrParent_(node.out());
|
||||
if (isValid(siblingOrParent)) {
|
||||
return siblingOrParent;
|
||||
} else if (siblingOrParent) {
|
||||
@@ -131,18 +133,18 @@ Blockly.BasicCursor.prototype.getNextNode_ = function(node, isValid) {
|
||||
* Reverses the pre order traversal in order to find the previous node. This
|
||||
* will allow a user to easily navigate the entire Blockly AST without having to
|
||||
* go in and out levels on the tree.
|
||||
* @param {Blockly.ASTNode} node The current position in the AST.
|
||||
* @param {!function(Blockly.ASTNode) : boolean} isValid A function true/false
|
||||
* @param {?ASTNode} node The current position in the AST.
|
||||
* @param {!function(ASTNode) : boolean} isValid A function true/false
|
||||
* depending on whether the given node should be traversed.
|
||||
* @return {Blockly.ASTNode} The previous node in the traversal or null if no
|
||||
* @return {?ASTNode} The previous node in the traversal or null if no
|
||||
* previous node exists.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.getPreviousNode_ = function(node, isValid) {
|
||||
BasicCursor.prototype.getPreviousNode_ = function(node, isValid) {
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
var newNode = node.prev();
|
||||
let newNode = node.prev();
|
||||
|
||||
if (newNode) {
|
||||
newNode = this.getRightMostChild_(newNode);
|
||||
@@ -160,19 +162,16 @@ Blockly.BasicCursor.prototype.getPreviousNode_ = function(node, isValid) {
|
||||
/**
|
||||
* Decides what nodes to traverse and which ones to skip. Currently, it
|
||||
* skips output, stack and workspace nodes.
|
||||
* @param {Blockly.ASTNode} node The AST node to check whether it is valid.
|
||||
* @param {?ASTNode} node The AST node to check whether it is valid.
|
||||
* @return {boolean} True if the node should be visited, false otherwise.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.validNode_ = function(node) {
|
||||
var isValid = false;
|
||||
var type = node && node.getType();
|
||||
if (type == Blockly.ASTNode.types.OUTPUT ||
|
||||
type == Blockly.ASTNode.types.INPUT ||
|
||||
type == Blockly.ASTNode.types.FIELD ||
|
||||
type == Blockly.ASTNode.types.NEXT ||
|
||||
type == Blockly.ASTNode.types.PREVIOUS ||
|
||||
type == Blockly.ASTNode.types.WORKSPACE) {
|
||||
BasicCursor.prototype.validNode_ = function(node) {
|
||||
let isValid = false;
|
||||
const type = node && node.getType();
|
||||
if (type == ASTNode.types.OUTPUT || type == ASTNode.types.INPUT ||
|
||||
type == ASTNode.types.FIELD || type == ASTNode.types.NEXT ||
|
||||
type == ASTNode.types.PREVIOUS || type == ASTNode.types.WORKSPACE) {
|
||||
isValid = true;
|
||||
}
|
||||
return isValid;
|
||||
@@ -180,16 +179,16 @@ Blockly.BasicCursor.prototype.validNode_ = function(node) {
|
||||
|
||||
/**
|
||||
* From the given node find either the next valid sibling or parent.
|
||||
* @param {Blockly.ASTNode} node The current position in the AST.
|
||||
* @return {Blockly.ASTNode} The parent AST node or null if there are no
|
||||
* @param {?ASTNode} node The current position in the AST.
|
||||
* @return {?ASTNode} The parent AST node or null if there are no
|
||||
* valid parents.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.findSiblingOrParent_ = function(node) {
|
||||
BasicCursor.prototype.findSiblingOrParent_ = function(node) {
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
var nextNode = node.next();
|
||||
const nextNode = node.next();
|
||||
if (nextNode) {
|
||||
return nextNode;
|
||||
}
|
||||
@@ -199,22 +198,22 @@ Blockly.BasicCursor.prototype.findSiblingOrParent_ = function(node) {
|
||||
|
||||
/**
|
||||
* Get the right most child of a node.
|
||||
* @param {Blockly.ASTNode} node The node to find the right most child of.
|
||||
* @return {Blockly.ASTNode} The right most child of the given node, or the node
|
||||
* @param {?ASTNode} node The node to find the right most child of.
|
||||
* @return {?ASTNode} The right most child of the given node, or the node
|
||||
* if no child exists.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.getRightMostChild_ = function(node) {
|
||||
BasicCursor.prototype.getRightMostChild_ = function(node) {
|
||||
if (!node.in()) {
|
||||
return node;
|
||||
}
|
||||
var newNode = node.in();
|
||||
let newNode = node.in();
|
||||
while (newNode.next()) {
|
||||
newNode = newNode.next();
|
||||
}
|
||||
return this.getRightMostChild_(newNode);
|
||||
};
|
||||
|
||||
Blockly.registry.register(
|
||||
Blockly.registry.Type.CURSOR, Blockly.BasicCursor.registrationName,
|
||||
Blockly.BasicCursor);
|
||||
register(Type.CURSOR, BasicCursor.registrationName, BasicCursor);
|
||||
|
||||
exports = BasicCursor;
|
||||
|
||||
@@ -11,46 +11,47 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Cursor');
|
||||
goog.module('Blockly.Cursor');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.ASTNode');
|
||||
goog.require('Blockly.Marker');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.utils.object');
|
||||
const ASTNode = goog.require('Blockly.ASTNode');
|
||||
const Marker = goog.require('Blockly.Marker');
|
||||
const {DEFAULT, register, Type} = goog.require('Blockly.registry');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a cursor.
|
||||
* A cursor controls how a user navigates the Blockly AST.
|
||||
* @constructor
|
||||
* @extends {Blockly.Marker}
|
||||
* @extends {Marker}
|
||||
*/
|
||||
Blockly.Cursor = function() {
|
||||
Blockly.Cursor.superClass_.constructor.call(this);
|
||||
const Cursor = function() {
|
||||
Cursor.superClass_.constructor.call(this);
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
this.type = 'cursor';
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Cursor, Blockly.Marker);
|
||||
inherits(Cursor, Marker);
|
||||
|
||||
/**
|
||||
* Find the next connection, field, or block.
|
||||
* @return {Blockly.ASTNode} The next element, or null if the current node is
|
||||
* @return {ASTNode} The next element, or null if the current node is
|
||||
* not set or there is no next value.
|
||||
* @public
|
||||
*/
|
||||
Blockly.Cursor.prototype.next = function() {
|
||||
var curNode = this.getCurNode();
|
||||
Cursor.prototype.next = function() {
|
||||
const curNode = this.getCurNode();
|
||||
if (!curNode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var newNode = curNode.next();
|
||||
let newNode = curNode.next();
|
||||
while (newNode && newNode.next() &&
|
||||
(newNode.getType() == Blockly.ASTNode.types.NEXT ||
|
||||
newNode.getType() == Blockly.ASTNode.types.BLOCK)) {
|
||||
(newNode.getType() == ASTNode.types.NEXT ||
|
||||
newNode.getType() == ASTNode.types.BLOCK)) {
|
||||
newNode = newNode.next();
|
||||
}
|
||||
|
||||
@@ -62,22 +63,22 @@ Blockly.Cursor.prototype.next = function() {
|
||||
|
||||
/**
|
||||
* Find the in connection or field.
|
||||
* @return {Blockly.ASTNode} The in element, or null if the current node is
|
||||
* @return {ASTNode} The in element, or null if the current node is
|
||||
* not set or there is no in value.
|
||||
* @public
|
||||
*/
|
||||
Blockly.Cursor.prototype.in = function() {
|
||||
var curNode = this.getCurNode();
|
||||
Cursor.prototype.in = function() {
|
||||
let curNode = this.getCurNode();
|
||||
if (!curNode) {
|
||||
return null;
|
||||
}
|
||||
// If we are on a previous or output connection, go to the block level before
|
||||
// performing next operation.
|
||||
if (curNode.getType() == Blockly.ASTNode.types.PREVIOUS ||
|
||||
curNode.getType() == Blockly.ASTNode.types.OUTPUT) {
|
||||
if (curNode.getType() == ASTNode.types.PREVIOUS ||
|
||||
curNode.getType() == ASTNode.types.OUTPUT) {
|
||||
curNode = curNode.next();
|
||||
}
|
||||
var newNode = curNode.in();
|
||||
const newNode = curNode.in();
|
||||
|
||||
if (newNode) {
|
||||
this.setCurNode(newNode);
|
||||
@@ -87,20 +88,20 @@ Blockly.Cursor.prototype.in = function() {
|
||||
|
||||
/**
|
||||
* Find the previous connection, field, or block.
|
||||
* @return {Blockly.ASTNode} The previous element, or null if the current node
|
||||
* @return {ASTNode} The previous element, or null if the current node
|
||||
* is not set or there is no previous value.
|
||||
* @public
|
||||
*/
|
||||
Blockly.Cursor.prototype.prev = function() {
|
||||
var curNode = this.getCurNode();
|
||||
Cursor.prototype.prev = function() {
|
||||
const curNode = this.getCurNode();
|
||||
if (!curNode) {
|
||||
return null;
|
||||
}
|
||||
var newNode = curNode.prev();
|
||||
let newNode = curNode.prev();
|
||||
|
||||
while (newNode && newNode.prev() &&
|
||||
(newNode.getType() == Blockly.ASTNode.types.NEXT ||
|
||||
newNode.getType() == Blockly.ASTNode.types.BLOCK)) {
|
||||
(newNode.getType() == ASTNode.types.NEXT ||
|
||||
newNode.getType() == ASTNode.types.BLOCK)) {
|
||||
newNode = newNode.prev();
|
||||
}
|
||||
|
||||
@@ -112,18 +113,18 @@ Blockly.Cursor.prototype.prev = function() {
|
||||
|
||||
/**
|
||||
* Find the out connection, field, or block.
|
||||
* @return {Blockly.ASTNode} The out element, or null if the current node is
|
||||
* @return {ASTNode} The out element, or null if the current node is
|
||||
* not set or there is no out value.
|
||||
* @public
|
||||
*/
|
||||
Blockly.Cursor.prototype.out = function() {
|
||||
var curNode = this.getCurNode();
|
||||
Cursor.prototype.out = function() {
|
||||
const curNode = this.getCurNode();
|
||||
if (!curNode) {
|
||||
return null;
|
||||
}
|
||||
var newNode = curNode.out();
|
||||
let newNode = curNode.out();
|
||||
|
||||
if (newNode && newNode.getType() == Blockly.ASTNode.types.BLOCK) {
|
||||
if (newNode && newNode.getType() == ASTNode.types.BLOCK) {
|
||||
newNode = newNode.prev() || newNode;
|
||||
}
|
||||
|
||||
@@ -133,5 +134,6 @@ Blockly.Cursor.prototype.out = function() {
|
||||
return newNode;
|
||||
};
|
||||
|
||||
Blockly.registry.register(
|
||||
Blockly.registry.Type.CURSOR, Blockly.registry.DEFAULT, Blockly.Cursor);
|
||||
register(Type.CURSOR, DEFAULT, Cursor);
|
||||
|
||||
exports = Cursor;
|
||||
|
||||
@@ -11,40 +11,43 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.TabNavigateCursor');
|
||||
goog.module('Blockly.TabNavigateCursor');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.ASTNode');
|
||||
goog.require('Blockly.BasicCursor');
|
||||
goog.require('Blockly.utils.object');
|
||||
|
||||
goog.requireType('Blockly.Field');
|
||||
const ASTNode = goog.require('Blockly.ASTNode');
|
||||
const BasicCursor = goog.require('Blockly.BasicCursor');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Field = goog.requireType('Blockly.Field');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
|
||||
|
||||
/**
|
||||
* A cursor for navigating between tab navigable fields.
|
||||
* @constructor
|
||||
* @extends {Blockly.BasicCursor}
|
||||
* @extends {BasicCursor}
|
||||
*/
|
||||
Blockly.TabNavigateCursor = function() {
|
||||
Blockly.TabNavigateCursor.superClass_.constructor.call(this);
|
||||
const TabNavigateCursor = function() {
|
||||
TabNavigateCursor.superClass_.constructor.call(this);
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.TabNavigateCursor, Blockly.BasicCursor);
|
||||
inherits(TabNavigateCursor, BasicCursor);
|
||||
|
||||
/**
|
||||
* Skip all nodes except for tab navigable fields.
|
||||
* @param {Blockly.ASTNode} node The AST node to check whether it is valid.
|
||||
* @param {?ASTNode} node The AST node to check whether it is valid.
|
||||
* @return {boolean} True if the node should be visited, false otherwise.
|
||||
* @override
|
||||
*/
|
||||
Blockly.TabNavigateCursor.prototype.validNode_ = function(node) {
|
||||
var isValid = false;
|
||||
var type = node && node.getType();
|
||||
TabNavigateCursor.prototype.validNode_ = function(node) {
|
||||
let isValid = false;
|
||||
const type = node && node.getType();
|
||||
if (node) {
|
||||
var location = /** @type {Blockly.Field} */ (node.getLocation());
|
||||
if (type == Blockly.ASTNode.types.FIELD &&
|
||||
location && location.isTabNavigable() && location.isClickable()) {
|
||||
const location = /** @type {Field} */ (node.getLocation());
|
||||
if (type == ASTNode.types.FIELD && location && location.isTabNavigable() &&
|
||||
location.isClickable()) {
|
||||
isValid = true;
|
||||
}
|
||||
}
|
||||
return isValid;
|
||||
};
|
||||
|
||||
exports = TabNavigateCursor;
|
||||
|
||||
@@ -10,24 +10,26 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.MarkerManager');
|
||||
goog.module('Blockly.MarkerManager');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Cursor');
|
||||
goog.require('Blockly.Marker');
|
||||
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Cursor = goog.requireType('Blockly.Cursor');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Marker = goog.requireType('Blockly.Marker');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
|
||||
|
||||
/**
|
||||
* Class to manage the multiple markers and the cursor on a workspace.
|
||||
* @param {!Blockly.WorkspaceSvg} workspace The workspace for the marker manager.
|
||||
* @param {!WorkspaceSvg} workspace The workspace for the marker manager.
|
||||
* @constructor
|
||||
* @package
|
||||
*/
|
||||
Blockly.MarkerManager = function(workspace){
|
||||
const MarkerManager = function(workspace) {
|
||||
/**
|
||||
* The cursor.
|
||||
* @type {?Blockly.Cursor}
|
||||
* @type {?Cursor}
|
||||
* @private
|
||||
*/
|
||||
this.cursor_ = null;
|
||||
@@ -41,14 +43,14 @@ Blockly.MarkerManager = function(workspace){
|
||||
|
||||
/**
|
||||
* The map of markers for the workspace.
|
||||
* @type {!Object<string, !Blockly.Marker>}
|
||||
* @type {!Object<string, !Marker>}
|
||||
* @private
|
||||
*/
|
||||
this.markers_ = Object.create(null);
|
||||
|
||||
/**
|
||||
* The workspace this marker manager is associated with.
|
||||
* @type {!Blockly.WorkspaceSvg}
|
||||
* @type {!WorkspaceSvg}
|
||||
* @private
|
||||
*/
|
||||
this.workspace_ = workspace;
|
||||
@@ -59,19 +61,19 @@ Blockly.MarkerManager = function(workspace){
|
||||
* @type {string}
|
||||
* @const
|
||||
*/
|
||||
Blockly.MarkerManager.LOCAL_MARKER = 'local_marker_1';
|
||||
MarkerManager.LOCAL_MARKER = 'local_marker_1';
|
||||
|
||||
/**
|
||||
* Register the marker by adding it to the map of markers.
|
||||
* @param {string} id A unique identifier for the marker.
|
||||
* @param {!Blockly.Marker} marker The marker to register.
|
||||
* @param {!Marker} marker The marker to register.
|
||||
*/
|
||||
Blockly.MarkerManager.prototype.registerMarker = function(id, marker) {
|
||||
MarkerManager.prototype.registerMarker = function(id, marker) {
|
||||
if (this.markers_[id]) {
|
||||
this.unregisterMarker(id);
|
||||
}
|
||||
marker.setDrawer(this.workspace_.getRenderer()
|
||||
.makeMarkerDrawer(this.workspace_, marker));
|
||||
marker.setDrawer(
|
||||
this.workspace_.getRenderer().makeMarkerDrawer(this.workspace_, marker));
|
||||
this.setMarkerSvg(marker.getDrawer().createDom());
|
||||
this.markers_[id] = marker;
|
||||
};
|
||||
@@ -80,47 +82,48 @@ Blockly.MarkerManager.prototype.registerMarker = function(id, marker) {
|
||||
* Unregister the marker by removing it from the map of markers.
|
||||
* @param {string} id The ID of the marker to unregister.
|
||||
*/
|
||||
Blockly.MarkerManager.prototype.unregisterMarker = function(id) {
|
||||
var marker = this.markers_[id];
|
||||
MarkerManager.prototype.unregisterMarker = function(id) {
|
||||
const marker = this.markers_[id];
|
||||
if (marker) {
|
||||
marker.dispose();
|
||||
delete this.markers_[id];
|
||||
} else {
|
||||
throw Error('Marker with ID ' + id + ' does not exist. ' +
|
||||
throw Error(
|
||||
'Marker with ID ' + id + ' does not exist. ' +
|
||||
'Can only unregister markers that exist.');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the cursor for the workspace.
|
||||
* @return {?Blockly.Cursor} The cursor for this workspace.
|
||||
* @return {?Cursor} The cursor for this workspace.
|
||||
*/
|
||||
Blockly.MarkerManager.prototype.getCursor = function() {
|
||||
MarkerManager.prototype.getCursor = function() {
|
||||
return this.cursor_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a single marker that corresponds to the given ID.
|
||||
* @param {string} id A unique identifier for the marker.
|
||||
* @return {?Blockly.Marker} The marker that corresponds to the given ID,
|
||||
* @return {?Marker} The marker that corresponds to the given ID,
|
||||
* or null if none exists.
|
||||
*/
|
||||
Blockly.MarkerManager.prototype.getMarker = function(id) {
|
||||
MarkerManager.prototype.getMarker = function(id) {
|
||||
return this.markers_[id] || null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the cursor and initializes the drawer for use with keyboard navigation.
|
||||
* @param {Blockly.Cursor} cursor The cursor used to move around this workspace.
|
||||
* @param {Cursor} cursor The cursor used to move around this workspace.
|
||||
*/
|
||||
Blockly.MarkerManager.prototype.setCursor = function(cursor) {
|
||||
MarkerManager.prototype.setCursor = function(cursor) {
|
||||
if (this.cursor_ && this.cursor_.getDrawer()) {
|
||||
this.cursor_.getDrawer().dispose();
|
||||
}
|
||||
this.cursor_ = cursor;
|
||||
if (this.cursor_) {
|
||||
var drawer = this.workspace_.getRenderer()
|
||||
.makeMarkerDrawer(this.workspace_, this.cursor_);
|
||||
const drawer = this.workspace_.getRenderer().makeMarkerDrawer(
|
||||
this.workspace_, this.cursor_);
|
||||
this.cursor_.setDrawer(drawer);
|
||||
this.setCursorSvg(this.cursor_.getDrawer().createDom());
|
||||
}
|
||||
@@ -132,7 +135,7 @@ Blockly.MarkerManager.prototype.setCursor = function(cursor) {
|
||||
* workspace SVG group.
|
||||
* @package
|
||||
*/
|
||||
Blockly.MarkerManager.prototype.setCursorSvg = function(cursorSvg) {
|
||||
MarkerManager.prototype.setCursorSvg = function(cursorSvg) {
|
||||
if (!cursorSvg) {
|
||||
this.cursorSvg_ = null;
|
||||
return;
|
||||
@@ -148,7 +151,7 @@ Blockly.MarkerManager.prototype.setCursorSvg = function(cursorSvg) {
|
||||
* workspace SVG group.
|
||||
* @package
|
||||
*/
|
||||
Blockly.MarkerManager.prototype.setMarkerSvg = function(markerSvg) {
|
||||
MarkerManager.prototype.setMarkerSvg = function(markerSvg) {
|
||||
if (!markerSvg) {
|
||||
this.markerSvg_ = null;
|
||||
return;
|
||||
@@ -167,7 +170,7 @@ Blockly.MarkerManager.prototype.setMarkerSvg = function(markerSvg) {
|
||||
* Redraw the attached cursor SVG if needed.
|
||||
* @package
|
||||
*/
|
||||
Blockly.MarkerManager.prototype.updateMarkers = function() {
|
||||
MarkerManager.prototype.updateMarkers = function() {
|
||||
if (this.workspace_.keyboardAccessibilityMode && this.cursorSvg_) {
|
||||
this.workspace_.getCursor().draw();
|
||||
}
|
||||
@@ -179,9 +182,9 @@ Blockly.MarkerManager.prototype.updateMarkers = function() {
|
||||
* @suppress {checkTypes}
|
||||
* @package
|
||||
*/
|
||||
Blockly.MarkerManager.prototype.dispose = function() {
|
||||
var markerIds = Object.keys(this.markers_);
|
||||
for (var i = 0, markerId; (markerId = markerIds[i]); i++) {
|
||||
MarkerManager.prototype.dispose = function() {
|
||||
const markerIds = Object.keys(this.markers_);
|
||||
for (let i = 0, markerId; (markerId = markerIds[i]); i++) {
|
||||
this.unregisterMarker(markerId);
|
||||
}
|
||||
this.markers_ = null;
|
||||
@@ -190,3 +193,6 @@ Blockly.MarkerManager.prototype.dispose = function() {
|
||||
this.cursor_ = null;
|
||||
}
|
||||
};
|
||||
|
||||
/** @package */
|
||||
exports = MarkerManager;
|
||||
|
||||
195
core/menu.js
195
core/menu.js
@@ -10,29 +10,31 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Menu');
|
||||
goog.module('Blockly.Menu');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.browserEvents');
|
||||
goog.require('Blockly.utils.aria');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.KeyCodes');
|
||||
goog.require('Blockly.utils.style');
|
||||
|
||||
goog.requireType('Blockly.MenuItem');
|
||||
goog.requireType('Blockly.utils.Size');
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const MenuItem = goog.requireType('Blockly.MenuItem');
|
||||
const KeyCodes = goog.require('Blockly.utils.KeyCodes');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Size = goog.requireType('Blockly.utils.Size');
|
||||
const aria = goog.require('Blockly.utils.aria');
|
||||
const browserEvents = goog.require('Blockly.browserEvents');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const style = goog.require('Blockly.utils.style');
|
||||
|
||||
|
||||
/**
|
||||
* A basic menu class.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Menu = function() {
|
||||
const Menu = function() {
|
||||
/**
|
||||
* Array of menu items.
|
||||
* (Nulls are never in the array, but typing the array as nullable prevents
|
||||
* the compiler from objecting to .indexOf(null))
|
||||
* @type {!Array<Blockly.MenuItem>}
|
||||
* @type {!Array<MenuItem>}
|
||||
* @private
|
||||
*/
|
||||
this.menuItems_ = [];
|
||||
@@ -41,7 +43,7 @@ Blockly.Menu = function() {
|
||||
* Coordinates of the mousedown event that caused this menu to open. Used to
|
||||
* prevent the consequent mouseup event due to a simple click from activating
|
||||
* a menu item immediately.
|
||||
* @type {?Blockly.utils.Coordinate}
|
||||
* @type {?Coordinate}
|
||||
* @package
|
||||
*/
|
||||
this.openingCoords = null;
|
||||
@@ -49,42 +51,42 @@ Blockly.Menu = function() {
|
||||
/**
|
||||
* This is the element that we will listen to the real focus events on.
|
||||
* A value of null means no menu item is highlighted.
|
||||
* @type {?Blockly.MenuItem}
|
||||
* @type {?MenuItem}
|
||||
* @private
|
||||
*/
|
||||
this.highlightedItem_ = null;
|
||||
|
||||
/**
|
||||
* Mouse over event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.mouseOverHandler_ = null;
|
||||
|
||||
/**
|
||||
* Click event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.clickHandler_ = null;
|
||||
|
||||
/**
|
||||
* Mouse enter event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.mouseEnterHandler_ = null;
|
||||
|
||||
/**
|
||||
* Mouse leave event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.mouseLeaveHandler_ = null;
|
||||
|
||||
/**
|
||||
* Key down event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.onKeyDownHandler_ = null;
|
||||
@@ -98,7 +100,7 @@ Blockly.Menu = function() {
|
||||
|
||||
/**
|
||||
* ARIA name for this menu.
|
||||
* @type {?Blockly.utils.aria.Role}
|
||||
* @type {?aria.Role}
|
||||
* @private
|
||||
*/
|
||||
this.roleName_ = null;
|
||||
@@ -107,9 +109,9 @@ Blockly.Menu = function() {
|
||||
|
||||
/**
|
||||
* Add a new menu item to the bottom of this menu.
|
||||
* @param {!Blockly.MenuItem} menuItem Menu item to append.
|
||||
* @param {!MenuItem} menuItem Menu item to append.
|
||||
*/
|
||||
Blockly.Menu.prototype.addChild = function(menuItem) {
|
||||
Menu.prototype.addChild = function(menuItem) {
|
||||
this.menuItems_.push(menuItem);
|
||||
};
|
||||
|
||||
@@ -117,32 +119,33 @@ Blockly.Menu.prototype.addChild = function(menuItem) {
|
||||
* Creates the menu DOM.
|
||||
* @param {!Element} container Element upon which to append this menu.
|
||||
*/
|
||||
Blockly.Menu.prototype.render = function(container) {
|
||||
var element = /** @type {!HTMLDivElement} */ (document.createElement('div'));
|
||||
Menu.prototype.render = function(container) {
|
||||
const element =
|
||||
/** @type {!HTMLDivElement} */ (document.createElement('div'));
|
||||
// goog-menu is deprecated, use blocklyMenu. May 2020.
|
||||
element.className = 'blocklyMenu goog-menu blocklyNonSelectable';
|
||||
element.tabIndex = 0;
|
||||
if (this.roleName_) {
|
||||
Blockly.utils.aria.setRole(element, this.roleName_);
|
||||
aria.setRole(element, this.roleName_);
|
||||
}
|
||||
this.element_ = element;
|
||||
|
||||
// Add menu items.
|
||||
for (var i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
|
||||
for (let i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
|
||||
element.appendChild(menuItem.createDom());
|
||||
}
|
||||
|
||||
// Add event handlers.
|
||||
this.mouseOverHandler_ = Blockly.browserEvents.conditionalBind(
|
||||
element, 'mouseover', this, this.handleMouseOver_, true);
|
||||
this.clickHandler_ = Blockly.browserEvents.conditionalBind(
|
||||
element, 'click', this, this.handleClick_, true);
|
||||
this.mouseEnterHandler_ = Blockly.browserEvents.conditionalBind(
|
||||
this.mouseOverHandler_ =
|
||||
browserEvents.conditionalBind(element, 'mouseover', this, this.handleMouseOver_, true);
|
||||
this.clickHandler_ =
|
||||
browserEvents.conditionalBind(element, 'click', this, this.handleClick_, true);
|
||||
this.mouseEnterHandler_ = browserEvents.conditionalBind(
|
||||
element, 'mouseenter', this, this.handleMouseEnter_, true);
|
||||
this.mouseLeaveHandler_ = Blockly.browserEvents.conditionalBind(
|
||||
this.mouseLeaveHandler_ = browserEvents.conditionalBind(
|
||||
element, 'mouseleave', this, this.handleMouseLeave_, true);
|
||||
this.onKeyDownHandler_ = Blockly.browserEvents.conditionalBind(
|
||||
element, 'keydown', this, this.handleKeyEvent_);
|
||||
this.onKeyDownHandler_ =
|
||||
browserEvents.conditionalBind(element, 'keydown', this, this.handleKeyEvent_);
|
||||
|
||||
container.appendChild(element);
|
||||
};
|
||||
@@ -152,7 +155,7 @@ Blockly.Menu.prototype.render = function(container) {
|
||||
* @return {?Element} The DOM element.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Menu.prototype.getElement = function() {
|
||||
Menu.prototype.getElement = function() {
|
||||
return this.element_;
|
||||
};
|
||||
|
||||
@@ -160,11 +163,11 @@ Blockly.Menu.prototype.getElement = function() {
|
||||
* Focus the menu element.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Menu.prototype.focus = function() {
|
||||
var el = this.getElement();
|
||||
Menu.prototype.focus = function() {
|
||||
const el = this.getElement();
|
||||
if (el) {
|
||||
el.focus({preventScroll:true});
|
||||
Blockly.utils.dom.addClass(el, 'blocklyFocused');
|
||||
el.focus({preventScroll: true});
|
||||
dom.addClass(el, 'blocklyFocused');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -172,51 +175,51 @@ Blockly.Menu.prototype.focus = function() {
|
||||
* Blur the menu element.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.blur_ = function() {
|
||||
var el = this.getElement();
|
||||
Menu.prototype.blur_ = function() {
|
||||
const el = this.getElement();
|
||||
if (el) {
|
||||
el.blur();
|
||||
Blockly.utils.dom.removeClass(el, 'blocklyFocused');
|
||||
dom.removeClass(el, 'blocklyFocused');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the menu accessibility role.
|
||||
* @param {!Blockly.utils.aria.Role} roleName role name.
|
||||
* @param {!aria.Role} roleName role name.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Menu.prototype.setRole = function(roleName) {
|
||||
Menu.prototype.setRole = function(roleName) {
|
||||
this.roleName_ = roleName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispose of this menu.
|
||||
*/
|
||||
Blockly.Menu.prototype.dispose = function() {
|
||||
Menu.prototype.dispose = function() {
|
||||
// Remove event handlers.
|
||||
if (this.mouseOverHandler_) {
|
||||
Blockly.browserEvents.unbind(this.mouseOverHandler_);
|
||||
browserEvents.unbind(this.mouseOverHandler_);
|
||||
this.mouseOverHandler_ = null;
|
||||
}
|
||||
if (this.clickHandler_) {
|
||||
Blockly.browserEvents.unbind(this.clickHandler_);
|
||||
browserEvents.unbind(this.clickHandler_);
|
||||
this.clickHandler_ = null;
|
||||
}
|
||||
if (this.mouseEnterHandler_) {
|
||||
Blockly.browserEvents.unbind(this.mouseEnterHandler_);
|
||||
browserEvents.unbind(this.mouseEnterHandler_);
|
||||
this.mouseEnterHandler_ = null;
|
||||
}
|
||||
if (this.mouseLeaveHandler_) {
|
||||
Blockly.browserEvents.unbind(this.mouseLeaveHandler_);
|
||||
browserEvents.unbind(this.mouseLeaveHandler_);
|
||||
this.mouseLeaveHandler_ = null;
|
||||
}
|
||||
if (this.onKeyDownHandler_) {
|
||||
Blockly.browserEvents.unbind(this.onKeyDownHandler_);
|
||||
browserEvents.unbind(this.onKeyDownHandler_);
|
||||
this.onKeyDownHandler_ = null;
|
||||
}
|
||||
|
||||
// Remove menu items.
|
||||
for (var i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
|
||||
for (let i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
|
||||
menuItem.dispose();
|
||||
}
|
||||
this.element_ = null;
|
||||
@@ -228,19 +231,19 @@ Blockly.Menu.prototype.dispose = function() {
|
||||
* Returns the child menu item that owns the given DOM element,
|
||||
* or null if no such menu item is found.
|
||||
* @param {Element} elem DOM element whose owner is to be returned.
|
||||
* @return {?Blockly.MenuItem} Menu item for which the DOM element belongs to.
|
||||
* @return {?MenuItem} Menu item for which the DOM element belongs to.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.getMenuItem_ = function(elem) {
|
||||
var menuElem = this.getElement();
|
||||
Menu.prototype.getMenuItem_ = function(elem) {
|
||||
const menuElem = this.getElement();
|
||||
// Node might be the menu border (resulting in no associated menu item), or
|
||||
// a menu item's div, or some element within the menu item.
|
||||
// Walk up parents until one meets either the menu's root element, or
|
||||
// a menu item's div.
|
||||
while (elem && elem != menuElem) {
|
||||
if (Blockly.utils.dom.hasClass(elem, 'blocklyMenuItem')) {
|
||||
if (dom.hasClass(elem, 'blocklyMenuItem')) {
|
||||
// Having found a menu item's div, locate that menu item in this menu.
|
||||
for (var i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
|
||||
for (let i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
|
||||
if (menuItem.getElement() == elem) {
|
||||
return menuItem;
|
||||
}
|
||||
@@ -255,11 +258,11 @@ Blockly.Menu.prototype.getMenuItem_ = function(elem) {
|
||||
|
||||
/**
|
||||
* Highlights the given menu item, or clears highlighting if null.
|
||||
* @param {?Blockly.MenuItem} item Item to highlight, or null.
|
||||
* @param {?MenuItem} item Item to highlight, or null.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Menu.prototype.setHighlighted = function(item) {
|
||||
var currentHighlighted = this.highlightedItem_;
|
||||
Menu.prototype.setHighlighted = function(item) {
|
||||
const currentHighlighted = this.highlightedItem_;
|
||||
if (currentHighlighted) {
|
||||
currentHighlighted.setHighlighted(false);
|
||||
this.highlightedItem_ = null;
|
||||
@@ -269,12 +272,11 @@ Blockly.Menu.prototype.setHighlighted = function(item) {
|
||||
this.highlightedItem_ = item;
|
||||
// Bring the highlighted item into view. This has no effect if the menu is
|
||||
// not scrollable.
|
||||
var el = /** @type {!Element} */ (this.getElement());
|
||||
Blockly.utils.style.scrollIntoContainerView(
|
||||
const el = /** @type {!Element} */ (this.getElement());
|
||||
style.scrollIntoContainerView(
|
||||
/** @type {!Element} */ (item.getElement()), el);
|
||||
|
||||
Blockly.utils.aria.setState(el, Blockly.utils.aria.State.ACTIVEDESCENDANT,
|
||||
item.getId());
|
||||
aria.setState(el, aria.State.ACTIVEDESCENDANT, item.getId());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -283,8 +285,8 @@ Blockly.Menu.prototype.setHighlighted = function(item) {
|
||||
* highlighted).
|
||||
* @package
|
||||
*/
|
||||
Blockly.Menu.prototype.highlightNext = function() {
|
||||
var index = this.menuItems_.indexOf(this.highlightedItem_);
|
||||
Menu.prototype.highlightNext = function() {
|
||||
const index = this.menuItems_.indexOf(this.highlightedItem_);
|
||||
this.highlightHelper_(index, 1);
|
||||
};
|
||||
|
||||
@@ -293,8 +295,8 @@ Blockly.Menu.prototype.highlightNext = function() {
|
||||
* currently highlighted).
|
||||
* @package
|
||||
*/
|
||||
Blockly.Menu.prototype.highlightPrevious = function() {
|
||||
var index = this.menuItems_.indexOf(this.highlightedItem_);
|
||||
Menu.prototype.highlightPrevious = function() {
|
||||
const index = this.menuItems_.indexOf(this.highlightedItem_);
|
||||
this.highlightHelper_(index < 0 ? this.menuItems_.length : index, -1);
|
||||
};
|
||||
|
||||
@@ -302,7 +304,7 @@ Blockly.Menu.prototype.highlightPrevious = function() {
|
||||
* Highlights the first highlightable item.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.highlightFirst_ = function() {
|
||||
Menu.prototype.highlightFirst_ = function() {
|
||||
this.highlightHelper_(-1, 1);
|
||||
};
|
||||
|
||||
@@ -310,7 +312,7 @@ Blockly.Menu.prototype.highlightFirst_ = function() {
|
||||
* Highlights the last highlightable item.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.highlightLast_ = function() {
|
||||
Menu.prototype.highlightLast_ = function() {
|
||||
this.highlightHelper_(this.menuItems_.length, -1);
|
||||
};
|
||||
|
||||
@@ -321,9 +323,9 @@ Blockly.Menu.prototype.highlightLast_ = function() {
|
||||
* @param {number} delta Step direction: 1 to go down, -1 to go up.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.highlightHelper_ = function(startIndex, delta) {
|
||||
var index = startIndex + delta;
|
||||
var menuItem;
|
||||
Menu.prototype.highlightHelper_ = function(startIndex, delta) {
|
||||
let index = startIndex + delta;
|
||||
let menuItem;
|
||||
while ((menuItem = this.menuItems_[index])) {
|
||||
if (menuItem.isEnabled()) {
|
||||
this.setHighlighted(menuItem);
|
||||
@@ -340,8 +342,8 @@ Blockly.Menu.prototype.highlightHelper_ = function(startIndex, delta) {
|
||||
* @param {!Event} e Mouse event to handle.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.handleMouseOver_ = function(e) {
|
||||
var menuItem = this.getMenuItem_(/** @type {Element} */ (e.target));
|
||||
Menu.prototype.handleMouseOver_ = function(e) {
|
||||
const menuItem = this.getMenuItem_(/** @type {Element} */ (e.target));
|
||||
|
||||
if (menuItem) {
|
||||
if (menuItem.isEnabled()) {
|
||||
@@ -359,13 +361,13 @@ Blockly.Menu.prototype.handleMouseOver_ = function(e) {
|
||||
* @param {!Event} e Click event to handle.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.handleClick_ = function(e) {
|
||||
var oldCoords = this.openingCoords;
|
||||
Menu.prototype.handleClick_ = function(e) {
|
||||
const oldCoords = this.openingCoords;
|
||||
// Clear out the saved opening coords immediately so they're not used twice.
|
||||
this.openingCoords = null;
|
||||
if (oldCoords && typeof e.clientX == 'number') {
|
||||
var newCoords = new Blockly.utils.Coordinate(e.clientX, e.clientY);
|
||||
if (Blockly.utils.Coordinate.distance(oldCoords, newCoords) < 1) {
|
||||
const newCoords = new Coordinate(e.clientX, e.clientY);
|
||||
if (Coordinate.distance(oldCoords, newCoords) < 1) {
|
||||
// This menu was opened by a mousedown and we're handling the consequent
|
||||
// click event. The coords haven't changed, meaning this was the same
|
||||
// opening event. Don't do the usual behavior because the menu just popped
|
||||
@@ -374,7 +376,7 @@ Blockly.Menu.prototype.handleClick_ = function(e) {
|
||||
}
|
||||
}
|
||||
|
||||
var menuItem = this.getMenuItem_(/** @type {Element} */ (e.target));
|
||||
const menuItem = this.getMenuItem_(/** @type {Element} */ (e.target));
|
||||
if (menuItem) {
|
||||
menuItem.performAction();
|
||||
}
|
||||
@@ -385,7 +387,7 @@ Blockly.Menu.prototype.handleClick_ = function(e) {
|
||||
* @param {!Event} _e Mouse event to handle.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.handleMouseEnter_ = function(_e) {
|
||||
Menu.prototype.handleMouseEnter_ = function(_e) {
|
||||
this.focus();
|
||||
};
|
||||
|
||||
@@ -394,7 +396,7 @@ Blockly.Menu.prototype.handleMouseEnter_ = function(_e) {
|
||||
* @param {!Event} _e Mouse event to handle.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.handleMouseLeave_ = function(_e) {
|
||||
Menu.prototype.handleMouseLeave_ = function(_e) {
|
||||
if (this.getElement()) {
|
||||
this.blur_();
|
||||
this.setHighlighted(null);
|
||||
@@ -409,7 +411,7 @@ Blockly.Menu.prototype.handleMouseLeave_ = function(_e) {
|
||||
* @param {!Event} e Key event to handle.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.handleKeyEvent_ = function(e) {
|
||||
Menu.prototype.handleKeyEvent_ = function(e) {
|
||||
if (!this.menuItems_.length) {
|
||||
// Empty menu.
|
||||
return;
|
||||
@@ -419,30 +421,30 @@ Blockly.Menu.prototype.handleKeyEvent_ = function(e) {
|
||||
return;
|
||||
}
|
||||
|
||||
var highlighted = this.highlightedItem_;
|
||||
const highlighted = this.highlightedItem_;
|
||||
switch (e.keyCode) {
|
||||
case Blockly.utils.KeyCodes.ENTER:
|
||||
case Blockly.utils.KeyCodes.SPACE:
|
||||
case KeyCodes.ENTER:
|
||||
case KeyCodes.SPACE:
|
||||
if (highlighted) {
|
||||
highlighted.performAction();
|
||||
}
|
||||
break;
|
||||
|
||||
case Blockly.utils.KeyCodes.UP:
|
||||
case KeyCodes.UP:
|
||||
this.highlightPrevious();
|
||||
break;
|
||||
|
||||
case Blockly.utils.KeyCodes.DOWN:
|
||||
case KeyCodes.DOWN:
|
||||
this.highlightNext();
|
||||
break;
|
||||
|
||||
case Blockly.utils.KeyCodes.PAGE_UP:
|
||||
case Blockly.utils.KeyCodes.HOME:
|
||||
case KeyCodes.PAGE_UP:
|
||||
case KeyCodes.HOME:
|
||||
this.highlightFirst_();
|
||||
break;
|
||||
|
||||
case Blockly.utils.KeyCodes.PAGE_DOWN:
|
||||
case Blockly.utils.KeyCodes.END:
|
||||
case KeyCodes.PAGE_DOWN:
|
||||
case KeyCodes.END:
|
||||
this.highlightLast_();
|
||||
break;
|
||||
|
||||
@@ -457,13 +459,16 @@ Blockly.Menu.prototype.handleKeyEvent_ = function(e) {
|
||||
|
||||
/**
|
||||
* Get the size of a rendered menu.
|
||||
* @return {!Blockly.utils.Size} Object with width and height properties.
|
||||
* @return {!Size} Object with width and height properties.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Menu.prototype.getSize = function() {
|
||||
var menuDom = this.getElement();
|
||||
var menuSize = Blockly.utils.style.getSize(/** @type {!Element} */ (menuDom));
|
||||
Menu.prototype.getSize = function() {
|
||||
const menuDom = this.getElement();
|
||||
const menuSize = style.getSize(/** @type {!Element} */
|
||||
(menuDom));
|
||||
// Recalculate height for the total content, not only box height.
|
||||
menuSize.height = menuDom.scrollHeight;
|
||||
return menuSize;
|
||||
};
|
||||
|
||||
exports = Menu;
|
||||
|
||||
@@ -20,6 +20,7 @@ goog.require('Blockly.Events.BlockChange');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BubbleOpen');
|
||||
goog.require('Blockly.Icon');
|
||||
goog.require('Blockly.internalConstants');
|
||||
goog.require('Blockly.Options');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.dom');
|
||||
@@ -444,7 +445,7 @@ Blockly.Mutator.prototype.workspaceChanged_ = function(e) {
|
||||
Blockly.Events.setGroup(group);
|
||||
block.bumpNeighbours();
|
||||
Blockly.Events.setGroup(false);
|
||||
}, Blockly.BUMP_DELAY);
|
||||
}, Blockly.internalConstants.BUMP_DELAY);
|
||||
}
|
||||
|
||||
// Don't update the bubble until the drag has ended, to avoid moving blocks
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
|
||||
goog.provide('Blockly.Names');
|
||||
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.internalConstants');
|
||||
goog.require('Blockly.Msg');
|
||||
|
||||
goog.requireType('Blockly.VariableMap');
|
||||
@@ -77,7 +76,7 @@ Blockly.Names.prototype.setVariableMap = function(map) {
|
||||
/**
|
||||
* Get the name for a user-defined variable, based on its ID.
|
||||
* This should only be used for variables of realm
|
||||
* Blockly.VARIABLE_CATEGORY_NAME.
|
||||
* Blockly.internalConstants.VARIABLE_CATEGORY_NAME.
|
||||
* @param {string} id The ID to look up in the variable map.
|
||||
* @return {?string} The name of the referenced variable, or null if there was
|
||||
* no variable map or the variable was not found in the map.
|
||||
@@ -106,7 +105,8 @@ Blockly.Names.prototype.getNameForUserVariable_ = function(id) {
|
||||
Blockly.Names.prototype.populateVariables = function(workspace) {
|
||||
var variables = Blockly.Variables.allUsedVarModels(workspace);
|
||||
for (var i = 0; i < variables.length; i++) {
|
||||
this.getName(variables[i].getId(), Blockly.VARIABLE_CATEGORY_NAME);
|
||||
this.getName(
|
||||
variables[i].getId(), Blockly.internalConstants.VARIABLE_CATEGORY_NAME);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -119,7 +119,8 @@ Blockly.Names.prototype.populateProcedures = function(workspace) {
|
||||
// Flatten the return vs no-return procedure lists.
|
||||
procedures = procedures[0].concat(procedures[1]);
|
||||
for (var i = 0; i < procedures.length; i++) {
|
||||
this.getName(procedures[i][0], Blockly.PROCEDURE_CATEGORY_NAME);
|
||||
this.getName(
|
||||
procedures[i][0], Blockly.internalConstants.PROCEDURE_CATEGORY_NAME);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -133,7 +134,7 @@ Blockly.Names.prototype.populateProcedures = function(workspace) {
|
||||
*/
|
||||
Blockly.Names.prototype.getName = function(nameOrId, realm) {
|
||||
var name = nameOrId;
|
||||
if (realm == Blockly.VARIABLE_CATEGORY_NAME) {
|
||||
if (realm == Blockly.internalConstants.VARIABLE_CATEGORY_NAME) {
|
||||
var varName = this.getNameForUserVariable_(nameOrId);
|
||||
if (varName) {
|
||||
// Successful ID lookup.
|
||||
@@ -142,7 +143,7 @@ Blockly.Names.prototype.getName = function(nameOrId, realm) {
|
||||
}
|
||||
var normalizedName = name.toLowerCase();
|
||||
|
||||
var isVar = realm == Blockly.VARIABLE_CATEGORY_NAME ||
|
||||
var isVar = realm == Blockly.internalConstants.VARIABLE_CATEGORY_NAME ||
|
||||
realm == Blockly.Names.DEVELOPER_VARIABLE_TYPE;
|
||||
|
||||
var prefix = isVar ? this.variablePrefix_ : '';
|
||||
@@ -189,7 +190,7 @@ Blockly.Names.prototype.getDistinctName = function(name, realm) {
|
||||
}
|
||||
safeName += i;
|
||||
this.dbReverse_[safeName] = true;
|
||||
var isVar = realm == Blockly.VARIABLE_CATEGORY_NAME ||
|
||||
var isVar = realm == Blockly.internalConstants.VARIABLE_CATEGORY_NAME ||
|
||||
realm == Blockly.Names.DEVELOPER_VARIABLE_TYPE;
|
||||
var prefix = isVar ? this.variablePrefix_ : '';
|
||||
return prefix + safeName;
|
||||
|
||||
@@ -17,12 +17,11 @@
|
||||
goog.provide('Blockly.Procedures');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.Events');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockChange');
|
||||
goog.require('Blockly.Field');
|
||||
goog.require('Blockly.internalConstants');
|
||||
goog.require('Blockly.Msg');
|
||||
goog.require('Blockly.Names');
|
||||
goog.require('Blockly.utils.xml');
|
||||
@@ -37,9 +36,10 @@ goog.requireType('Blockly.WorkspaceSvg');
|
||||
/**
|
||||
* Constant to separate procedure names from variables and generated functions
|
||||
* when running generators.
|
||||
* @deprecated Use Blockly.PROCEDURE_CATEGORY_NAME
|
||||
* @deprecated Use Blockly.internalConstants.PROCEDURE_CATEGORY_NAME
|
||||
*/
|
||||
Blockly.Procedures.NAME_TYPE = Blockly.PROCEDURE_CATEGORY_NAME;
|
||||
Blockly.Procedures.NAME_TYPE =
|
||||
Blockly.internalConstants.PROCEDURE_CATEGORY_NAME;
|
||||
|
||||
/**
|
||||
* The default argument for a procedures_mutatorarg block.
|
||||
|
||||
@@ -14,8 +14,7 @@ goog.provide('Blockly.RenderedConnection');
|
||||
|
||||
goog.require('Blockly.Connection');
|
||||
goog.require('Blockly.connectionTypes');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.internalConstants');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.utils.deprecation');
|
||||
@@ -51,8 +50,9 @@ Blockly.RenderedConnection = function(source, type) {
|
||||
* @const {!Blockly.ConnectionDB}
|
||||
* @private
|
||||
*/
|
||||
this.dbOpposite_ = source.workspace
|
||||
.connectionDBList[Blockly.OPPOSITE_TYPE[type]];
|
||||
this.dbOpposite_ =
|
||||
source.workspace
|
||||
.connectionDBList[Blockly.internalConstants.OPPOSITE_TYPE[type]];
|
||||
|
||||
/**
|
||||
* Workspace units, (0, 0) is top left of block.
|
||||
@@ -173,17 +173,23 @@ Blockly.RenderedConnection.prototype.bumpAwayFrom = function(staticConnection) {
|
||||
// Raise it to the top for extra visibility.
|
||||
var selected = Blockly.selected == rootBlock;
|
||||
selected || rootBlock.addSelect();
|
||||
var dx = (staticConnection.x + Blockly.SNAP_RADIUS +
|
||||
Math.floor(Math.random() * Blockly.BUMP_RANDOMNESS)) - this.x;
|
||||
var dy = (staticConnection.y + Blockly.SNAP_RADIUS +
|
||||
Math.floor(Math.random() * Blockly.BUMP_RANDOMNESS)) - this.y;
|
||||
var dx =
|
||||
(staticConnection.x + Blockly.internalConstants.SNAP_RADIUS +
|
||||
Math.floor(Math.random() * Blockly.internalConstants.BUMP_RANDOMNESS)) -
|
||||
this.x;
|
||||
var dy =
|
||||
(staticConnection.y + Blockly.internalConstants.SNAP_RADIUS +
|
||||
Math.floor(Math.random() * Blockly.internalConstants.BUMP_RANDOMNESS)) -
|
||||
this.y;
|
||||
if (reverse) {
|
||||
// When reversing a bump due to an uneditable block, bump up.
|
||||
dy = -dy;
|
||||
}
|
||||
if (rootBlock.RTL) {
|
||||
dx = (staticConnection.x - Blockly.SNAP_RADIUS -
|
||||
Math.floor(Math.random() * Blockly.BUMP_RANDOMNESS)) - this.x;
|
||||
dx = (staticConnection.x - Blockly.internalConstants.SNAP_RADIUS -
|
||||
Math.floor(
|
||||
Math.random() * Blockly.internalConstants.BUMP_RANDOMNESS)) -
|
||||
this.x;
|
||||
}
|
||||
rootBlock.moveBy(dx, dy);
|
||||
selected || rootBlock.removeSelect();
|
||||
@@ -466,7 +472,7 @@ Blockly.RenderedConnection.prototype.onFailedConnect =
|
||||
this.bumpAwayFrom(otherConnection);
|
||||
Blockly.Events.setGroup(false);
|
||||
}
|
||||
}.bind(this), Blockly.BUMP_DELAY);
|
||||
}.bind(this), Blockly.internalConstants.BUMP_DELAY);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -10,21 +10,20 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.blockRendering.ConstantProvider');
|
||||
goog.module('Blockly.blockRendering.ConstantProvider');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.connectionTypes');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.colour');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
goog.require('Blockly.utils.svgPaths');
|
||||
goog.require('Blockly.utils.userAgent');
|
||||
|
||||
goog.requireType('Blockly.blockRendering.Debug');
|
||||
goog.requireType('Blockly.RenderedConnection');
|
||||
goog.requireType('Blockly.Theme');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const RenderedConnection = goog.requireType('Blockly.RenderedConnection');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Theme = goog.requireType('Blockly.Theme');
|
||||
const colour = goog.require('Blockly.utils.colour');
|
||||
const connectionTypes = goog.require('Blockly.connectionTypes');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const svgPaths = goog.require('Blockly.utils.svgPaths');
|
||||
const userAgent = goog.require('Blockly.utils.userAgent');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
@@ -32,8 +31,7 @@ goog.requireType('Blockly.Theme');
|
||||
* @constructor
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider = function() {
|
||||
|
||||
const ConstantProvider = function() {
|
||||
/**
|
||||
* The size of an empty spacer.
|
||||
* @type {number}
|
||||
@@ -216,15 +214,15 @@ Blockly.blockRendering.ConstantProvider = function() {
|
||||
this.EXTERNAL_VALUE_INPUT_PADDING = 2;
|
||||
|
||||
/**
|
||||
* The height of an empty statement input. Note that in the old rendering this
|
||||
* varies slightly depending on whether the block has external or inline inputs.
|
||||
* In the new rendering this is consistent. It seems unlikely that the old
|
||||
* behaviour was intentional.
|
||||
* The height of an empty statement input. Note that in the old rendering
|
||||
* this varies slightly depending on whether the block has external or inline
|
||||
* inputs. In the new rendering this is consistent. It seems unlikely that
|
||||
* the old behaviour was intentional.
|
||||
* @type {number}
|
||||
*/
|
||||
this.EMPTY_STATEMENT_INPUT_HEIGHT = this.MIN_BLOCK_HEIGHT;
|
||||
|
||||
this.START_POINT = Blockly.utils.svgPaths.moveBy(0, 0);
|
||||
this.START_POINT = svgPaths.moveBy(0, 0);
|
||||
|
||||
/**
|
||||
* Height of SVG path for jagged teeth at the end of collapsed blocks.
|
||||
@@ -305,8 +303,7 @@ Blockly.blockRendering.ConstantProvider = function() {
|
||||
* A field's text element's dominant baseline.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.FIELD_TEXT_BASELINE_CENTER =
|
||||
!Blockly.utils.userAgent.IE && !Blockly.utils.userAgent.EDGE;
|
||||
this.FIELD_TEXT_BASELINE_CENTER = !userAgent.IE && !userAgent.EDGE;
|
||||
|
||||
/**
|
||||
* A dropdown field's border rect height.
|
||||
@@ -351,17 +348,17 @@ Blockly.blockRendering.ConstantProvider = function() {
|
||||
* @type {string}
|
||||
*/
|
||||
this.FIELD_DROPDOWN_SVG_ARROW_DATAURI =
|
||||
'data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllci' +
|
||||
'AxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMi43MSIgaG' +
|
||||
'VpZ2h0PSI4Ljc5IiB2aWV3Qm94PSIwIDAgMTIuNzEgOC43OSI+PHRpdGxlPmRyb3Bkb3duLW' +
|
||||
'Fycm93PC90aXRsZT48ZyBvcGFjaXR5PSIwLjEiPjxwYXRoIGQ9Ik0xMi43MSwyLjQ0QTIuND' +
|
||||
'EsMi40MSwwLDAsMSwxMiw0LjE2TDguMDgsOC4wOGEyLjQ1LDIuNDUsMCwwLDEtMy40NSwwTD' +
|
||||
'AuNzIsNC4xNkEyLjQyLDIuNDIsMCwwLDEsMCwyLjQ0LDIuNDgsMi40OCwwLDAsMSwuNzEuNz' +
|
||||
'FDMSwwLjQ3LDEuNDMsMCw2LjM2LDBTMTEuNzUsMC40NiwxMiwuNzFBMi40NCwyLjQ0LDAsMC' +
|
||||
'wxLDEyLjcxLDIuNDRaIiBmaWxsPSIjMjMxZjIwIi8+PC9nPjxwYXRoIGQ9Ik02LjM2LDcuNz' +
|
||||
'lhMS40MywxLjQzLDAsMCwxLTEtLjQyTDEuNDIsMy40NWExLjQ0LDEuNDQsMCwwLDEsMC0yYz' +
|
||||
'AuNTYtLjU2LDkuMzEtMC41Niw5Ljg3LDBhMS40NCwxLjQ0LDAsMCwxLDAsMkw3LjM3LDcuMz' +
|
||||
'dBMS40MywxLjQzLDAsMCwxLDYuMzYsNy43OVoiIGZpbGw9IiNmZmYiLz48L3N2Zz4=';
|
||||
'data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllci' +
|
||||
'AxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMi43MSIgaG' +
|
||||
'VpZ2h0PSI4Ljc5IiB2aWV3Qm94PSIwIDAgMTIuNzEgOC43OSI+PHRpdGxlPmRyb3Bkb3duLW' +
|
||||
'Fycm93PC90aXRsZT48ZyBvcGFjaXR5PSIwLjEiPjxwYXRoIGQ9Ik0xMi43MSwyLjQ0QTIuND' +
|
||||
'EsMi40MSwwLDAsMSwxMiw0LjE2TDguMDgsOC4wOGEyLjQ1LDIuNDUsMCwwLDEtMy40NSwwTD' +
|
||||
'AuNzIsNC4xNkEyLjQyLDIuNDIsMCwwLDEsMCwyLjQ0LDIuNDgsMi40OCwwLDAsMSwuNzEuNz' +
|
||||
'FDMSwwLjQ3LDEuNDMsMCw2LjM2LDBTMTEuNzUsMC40NiwxMiwuNzFBMi40NCwyLjQ0LDAsMC' +
|
||||
'wxLDEyLjcxLDIuNDRaIiBmaWxsPSIjMjMxZjIwIi8+PC9nPjxwYXRoIGQ9Ik02LjM2LDcuNz' +
|
||||
'lhMS40MywxLjQzLDAsMCwxLTEtLjQyTDEuNDIsMy40NWExLjQ0LDEuNDQsMCwwLDEsMC0yYz' +
|
||||
'AuNTYtLjU2LDkuMzEtMC41Niw5Ljg3LDBhMS40NCwxLjQ0LDAsMCwxLDAsMkw3LjM3LDcuMz' +
|
||||
'dBMS40MywxLjQzLDAsMCwxLDYuMzYsNy43OVoiIGZpbGw9IiNmZmYiLz48L3N2Zz4=';
|
||||
|
||||
/**
|
||||
* Whether or not to show a box shadow around the widget div. This is only a
|
||||
@@ -403,6 +400,14 @@ Blockly.blockRendering.ConstantProvider = function() {
|
||||
*/
|
||||
this.randomIdentifier = String(Math.random()).substring(2);
|
||||
|
||||
/**
|
||||
* The defs tag that contains all filters and patterns for this Blockly
|
||||
* instance.
|
||||
* @type {?SVGElement}
|
||||
* @private
|
||||
*/
|
||||
this.defs_ = null;
|
||||
|
||||
/**
|
||||
* The ID of the emboss filter, or the empty string if no filter is set.
|
||||
* @type {string}
|
||||
@@ -527,18 +532,14 @@ Blockly.blockRendering.ConstantProvider = function() {
|
||||
* Enum for connection shapes.
|
||||
* @enum {number}
|
||||
*/
|
||||
this.SHAPES = {
|
||||
PUZZLE: 1,
|
||||
NOTCH: 2
|
||||
};
|
||||
this.SHAPES = {PUZZLE: 1, NOTCH: 2};
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize shape objects based on the constants set in the constructor.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.init = function() {
|
||||
|
||||
ConstantProvider.prototype.init = function() {
|
||||
/**
|
||||
* An object containing sizing and path information about collapsed block
|
||||
* indicators.
|
||||
@@ -579,21 +580,19 @@ Blockly.blockRendering.ConstantProvider.prototype.init = function() {
|
||||
|
||||
/**
|
||||
* Refresh constants properties that depend on the theme.
|
||||
* @param {!Blockly.Theme} theme The current workspace theme.
|
||||
* @param {!Theme} theme The current workspace theme.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.setTheme = function(
|
||||
theme) {
|
||||
|
||||
ConstantProvider.prototype.setTheme = function(theme) {
|
||||
/**
|
||||
* The block styles map.
|
||||
* @type {Object<string, !Blockly.Theme.BlockStyle>}
|
||||
* @type {Object<string, !Theme.BlockStyle>}
|
||||
* @package
|
||||
*/
|
||||
this.blockStyles = Object.create(null);
|
||||
|
||||
var blockStyles = theme.blockStyles;
|
||||
for (var key in blockStyles) {
|
||||
const blockStyles = theme.blockStyles;
|
||||
for (const key in blockStyles) {
|
||||
this.blockStyles[key] = this.validatedBlockStyle_(blockStyles[key]);
|
||||
}
|
||||
|
||||
@@ -602,39 +601,38 @@ Blockly.blockRendering.ConstantProvider.prototype.setTheme = function(
|
||||
|
||||
/**
|
||||
* Sets dynamic properties that depend on other values or theme properties.
|
||||
* @param {!Blockly.Theme} theme The current workspace theme.
|
||||
* @param {!Theme} theme The current workspace theme.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.setDynamicProperties_ =
|
||||
function(theme) {
|
||||
/* eslint-disable indent */
|
||||
ConstantProvider.prototype.setDynamicProperties_ = function(theme) {
|
||||
this.setFontConstants_(theme);
|
||||
this.setComponentConstants_(theme);
|
||||
|
||||
this.ADD_START_HATS = theme.startHats != null ? theme.startHats :
|
||||
this.ADD_START_HATS;
|
||||
}; /* eslint-enable indent */
|
||||
this.ADD_START_HATS =
|
||||
theme.startHats != null ? theme.startHats : this.ADD_START_HATS;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set constants related to fonts.
|
||||
* @param {!Blockly.Theme} theme The current workspace theme.
|
||||
* @param {!Theme} theme The current workspace theme.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.setFontConstants_ = function(
|
||||
theme) {
|
||||
ConstantProvider.prototype.setFontConstants_ = function(theme) {
|
||||
this.FIELD_TEXT_FONTFAMILY =
|
||||
theme.fontStyle && theme.fontStyle['family'] != undefined ?
|
||||
theme.fontStyle['family'] : this.FIELD_TEXT_FONTFAMILY;
|
||||
theme.fontStyle['family'] :
|
||||
this.FIELD_TEXT_FONTFAMILY;
|
||||
this.FIELD_TEXT_FONTWEIGHT =
|
||||
theme.fontStyle && theme.fontStyle['weight'] != undefined ?
|
||||
theme.fontStyle['weight'] : this.FIELD_TEXT_FONTWEIGHT;
|
||||
theme.fontStyle['weight'] :
|
||||
this.FIELD_TEXT_FONTWEIGHT;
|
||||
this.FIELD_TEXT_FONTSIZE =
|
||||
theme.fontStyle && theme.fontStyle['size'] != undefined ?
|
||||
theme.fontStyle['size'] : this.FIELD_TEXT_FONTSIZE;
|
||||
theme.fontStyle['size'] :
|
||||
this.FIELD_TEXT_FONTSIZE;
|
||||
|
||||
var fontMetrics = Blockly.utils.dom.measureFontMetrics('Hg',
|
||||
this.FIELD_TEXT_FONTSIZE + 'pt',
|
||||
this.FIELD_TEXT_FONTWEIGHT,
|
||||
const fontMetrics = dom.measureFontMetrics(
|
||||
'Hg', this.FIELD_TEXT_FONTSIZE + 'pt', this.FIELD_TEXT_FONTWEIGHT,
|
||||
this.FIELD_TEXT_FONTFAMILY);
|
||||
|
||||
this.FIELD_TEXT_HEIGHT = fontMetrics.height;
|
||||
@@ -643,68 +641,60 @@ Blockly.blockRendering.ConstantProvider.prototype.setFontConstants_ = function(
|
||||
|
||||
/**
|
||||
* Set constants from a theme's component styles.
|
||||
* @param {!Blockly.Theme} theme The current workspace theme.
|
||||
* @param {!Theme} theme The current workspace theme.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.setComponentConstants_ =
|
||||
function(theme) {
|
||||
/* eslint-disable indent */
|
||||
this.CURSOR_COLOUR = theme.getComponentStyle('cursorColour') ||
|
||||
this.CURSOR_COLOUR;
|
||||
this.MARKER_COLOUR = theme.getComponentStyle('markerColour') ||
|
||||
this.MARKER_COLOUR;
|
||||
ConstantProvider.prototype.setComponentConstants_ = function(theme) {
|
||||
this.CURSOR_COLOUR =
|
||||
theme.getComponentStyle('cursorColour') || this.CURSOR_COLOUR;
|
||||
this.MARKER_COLOUR =
|
||||
theme.getComponentStyle('markerColour') || this.MARKER_COLOUR;
|
||||
this.INSERTION_MARKER_COLOUR =
|
||||
theme.getComponentStyle('insertionMarkerColour') ||
|
||||
this.INSERTION_MARKER_COLOUR;
|
||||
theme.getComponentStyle('insertionMarkerColour') ||
|
||||
this.INSERTION_MARKER_COLOUR;
|
||||
this.INSERTION_MARKER_OPACITY =
|
||||
Number(theme.getComponentStyle('insertionMarkerOpacity')) ||
|
||||
this.INSERTION_MARKER_OPACITY;
|
||||
}; /* eslint-enable indent */
|
||||
Number(theme.getComponentStyle('insertionMarkerOpacity')) ||
|
||||
this.INSERTION_MARKER_OPACITY;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get or create a block style based on a single colour value. Generate a name
|
||||
* for the style based on the colour.
|
||||
* @param {string} colour #RRGGBB colour string.
|
||||
* @return {{style: !Blockly.Theme.BlockStyle, name: string}} An object
|
||||
* @return {{style: !Theme.BlockStyle, name: string}} An object
|
||||
* containing the style and an autogenerated name for that style.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.getBlockStyleForColour =
|
||||
function(colour) {
|
||||
/* eslint-disable indent */
|
||||
var name = 'auto_' + colour;
|
||||
ConstantProvider.prototype.getBlockStyleForColour = function(colour) {
|
||||
const name = 'auto_' + colour;
|
||||
if (!this.blockStyles[name]) {
|
||||
this.blockStyles[name] = this.createBlockStyle_(colour);
|
||||
}
|
||||
return {style: this.blockStyles[name], name: name};
|
||||
}; /* eslint-enable indent */
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the BlockStyle for the given block style name.
|
||||
* @param {?string} blockStyleName The name of the block style.
|
||||
* @return {!Blockly.Theme.BlockStyle} The named block style, or a default style
|
||||
* @return {!Theme.BlockStyle} The named block style, or a default style
|
||||
* if no style with the given name was found.
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.getBlockStyle = function(
|
||||
blockStyleName) {
|
||||
ConstantProvider.prototype.getBlockStyle = function(blockStyleName) {
|
||||
return this.blockStyles[blockStyleName || ''] ||
|
||||
(blockStyleName && blockStyleName.indexOf('auto_') == 0 ?
|
||||
this.getBlockStyleForColour(blockStyleName.substring(5)).style :
|
||||
this.createBlockStyle_('#000000'));
|
||||
this.getBlockStyleForColour(blockStyleName.substring(5)).style :
|
||||
this.createBlockStyle_('#000000'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a block style object based on the given colour.
|
||||
* @param {string} colour #RRGGBB colour string.
|
||||
* @return {!Blockly.Theme.BlockStyle} A populated block style based on the
|
||||
* @return {!Theme.BlockStyle} A populated block style based on the
|
||||
* given colour.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.createBlockStyle_ = function(
|
||||
colour) {
|
||||
return this.validatedBlockStyle_({
|
||||
'colourPrimary': colour
|
||||
});
|
||||
ConstantProvider.prototype.createBlockStyle_ = function(colour) {
|
||||
return this.validatedBlockStyle_({'colourPrimary': colour});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -717,56 +707,49 @@ Blockly.blockRendering.ConstantProvider.prototype.createBlockStyle_ = function(
|
||||
* hat:(string|undefined)
|
||||
* }} blockStyle A full or partial block style object.
|
||||
|
||||
* @return {!Blockly.Theme.BlockStyle} A full block style object, with all
|
||||
* @return {!Theme.BlockStyle} A full block style object, with all
|
||||
* required properties populated.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.validatedBlockStyle_ =
|
||||
function(blockStyle) {
|
||||
/* eslint-disable indent */
|
||||
ConstantProvider.prototype.validatedBlockStyle_ = function(blockStyle) {
|
||||
// Make a new object with all of the same properties.
|
||||
var valid = /** @type {!Blockly.Theme.BlockStyle} */ ({});
|
||||
const valid = /** @type {!Theme.BlockStyle} */ ({});
|
||||
if (blockStyle) {
|
||||
Blockly.utils.object.mixin(valid, blockStyle);
|
||||
utils.object.mixin(valid, blockStyle);
|
||||
}
|
||||
// Validate required properties.
|
||||
var parsedColour = Blockly.utils.parseBlockColour(
|
||||
valid['colourPrimary'] || '#000');
|
||||
const parsedColour = utils.parseBlockColour(valid['colourPrimary'] || '#000');
|
||||
valid.colourPrimary = parsedColour.hex;
|
||||
valid.colourSecondary = valid['colourSecondary'] ?
|
||||
Blockly.utils.parseBlockColour(valid['colourSecondary']).hex :
|
||||
utils.parseBlockColour(valid['colourSecondary']).hex :
|
||||
this.generateSecondaryColour_(valid.colourPrimary);
|
||||
valid.colourTertiary = valid['colourTertiary'] ?
|
||||
Blockly.utils.parseBlockColour(valid['colourTertiary']).hex :
|
||||
utils.parseBlockColour(valid['colourTertiary']).hex :
|
||||
this.generateTertiaryColour_(valid.colourPrimary);
|
||||
|
||||
valid.hat = valid['hat'] || '';
|
||||
return valid;
|
||||
}; /* eslint-enable indent */
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate a secondary colour from the passed in primary colour.
|
||||
* @param {string} colour Primary colour.
|
||||
* @param {string} inputColour Primary colour.
|
||||
* @return {string} The generated secondary colour.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.generateSecondaryColour_ =
|
||||
function(colour) {
|
||||
/* eslint-disable indent */
|
||||
return Blockly.utils.colour.blend('#fff', colour, 0.6) || colour;
|
||||
}; /* eslint-enable indent */
|
||||
ConstantProvider.prototype.generateSecondaryColour_ = function(inputColour) {
|
||||
return colour.blend('#fff', inputColour, 0.6) || inputColour;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate a tertiary colour from the passed in primary colour.
|
||||
* @param {string} colour Primary colour.
|
||||
* @param {string} inputColour Primary colour.
|
||||
* @return {string} The generated tertiary colour.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.generateTertiaryColour_ =
|
||||
function(colour) {
|
||||
/* eslint-disable indent */
|
||||
return Blockly.utils.colour.blend('#fff', colour, 0.3) || colour;
|
||||
}; /* eslint-enable indent */
|
||||
ConstantProvider.prototype.generateTertiaryColour_ = function(inputColour) {
|
||||
return colour.blend('#fff', inputColour, 0.3) || inputColour;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@@ -774,15 +757,15 @@ Blockly.blockRendering.ConstantProvider.prototype.generateTertiaryColour_ =
|
||||
* Delete all DOM elements that this provider created.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.dispose = function() {
|
||||
ConstantProvider.prototype.dispose = function() {
|
||||
if (this.embossFilter_) {
|
||||
Blockly.utils.dom.removeNode(this.embossFilter_);
|
||||
dom.removeNode(this.embossFilter_);
|
||||
}
|
||||
if (this.disabledPattern_) {
|
||||
Blockly.utils.dom.removeNode(this.disabledPattern_);
|
||||
dom.removeNode(this.disabledPattern_);
|
||||
}
|
||||
if (this.debugFilter_) {
|
||||
Blockly.utils.dom.removeNode(this.debugFilter_);
|
||||
dom.removeNode(this.debugFilter_);
|
||||
}
|
||||
this.cssNode_ = null;
|
||||
};
|
||||
@@ -792,22 +775,15 @@ Blockly.blockRendering.ConstantProvider.prototype.dispose = function() {
|
||||
* collapsed block indicators.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.makeJaggedTeeth = function() {
|
||||
var height = this.JAGGED_TEETH_HEIGHT;
|
||||
var width = this.JAGGED_TEETH_WIDTH;
|
||||
ConstantProvider.prototype.makeJaggedTeeth = function() {
|
||||
const height = this.JAGGED_TEETH_HEIGHT;
|
||||
const width = this.JAGGED_TEETH_WIDTH;
|
||||
|
||||
var mainPath =
|
||||
Blockly.utils.svgPaths.line(
|
||||
[
|
||||
Blockly.utils.svgPaths.point(width, height / 4),
|
||||
Blockly.utils.svgPaths.point(-width * 2, height / 2),
|
||||
Blockly.utils.svgPaths.point(width, height / 4)
|
||||
]);
|
||||
return {
|
||||
height: height,
|
||||
width: width,
|
||||
path: mainPath
|
||||
};
|
||||
const mainPath = svgPaths.line([
|
||||
svgPaths.point(width, height / 4), svgPaths.point(-width * 2, height / 2),
|
||||
svgPaths.point(width, height / 4)
|
||||
]);
|
||||
return {height: height, width: width, path: mainPath};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -815,22 +791,15 @@ Blockly.blockRendering.ConstantProvider.prototype.makeJaggedTeeth = function() {
|
||||
* start hats.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.makeStartHat = function() {
|
||||
var height = this.START_HAT_HEIGHT;
|
||||
var width = this.START_HAT_WIDTH;
|
||||
ConstantProvider.prototype.makeStartHat = function() {
|
||||
const height = this.START_HAT_HEIGHT;
|
||||
const width = this.START_HAT_WIDTH;
|
||||
|
||||
var mainPath =
|
||||
Blockly.utils.svgPaths.curve('c',
|
||||
[
|
||||
Blockly.utils.svgPaths.point(30, -height),
|
||||
Blockly.utils.svgPaths.point(70, -height),
|
||||
Blockly.utils.svgPaths.point(width, 0)
|
||||
]);
|
||||
return {
|
||||
height: height,
|
||||
width: width,
|
||||
path: mainPath
|
||||
};
|
||||
const mainPath = svgPaths.curve('c', [
|
||||
svgPaths.point(30, -height), svgPaths.point(70, -height),
|
||||
svgPaths.point(width, 0)
|
||||
]);
|
||||
return {height: height, width: width, path: mainPath};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -838,9 +807,9 @@ Blockly.blockRendering.ConstantProvider.prototype.makeStartHat = function() {
|
||||
* puzzle tabs.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.makePuzzleTab = function() {
|
||||
var width = this.TAB_WIDTH;
|
||||
var height = this.TAB_HEIGHT;
|
||||
ConstantProvider.prototype.makePuzzleTab = function() {
|
||||
const width = this.TAB_WIDTH;
|
||||
const height = this.TAB_HEIGHT;
|
||||
|
||||
// The main path for the puzzle tab is made out of a few curves (c and s).
|
||||
// Those curves are defined with relative positions. The 'up' and 'down'
|
||||
@@ -848,35 +817,32 @@ Blockly.blockRendering.ConstantProvider.prototype.makePuzzleTab = function() {
|
||||
// are the signs to use to move the cursor in the direction that the path is
|
||||
// being drawn.
|
||||
function makeMainPath(up) {
|
||||
var forward = up ? -1 : 1;
|
||||
var back = -forward;
|
||||
const forward = up ? -1 : 1;
|
||||
const back = -forward;
|
||||
|
||||
var overlap = 2.5;
|
||||
var halfHeight = height / 2;
|
||||
var control1Y = halfHeight + overlap;
|
||||
var control2Y = halfHeight + 0.5;
|
||||
var control3Y = overlap; // 2.5
|
||||
const overlap = 2.5;
|
||||
const halfHeight = height / 2;
|
||||
const control1Y = halfHeight + overlap;
|
||||
const control2Y = halfHeight + 0.5;
|
||||
const control3Y = overlap; // 2.5
|
||||
|
||||
var endPoint1 = Blockly.utils.svgPaths.point(-width, forward * halfHeight);
|
||||
var endPoint2 = Blockly.utils.svgPaths.point(width, forward * halfHeight);
|
||||
const endPoint1 = svgPaths.point(-width, forward * halfHeight);
|
||||
const endPoint2 = svgPaths.point(width, forward * halfHeight);
|
||||
|
||||
return Blockly.utils.svgPaths.curve('c',
|
||||
[
|
||||
Blockly.utils.svgPaths.point(0, forward * control1Y),
|
||||
Blockly.utils.svgPaths.point(-width, back * control2Y),
|
||||
endPoint1
|
||||
]) +
|
||||
Blockly.utils.svgPaths.curve('s',
|
||||
[
|
||||
Blockly.utils.svgPaths.point(width, back * control3Y),
|
||||
endPoint2
|
||||
]);
|
||||
return svgPaths.curve(
|
||||
'c',
|
||||
[
|
||||
svgPaths.point(0, forward * control1Y),
|
||||
svgPaths.point(-width, back * control2Y), endPoint1
|
||||
]) +
|
||||
svgPaths.curve(
|
||||
's', [svgPaths.point(width, back * control3Y), endPoint2]);
|
||||
}
|
||||
|
||||
// c 0,-10 -8,8 -8,-7.5 s 8,2.5 8,-7.5
|
||||
var pathUp = makeMainPath(true);
|
||||
const pathUp = makeMainPath(true);
|
||||
// c 0,10 -8,-8 -8,7.5 s 8,-2.5 8,7.5
|
||||
var pathDown = makeMainPath(false);
|
||||
const pathDown = makeMainPath(false);
|
||||
|
||||
return {
|
||||
type: this.SHAPES.PUZZLE,
|
||||
@@ -892,21 +858,20 @@ Blockly.blockRendering.ConstantProvider.prototype.makePuzzleTab = function() {
|
||||
* notches.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.makeNotch = function() {
|
||||
var width = this.NOTCH_WIDTH;
|
||||
var height = this.NOTCH_HEIGHT;
|
||||
var innerWidth = 3;
|
||||
var outerWidth = (width - innerWidth) / 2;
|
||||
ConstantProvider.prototype.makeNotch = function() {
|
||||
const width = this.NOTCH_WIDTH;
|
||||
const height = this.NOTCH_HEIGHT;
|
||||
const innerWidth = 3;
|
||||
const outerWidth = (width - innerWidth) / 2;
|
||||
function makeMainPath(dir) {
|
||||
return Blockly.utils.svgPaths.line(
|
||||
[
|
||||
Blockly.utils.svgPaths.point(dir * outerWidth, height),
|
||||
Blockly.utils.svgPaths.point(dir * innerWidth, 0),
|
||||
Blockly.utils.svgPaths.point(dir * outerWidth, -height)
|
||||
]);
|
||||
return svgPaths.line([
|
||||
svgPaths.point(dir * outerWidth, height),
|
||||
svgPaths.point(dir * innerWidth, 0),
|
||||
svgPaths.point(dir * outerWidth, -height)
|
||||
]);
|
||||
}
|
||||
var pathLeft = makeMainPath(1);
|
||||
var pathRight = makeMainPath(-1);
|
||||
const pathLeft = makeMainPath(1);
|
||||
const pathRight = makeMainPath(-1);
|
||||
|
||||
return {
|
||||
type: this.SHAPES.NOTCH,
|
||||
@@ -922,14 +887,14 @@ Blockly.blockRendering.ConstantProvider.prototype.makeNotch = function() {
|
||||
* inside corners.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.makeInsideCorners = function() {
|
||||
var radius = this.CORNER_RADIUS;
|
||||
ConstantProvider.prototype.makeInsideCorners = function() {
|
||||
const radius = this.CORNER_RADIUS;
|
||||
|
||||
var innerTopLeftCorner = Blockly.utils.svgPaths.arc('a', '0 0,0', radius,
|
||||
Blockly.utils.svgPaths.point(-radius, radius));
|
||||
const innerTopLeftCorner =
|
||||
svgPaths.arc('a', '0 0,0', radius, svgPaths.point(-radius, radius));
|
||||
|
||||
var innerBottomLeftCorner = Blockly.utils.svgPaths.arc('a', '0 0,0', radius,
|
||||
Blockly.utils.svgPaths.point(radius, radius));
|
||||
const innerBottomLeftCorner =
|
||||
svgPaths.arc('a', '0 0,0', radius, svgPaths.point(radius, radius));
|
||||
|
||||
return {
|
||||
width: radius,
|
||||
@@ -944,38 +909,35 @@ Blockly.blockRendering.ConstantProvider.prototype.makeInsideCorners = function()
|
||||
* outside corners.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.makeOutsideCorners = function() {
|
||||
var radius = this.CORNER_RADIUS;
|
||||
ConstantProvider.prototype.makeOutsideCorners = function() {
|
||||
const radius = this.CORNER_RADIUS;
|
||||
/**
|
||||
* SVG path for drawing the rounded top-left corner.
|
||||
* @const
|
||||
*/
|
||||
var topLeft =
|
||||
Blockly.utils.svgPaths.moveBy(0, radius) +
|
||||
Blockly.utils.svgPaths.arc('a', '0 0,1', radius,
|
||||
Blockly.utils.svgPaths.point(radius, -radius));
|
||||
const topLeft = svgPaths.moveBy(0, radius) +
|
||||
svgPaths.arc('a', '0 0,1', radius, svgPaths.point(radius, -radius));
|
||||
|
||||
/**
|
||||
* SVG path for drawing the rounded top-right corner.
|
||||
* @const
|
||||
*/
|
||||
var topRight =
|
||||
Blockly.utils.svgPaths.arc('a', '0 0,1', radius,
|
||||
Blockly.utils.svgPaths.point(radius, radius));
|
||||
const topRight =
|
||||
svgPaths.arc('a', '0 0,1', radius, svgPaths.point(radius, radius));
|
||||
|
||||
/**
|
||||
* SVG path for drawing the rounded bottom-left corner.
|
||||
* @const
|
||||
*/
|
||||
var bottomLeft = Blockly.utils.svgPaths.arc('a', '0 0,1', radius,
|
||||
Blockly.utils.svgPaths.point(-radius, -radius));
|
||||
const bottomLeft =
|
||||
svgPaths.arc('a', '0 0,1', radius, svgPaths.point(-radius, -radius));
|
||||
|
||||
/**
|
||||
* SVG path for drawing the rounded bottom-right corner.
|
||||
* @const
|
||||
*/
|
||||
var bottomRight = Blockly.utils.svgPaths.arc('a', '0 0,1', radius,
|
||||
Blockly.utils.svgPaths.point(-radius, radius));
|
||||
const bottomRight =
|
||||
svgPaths.arc('a', '0 0,1', radius, svgPaths.point(-radius, radius));
|
||||
|
||||
return {
|
||||
topLeft: topLeft,
|
||||
@@ -989,19 +951,18 @@ Blockly.blockRendering.ConstantProvider.prototype.makeOutsideCorners = function(
|
||||
/**
|
||||
* Get an object with connection shape and sizing information based on the type
|
||||
* of the connection.
|
||||
* @param {!Blockly.RenderedConnection} connection The connection to find a
|
||||
* @param {!RenderedConnection} connection The connection to find a
|
||||
* shape object for
|
||||
* @return {!Object} The shape object for the connection.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.shapeFor = function(
|
||||
connection) {
|
||||
ConstantProvider.prototype.shapeFor = function(connection) {
|
||||
switch (connection.type) {
|
||||
case Blockly.connectionTypes.INPUT_VALUE:
|
||||
case Blockly.connectionTypes.OUTPUT_VALUE:
|
||||
case connectionTypes.INPUT_VALUE:
|
||||
case connectionTypes.OUTPUT_VALUE:
|
||||
return this.PUZZLE_TAB;
|
||||
case Blockly.connectionTypes.PREVIOUS_STATEMENT:
|
||||
case Blockly.connectionTypes.NEXT_STATEMENT:
|
||||
case connectionTypes.PREVIOUS_STATEMENT:
|
||||
case connectionTypes.NEXT_STATEMENT:
|
||||
return this.NOTCH;
|
||||
default:
|
||||
throw Error('Unknown connection type');
|
||||
@@ -1016,8 +977,7 @@ Blockly.blockRendering.ConstantProvider.prototype.shapeFor = function(
|
||||
* @suppress {strictModuleDepCheck} Debug renderer only included in playground.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg,
|
||||
tagName, selector) {
|
||||
ConstantProvider.prototype.createDom = function(svg, tagName, selector) {
|
||||
this.injectCSS_(tagName, selector);
|
||||
|
||||
/*
|
||||
@@ -1025,8 +985,7 @@ Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg,
|
||||
... filters go here ...
|
||||
</defs>
|
||||
*/
|
||||
var defs = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.DEFS, {}, svg);
|
||||
this.defs_ = dom.createSvgElement(Svg.DEFS, {}, svg);
|
||||
/*
|
||||
<filter id="blocklyEmbossFilter837493">
|
||||
<feGaussianBlur in="SourceAlpha" stdDeviation="1" result="blur" />
|
||||
@@ -1041,15 +1000,14 @@ Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg,
|
||||
k1="0" k2="1" k3="1" k4="0" />
|
||||
</filter>
|
||||
*/
|
||||
var embossFilter = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.FILTER,
|
||||
{'id': 'blocklyEmbossFilter' + this.randomIdentifier}, defs);
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.FEGAUSSIANBLUR,
|
||||
const embossFilter = dom.createSvgElement(
|
||||
Svg.FILTER, {'id': 'blocklyEmbossFilter' + this.randomIdentifier},
|
||||
this.defs_);
|
||||
dom.createSvgElement(
|
||||
Svg.FEGAUSSIANBLUR,
|
||||
{'in': 'SourceAlpha', 'stdDeviation': 1, 'result': 'blur'}, embossFilter);
|
||||
var feSpecularLighting = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.FESPECULARLIGHTING,
|
||||
{
|
||||
const feSpecularLighting = dom.createSvgElement(
|
||||
Svg.FESPECULARLIGHTING, {
|
||||
'in': 'blur',
|
||||
'surfaceScale': 1,
|
||||
'specularConstant': 0.5,
|
||||
@@ -1058,20 +1016,19 @@ Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg,
|
||||
'result': 'specOut'
|
||||
},
|
||||
embossFilter);
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.FEPOINTLIGHT,
|
||||
{'x': -5000, 'y': -10000, 'z': 20000}, feSpecularLighting);
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.FECOMPOSITE,
|
||||
{
|
||||
dom.createSvgElement(
|
||||
Svg.FEPOINTLIGHT, {'x': -5000, 'y': -10000, 'z': 20000},
|
||||
feSpecularLighting);
|
||||
dom.createSvgElement(
|
||||
Svg.FECOMPOSITE, {
|
||||
'in': 'specOut',
|
||||
'in2': 'SourceAlpha',
|
||||
'operator': 'in',
|
||||
'result': 'specOut'
|
||||
}, embossFilter);
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.FECOMPOSITE,
|
||||
{
|
||||
},
|
||||
embossFilter);
|
||||
dom.createSvgElement(
|
||||
Svg.FECOMPOSITE, {
|
||||
'in': 'SourceGraphic',
|
||||
'in2': 'specOut',
|
||||
'operator': 'arithmetic',
|
||||
@@ -1079,7 +1036,8 @@ Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg,
|
||||
'k2': 1,
|
||||
'k3': 1,
|
||||
'k4': 0
|
||||
}, embossFilter);
|
||||
},
|
||||
embossFilter);
|
||||
this.embossFilterId = embossFilter.id;
|
||||
this.embossFilter_ = embossFilter;
|
||||
|
||||
@@ -1090,59 +1048,60 @@ Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg,
|
||||
<path d="M 0 0 L 10 10 M 10 0 L 0 10" stroke="#cc0" />
|
||||
</pattern>
|
||||
*/
|
||||
var disabledPattern = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.PATTERN,
|
||||
{
|
||||
const disabledPattern = dom.createSvgElement(
|
||||
Svg.PATTERN, {
|
||||
'id': 'blocklyDisabledPattern' + this.randomIdentifier,
|
||||
'patternUnits': 'userSpaceOnUse',
|
||||
'width': 10,
|
||||
'height': 10
|
||||
}, defs);
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.RECT,
|
||||
{'width': 10, 'height': 10, 'fill': '#aaa'}, disabledPattern);
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.PATH,
|
||||
{'d': 'M 0 0 L 10 10 M 10 0 L 0 10', 'stroke': '#cc0'}, disabledPattern);
|
||||
},
|
||||
this.defs_);
|
||||
dom.createSvgElement(
|
||||
Svg.RECT, {'width': 10, 'height': 10, 'fill': '#aaa'}, disabledPattern);
|
||||
dom.createSvgElement(
|
||||
Svg.PATH, {'d': 'M 0 0 L 10 10 M 10 0 L 0 10', 'stroke': '#cc0'},
|
||||
disabledPattern);
|
||||
this.disabledPatternId = disabledPattern.id;
|
||||
this.disabledPattern_ = disabledPattern;
|
||||
|
||||
if (Blockly.blockRendering.Debug) {
|
||||
var debugFilter = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.FILTER,
|
||||
{
|
||||
this.createDebugFilter();
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a filter for highlighting the currently rendering block during
|
||||
* render debugging.
|
||||
* @private
|
||||
*/
|
||||
ConstantProvider.prototype.createDebugFilter = function() {
|
||||
// Only create the debug filter once.
|
||||
if (!this.debugFilter_) {
|
||||
const debugFilter = dom.createSvgElement(
|
||||
Svg.FILTER, {
|
||||
'id': 'blocklyDebugFilter' + this.randomIdentifier,
|
||||
'height': '160%',
|
||||
'width': '180%',
|
||||
y: '-30%',
|
||||
x: '-40%'
|
||||
},
|
||||
defs);
|
||||
this.defs_);
|
||||
// Set all gaussian blur pixels to 1 opacity before applying flood
|
||||
var debugComponentTransfer = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.FECOMPONENTTRANSFER, {
|
||||
'result': 'outBlur'
|
||||
}, debugFilter);
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.FEFUNCA,
|
||||
{
|
||||
'type': 'table', 'tableValues': '0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1'
|
||||
},
|
||||
const debugComponentTransfer = dom.createSvgElement(
|
||||
Svg.FECOMPONENTTRANSFER, {'result': 'outBlur'}, debugFilter);
|
||||
dom.createSvgElement(
|
||||
Svg.FEFUNCA,
|
||||
{'type': 'table', 'tableValues': '0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1'},
|
||||
debugComponentTransfer);
|
||||
// Color the highlight
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.FEFLOOD,
|
||||
{
|
||||
'flood-color': '#ff0000',
|
||||
'flood-opacity': 0.5,
|
||||
'result': 'outColor'
|
||||
},
|
||||
dom.createSvgElement(
|
||||
Svg.FEFLOOD,
|
||||
{'flood-color': '#ff0000', 'flood-opacity': 0.5, 'result': 'outColor'},
|
||||
debugFilter);
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.FECOMPOSITE,
|
||||
{
|
||||
'in': 'outColor', 'in2': 'outBlur',
|
||||
'operator': 'in', 'result': 'outGlow'
|
||||
dom.createSvgElement(
|
||||
Svg.FECOMPOSITE, {
|
||||
'in': 'outColor',
|
||||
'in2': 'outBlur',
|
||||
'operator': 'in',
|
||||
'result': 'outGlow'
|
||||
},
|
||||
debugFilter);
|
||||
this.debugFilterId = debugFilter.id;
|
||||
@@ -1156,23 +1115,22 @@ Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg,
|
||||
* @param {string} selector The CSS selector to use.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.injectCSS_ = function(
|
||||
tagName, selector) {
|
||||
var cssArray = this.getCSS_(selector);
|
||||
var cssNodeId = 'blockly-renderer-style-' + tagName;
|
||||
ConstantProvider.prototype.injectCSS_ = function(tagName, selector) {
|
||||
const cssArray = this.getCSS_(selector);
|
||||
const cssNodeId = 'blockly-renderer-style-' + tagName;
|
||||
this.cssNode_ =
|
||||
/** @type {!HTMLStyleElement} */ (document.getElementById(cssNodeId));
|
||||
var text = cssArray.join('\n');
|
||||
/** @type {!HTMLStyleElement} */ (document.getElementById(cssNodeId));
|
||||
const text = cssArray.join('\n');
|
||||
if (this.cssNode_) {
|
||||
// Already injected, update if the theme changed.
|
||||
this.cssNode_.firstChild.textContent = text;
|
||||
return;
|
||||
}
|
||||
// Inject CSS tag at start of head.
|
||||
var cssNode =
|
||||
/** @type {!HTMLStyleElement} */ (document.createElement('style'));
|
||||
const cssNode =
|
||||
/** @type {!HTMLStyleElement} */ (document.createElement('style'));
|
||||
cssNode.id = cssNodeId;
|
||||
var cssTextNode = document.createTextNode(text);
|
||||
const cssTextNode = document.createTextNode(text);
|
||||
cssNode.appendChild(cssTextNode);
|
||||
document.head.insertBefore(cssNode, document.head.firstChild);
|
||||
this.cssNode_ = cssNode;
|
||||
@@ -1184,9 +1142,10 @@ Blockly.blockRendering.ConstantProvider.prototype.injectCSS_ = function(
|
||||
* @return {!Array<string>} Array of CSS strings.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.ConstantProvider.prototype.getCSS_ = function(selector) {
|
||||
ConstantProvider.prototype.getCSS_ = function(selector) {
|
||||
return [
|
||||
/* eslint-disable indent */
|
||||
/* clang-format off */
|
||||
// Text.
|
||||
selector + ' .blocklyText, ',
|
||||
selector + ' .blocklyFlyoutLabelText {',
|
||||
@@ -1256,6 +1215,9 @@ Blockly.blockRendering.ConstantProvider.prototype.getCSS_ = function(selector) {
|
||||
'fill-opacity: ' + this.INSERTION_MARKER_OPACITY + ';',
|
||||
'stroke: none;',
|
||||
'}',
|
||||
/* clang-format on */
|
||||
/* eslint-enable indent */
|
||||
];
|
||||
};
|
||||
|
||||
exports = ConstantProvider;
|
||||
|
||||
@@ -17,8 +17,6 @@ goog.require('Blockly.blockRendering.RenderInfo');
|
||||
goog.require('Blockly.blockRendering.Row');
|
||||
goog.require('Blockly.blockRendering.Types');
|
||||
goog.require('Blockly.connectionTypes');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
|
||||
|
||||
@@ -10,29 +10,36 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.blockRendering.Drawer');
|
||||
goog.module('Blockly.blockRendering.Drawer');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.blockRendering.RenderInfo');
|
||||
goog.require('Blockly.blockRendering.Row');
|
||||
goog.require('Blockly.blockRendering.Types');
|
||||
goog.require('Blockly.utils.svgPaths');
|
||||
|
||||
goog.requireType('Blockly.blockRendering.ConstantProvider');
|
||||
goog.requireType('Blockly.blockRendering.Field');
|
||||
goog.requireType('Blockly.blockRendering.Icon');
|
||||
goog.requireType('Blockly.blockRendering.InlineInput');
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const ConstantProvider = goog.requireType('Blockly.blockRendering.ConstantProvider');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Field = goog.requireType('Blockly.blockRendering.Field');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Icon = goog.requireType('Blockly.blockRendering.Icon');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const InlineInput = goog.requireType('Blockly.blockRendering.InlineInput');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const RenderInfo = goog.requireType('Blockly.blockRendering.RenderInfo');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Row = goog.require('Blockly.blockRendering.Row');
|
||||
const Types = goog.require('Blockly.blockRendering.Types');
|
||||
const svgPaths = goog.require('Blockly.utils.svgPaths');
|
||||
|
||||
|
||||
/**
|
||||
* An object that draws a block based on the given rendering information.
|
||||
* @param {!Blockly.BlockSvg} block The block to render.
|
||||
* @param {!Blockly.blockRendering.RenderInfo} info An object containing all
|
||||
* @param {!BlockSvg} block The block to render.
|
||||
* @param {!RenderInfo} info An object containing all
|
||||
* information needed to render this block.
|
||||
* @package
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.blockRendering.Drawer = function(block, info) {
|
||||
const Drawer = function(block, info) {
|
||||
this.block_ = block;
|
||||
this.info_ = info;
|
||||
this.topLeft_ = block.getRelativeToSurfaceXY();
|
||||
@@ -41,7 +48,7 @@ Blockly.blockRendering.Drawer = function(block, info) {
|
||||
|
||||
/**
|
||||
* The renderer's constant provider.
|
||||
* @type {!Blockly.blockRendering.ConstantProvider}
|
||||
* @type {!ConstantProvider}
|
||||
* @protected
|
||||
*/
|
||||
this.constants_ = info.getRenderer().getConstants();
|
||||
@@ -57,7 +64,7 @@ Blockly.blockRendering.Drawer = function(block, info) {
|
||||
* required.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.draw = function() {
|
||||
Drawer.prototype.draw = function() {
|
||||
this.hideHiddenIcons_();
|
||||
this.drawOutline_();
|
||||
this.drawInternals_();
|
||||
@@ -78,7 +85,7 @@ Blockly.blockRendering.Drawer.prototype.draw = function() {
|
||||
* render. Anything that needs to be kept around should be set in this function.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.recordSizeOnBlock_ = function() {
|
||||
Drawer.prototype.recordSizeOnBlock_ = function() {
|
||||
// This is used when the block is reporting its size to anyone else.
|
||||
// The dark path adds to the size of the block in both X and Y.
|
||||
this.block_.height = this.info_.height;
|
||||
@@ -89,8 +96,8 @@ Blockly.blockRendering.Drawer.prototype.recordSizeOnBlock_ = function() {
|
||||
* Hide icons that were marked as hidden.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.hideHiddenIcons_ = function() {
|
||||
for (var i = 0, iconInfo; (iconInfo = this.info_.hiddenIcons[i]); i++) {
|
||||
Drawer.prototype.hideHiddenIcons_ = function() {
|
||||
for (let i = 0, iconInfo; (iconInfo = this.info_.hiddenIcons[i]); i++) {
|
||||
iconInfo.icon.iconGroup_.setAttribute('display', 'none');
|
||||
}
|
||||
};
|
||||
@@ -99,10 +106,10 @@ Blockly.blockRendering.Drawer.prototype.hideHiddenIcons_ = function() {
|
||||
* Create the outline of the block. This is a single continuous path.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.drawOutline_ = function() {
|
||||
Drawer.prototype.drawOutline_ = function() {
|
||||
this.drawTop_();
|
||||
for (var r = 1; r < this.info_.rows.length - 1; r++) {
|
||||
var row = this.info_.rows[r];
|
||||
for (let r = 1; r < this.info_.rows.length - 1; r++) {
|
||||
const row = this.info_.rows[r];
|
||||
if (row.hasJaggedEdge) {
|
||||
this.drawJaggedEdge_(row);
|
||||
} else if (row.hasStatement) {
|
||||
@@ -123,91 +130,80 @@ Blockly.blockRendering.Drawer.prototype.drawOutline_ = function() {
|
||||
* details such as hats and rounded corners.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.drawTop_ = function() {
|
||||
var topRow = this.info_.topRow;
|
||||
var elements = topRow.elements;
|
||||
Drawer.prototype.drawTop_ = function() {
|
||||
const topRow = this.info_.topRow;
|
||||
const elements = topRow.elements;
|
||||
|
||||
this.positionPreviousConnection_();
|
||||
this.outlinePath_ +=
|
||||
Blockly.utils.svgPaths.moveBy(topRow.xPos, this.info_.startY);
|
||||
for (var i = 0, elem; (elem = elements[i]); i++) {
|
||||
if (Blockly.blockRendering.Types.isLeftRoundedCorner(elem)) {
|
||||
this.outlinePath_ +=
|
||||
this.constants_.OUTSIDE_CORNERS.topLeft;
|
||||
} else if (Blockly.blockRendering.Types.isRightRoundedCorner(elem)) {
|
||||
this.outlinePath_ +=
|
||||
this.constants_.OUTSIDE_CORNERS.topRight;
|
||||
} else if (Blockly.blockRendering.Types.isPreviousConnection(elem)) {
|
||||
this.outlinePath_ += svgPaths.moveBy(topRow.xPos, this.info_.startY);
|
||||
for (let i = 0, elem; (elem = elements[i]); i++) {
|
||||
if (Types.isLeftRoundedCorner(elem)) {
|
||||
this.outlinePath_ += this.constants_.OUTSIDE_CORNERS.topLeft;
|
||||
} else if (Types.isRightRoundedCorner(elem)) {
|
||||
this.outlinePath_ += this.constants_.OUTSIDE_CORNERS.topRight;
|
||||
} else if (Types.isPreviousConnection(elem)) {
|
||||
this.outlinePath_ += elem.shape.pathLeft;
|
||||
} else if (Blockly.blockRendering.Types.isHat(elem)) {
|
||||
} else if (Types.isHat(elem)) {
|
||||
this.outlinePath_ += this.constants_.START_HAT.path;
|
||||
} else if (Blockly.blockRendering.Types.isSpacer(elem)) {
|
||||
this.outlinePath_ += Blockly.utils.svgPaths.lineOnAxis('h', elem.width);
|
||||
} else if (Types.isSpacer(elem)) {
|
||||
this.outlinePath_ += svgPaths.lineOnAxis('h', elem.width);
|
||||
}
|
||||
// No branch for a square corner, because it's a no-op.
|
||||
}
|
||||
this.outlinePath_ += Blockly.utils.svgPaths.lineOnAxis('v', topRow.height);
|
||||
this.outlinePath_ += svgPaths.lineOnAxis('v', topRow.height);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add steps for the jagged edge of a row on a collapsed block.
|
||||
* @param {!Blockly.blockRendering.Row} row The row to draw the side of.
|
||||
* @param {!Row} row The row to draw the side of.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.drawJaggedEdge_ = function(row) {
|
||||
var remainder =
|
||||
row.height - this.constants_.JAGGED_TEETH.height;
|
||||
this.outlinePath_ += this.constants_.JAGGED_TEETH.path +
|
||||
Blockly.utils.svgPaths.lineOnAxis('v', remainder);
|
||||
Drawer.prototype.drawJaggedEdge_ = function(row) {
|
||||
const remainder = row.height - this.constants_.JAGGED_TEETH.height;
|
||||
this.outlinePath_ +=
|
||||
this.constants_.JAGGED_TEETH.path + svgPaths.lineOnAxis('v', remainder);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add steps for an external value input, rendered as a notch in the side
|
||||
* of the block.
|
||||
* @param {!Blockly.blockRendering.Row} row The row that this input
|
||||
* belongs to.
|
||||
* @param {!Row} row The row that this input belongs to.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.drawValueInput_ = function(row) {
|
||||
var input = row.getLastInput();
|
||||
Drawer.prototype.drawValueInput_ = function(row) {
|
||||
const input = row.getLastInput();
|
||||
this.positionExternalValueConnection_(row);
|
||||
|
||||
var pathDown = (typeof input.shape.pathDown == "function") ?
|
||||
const pathDown = (typeof input.shape.pathDown == 'function') ?
|
||||
input.shape.pathDown(input.height) :
|
||||
input.shape.pathDown;
|
||||
|
||||
this.outlinePath_ +=
|
||||
Blockly.utils.svgPaths.lineOnAxis('H', input.xPos + input.width) +
|
||||
pathDown +
|
||||
Blockly.utils.svgPaths.lineOnAxis('v', row.height - input.connectionHeight);
|
||||
this.outlinePath_ += svgPaths.lineOnAxis('H', input.xPos + input.width) +
|
||||
pathDown + svgPaths.lineOnAxis('v', row.height - input.connectionHeight);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add steps for a statement input.
|
||||
* @param {!Blockly.blockRendering.Row} row The row that this input
|
||||
* belongs to.
|
||||
* @param {!Row} row The row that this input belongs to.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.drawStatementInput_ = function(row) {
|
||||
var input = row.getLastInput();
|
||||
Drawer.prototype.drawStatementInput_ = function(row) {
|
||||
const input = row.getLastInput();
|
||||
// Where to start drawing the notch, which is on the right side in LTR.
|
||||
var x = input.xPos + input.notchOffset + input.shape.width;
|
||||
const x = input.xPos + input.notchOffset + input.shape.width;
|
||||
|
||||
var innerTopLeftCorner =
|
||||
input.shape.pathRight +
|
||||
Blockly.utils.svgPaths.lineOnAxis('h',
|
||||
-(input.notchOffset - this.constants_.INSIDE_CORNERS.width)) +
|
||||
const innerTopLeftCorner = input.shape.pathRight +
|
||||
svgPaths.lineOnAxis(
|
||||
'h', -(input.notchOffset - this.constants_.INSIDE_CORNERS.width)) +
|
||||
this.constants_.INSIDE_CORNERS.pathTop;
|
||||
|
||||
var innerHeight =
|
||||
row.height - (2 * this.constants_.INSIDE_CORNERS.height);
|
||||
const innerHeight = row.height - (2 * this.constants_.INSIDE_CORNERS.height);
|
||||
|
||||
this.outlinePath_ += Blockly.utils.svgPaths.lineOnAxis('H', x) +
|
||||
innerTopLeftCorner +
|
||||
Blockly.utils.svgPaths.lineOnAxis('v', innerHeight) +
|
||||
this.outlinePath_ += svgPaths.lineOnAxis('H', x) + innerTopLeftCorner +
|
||||
svgPaths.lineOnAxis('v', innerHeight) +
|
||||
this.constants_.INSIDE_CORNERS.pathBottom +
|
||||
Blockly.utils.svgPaths.lineOnAxis('H', row.xPos + row.width);
|
||||
svgPaths.lineOnAxis('H', row.xPos + row.width);
|
||||
|
||||
this.positionStatementInputConnection_(row);
|
||||
};
|
||||
@@ -215,13 +211,11 @@ Blockly.blockRendering.Drawer.prototype.drawStatementInput_ = function(row) {
|
||||
/**
|
||||
* Add steps for the right side of a row that does not have value or
|
||||
* statement input connections.
|
||||
* @param {!Blockly.blockRendering.Row} row The row to draw the
|
||||
* side of.
|
||||
* @param {!Row} row The row to draw the side of.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.drawRightSideRow_ = function(row) {
|
||||
this.outlinePath_ +=
|
||||
Blockly.utils.svgPaths.lineOnAxis('V', row.yPos + row.height);
|
||||
Drawer.prototype.drawRightSideRow_ = function(row) {
|
||||
this.outlinePath_ += svgPaths.lineOnAxis('V', row.yPos + row.height);
|
||||
};
|
||||
|
||||
|
||||
@@ -230,30 +224,30 @@ Blockly.blockRendering.Drawer.prototype.drawRightSideRow_ = function(row) {
|
||||
* for the next connection.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.drawBottom_ = function() {
|
||||
var bottomRow = this.info_.bottomRow;
|
||||
var elems = bottomRow.elements;
|
||||
Drawer.prototype.drawBottom_ = function() {
|
||||
const bottomRow = this.info_.bottomRow;
|
||||
const elems = bottomRow.elements;
|
||||
this.positionNextConnection_();
|
||||
|
||||
var rightCornerYOffset = 0;
|
||||
var outlinePath = '';
|
||||
for (var i = elems.length - 1, elem; (elem = elems[i]); i--) {
|
||||
if (Blockly.blockRendering.Types.isNextConnection(elem)) {
|
||||
let rightCornerYOffset = 0;
|
||||
let outlinePath = '';
|
||||
for (let i = elems.length - 1, elem; (elem = elems[i]); i--) {
|
||||
if (Types.isNextConnection(elem)) {
|
||||
outlinePath += elem.shape.pathRight;
|
||||
} else if (Blockly.blockRendering.Types.isLeftSquareCorner(elem)) {
|
||||
outlinePath += Blockly.utils.svgPaths.lineOnAxis('H', bottomRow.xPos);
|
||||
} else if (Blockly.blockRendering.Types.isLeftRoundedCorner(elem)) {
|
||||
} else if (Types.isLeftSquareCorner(elem)) {
|
||||
outlinePath += svgPaths.lineOnAxis('H', bottomRow.xPos);
|
||||
} else if (Types.isLeftRoundedCorner(elem)) {
|
||||
outlinePath += this.constants_.OUTSIDE_CORNERS.bottomLeft;
|
||||
} else if (Blockly.blockRendering.Types.isRightRoundedCorner(elem)) {
|
||||
} else if (Types.isRightRoundedCorner(elem)) {
|
||||
outlinePath += this.constants_.OUTSIDE_CORNERS.bottomRight;
|
||||
rightCornerYOffset = this.constants_.OUTSIDE_CORNERS.rightHeight;
|
||||
} else if (Blockly.blockRendering.Types.isSpacer(elem)) {
|
||||
outlinePath += Blockly.utils.svgPaths.lineOnAxis('h', elem.width * -1);
|
||||
} else if (Types.isSpacer(elem)) {
|
||||
outlinePath += svgPaths.lineOnAxis('h', elem.width * -1);
|
||||
}
|
||||
}
|
||||
|
||||
this.outlinePath_ += Blockly.utils.svgPaths.lineOnAxis('V',
|
||||
bottomRow.baseline - rightCornerYOffset);
|
||||
this.outlinePath_ +=
|
||||
svgPaths.lineOnAxis('V', bottomRow.baseline - rightCornerYOffset);
|
||||
this.outlinePath_ += outlinePath;
|
||||
};
|
||||
|
||||
@@ -262,21 +256,19 @@ Blockly.blockRendering.Drawer.prototype.drawBottom_ = function() {
|
||||
* connection
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.drawLeft_ = function() {
|
||||
var outputConnection = this.info_.outputConnection;
|
||||
Drawer.prototype.drawLeft_ = function() {
|
||||
const outputConnection = this.info_.outputConnection;
|
||||
this.positionOutputConnection_();
|
||||
|
||||
if (outputConnection) {
|
||||
var tabBottom = outputConnection.connectionOffsetY +
|
||||
outputConnection.height;
|
||||
var pathUp = (typeof outputConnection.shape.pathUp == "function") ?
|
||||
const tabBottom =
|
||||
outputConnection.connectionOffsetY + outputConnection.height;
|
||||
const pathUp = (typeof outputConnection.shape.pathUp == 'function') ?
|
||||
outputConnection.shape.pathUp(outputConnection.height) :
|
||||
outputConnection.shape.pathUp;
|
||||
|
||||
// Draw a line up to the bottom of the tab.
|
||||
this.outlinePath_ +=
|
||||
Blockly.utils.svgPaths.lineOnAxis('V', tabBottom) +
|
||||
pathUp;
|
||||
this.outlinePath_ += svgPaths.lineOnAxis('V', tabBottom) + pathUp;
|
||||
}
|
||||
// Close off the path. This draws a vertical line up to the start of the
|
||||
// block's path, which may be either a rounded or a sharp corner.
|
||||
@@ -288,16 +280,15 @@ Blockly.blockRendering.Drawer.prototype.drawLeft_ = function() {
|
||||
* not depend on the outer path for placement.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.drawInternals_ = function() {
|
||||
for (var i = 0, row; (row = this.info_.rows[i]); i++) {
|
||||
for (var j = 0, elem; (elem = row.elements[j]); j++) {
|
||||
if (Blockly.blockRendering.Types.isInlineInput(elem)) {
|
||||
Drawer.prototype.drawInternals_ = function() {
|
||||
for (let i = 0, row; (row = this.info_.rows[i]); i++) {
|
||||
for (let j = 0, elem; (elem = row.elements[j]); j++) {
|
||||
if (Types.isInlineInput(elem)) {
|
||||
this.drawInlineInput_(
|
||||
/** @type {!Blockly.blockRendering.InlineInput} */ (elem));
|
||||
} else if (Blockly.blockRendering.Types.isIcon(elem) ||
|
||||
Blockly.blockRendering.Types.isField(elem)) {
|
||||
/** @type {!InlineInput} */ (elem));
|
||||
} else if (Types.isIcon(elem) || Types.isField(elem)) {
|
||||
this.layoutField_(
|
||||
/** @type {!Blockly.blockRendering.Field|!Blockly.blockRendering.Icon} */
|
||||
/** @type {!Field|!Icon} */
|
||||
(elem));
|
||||
}
|
||||
}
|
||||
@@ -306,20 +297,21 @@ Blockly.blockRendering.Drawer.prototype.drawInternals_ = function() {
|
||||
|
||||
/**
|
||||
* Push a field or icon's new position to its SVG root.
|
||||
* @param {!Blockly.blockRendering.Icon|!Blockly.blockRendering.Field} fieldInfo
|
||||
* @param {!Icon|!Field} fieldInfo
|
||||
* The rendering information for the field or icon.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.layoutField_ = function(fieldInfo) {
|
||||
if (Blockly.blockRendering.Types.isField(fieldInfo)) {
|
||||
var svgGroup = fieldInfo.field.getSvgRoot();
|
||||
} else if (Blockly.blockRendering.Types.isIcon(fieldInfo)) {
|
||||
var svgGroup = fieldInfo.icon.iconGroup_;
|
||||
Drawer.prototype.layoutField_ = function(fieldInfo) {
|
||||
let svgGroup;
|
||||
if (Types.isField(fieldInfo)) {
|
||||
svgGroup = fieldInfo.field.getSvgRoot();
|
||||
} else if (Types.isIcon(fieldInfo)) {
|
||||
svgGroup = fieldInfo.icon.iconGroup_;
|
||||
}
|
||||
|
||||
var yPos = fieldInfo.centerline - fieldInfo.height / 2;
|
||||
var xPos = fieldInfo.xPos;
|
||||
var scale = '';
|
||||
const yPos = fieldInfo.centerline - fieldInfo.height / 2;
|
||||
let xPos = fieldInfo.xPos;
|
||||
let scale = '';
|
||||
if (this.info_.RTL) {
|
||||
xPos = -(xPos + fieldInfo.width);
|
||||
if (fieldInfo.flipRtl) {
|
||||
@@ -327,7 +319,7 @@ Blockly.blockRendering.Drawer.prototype.layoutField_ = function(fieldInfo) {
|
||||
scale = 'scale(-1 1)';
|
||||
}
|
||||
}
|
||||
if (Blockly.blockRendering.Types.isIcon(fieldInfo)) {
|
||||
if (Types.isIcon(fieldInfo)) {
|
||||
svgGroup.setAttribute('display', 'block');
|
||||
svgGroup.setAttribute('transform', 'translate(' + xPos + ',' + yPos + ')');
|
||||
fieldInfo.icon.computeIconLocation();
|
||||
@@ -345,26 +337,24 @@ Blockly.blockRendering.Drawer.prototype.layoutField_ = function(fieldInfo) {
|
||||
|
||||
/**
|
||||
* Add steps for an inline input.
|
||||
* @param {!Blockly.blockRendering.InlineInput} input The information about the
|
||||
* @param {!InlineInput} input The information about the
|
||||
* input to render.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.drawInlineInput_ = function(input) {
|
||||
var width = input.width;
|
||||
var height = input.height;
|
||||
var yPos = input.centerline - height / 2;
|
||||
Drawer.prototype.drawInlineInput_ = function(input) {
|
||||
const width = input.width;
|
||||
const height = input.height;
|
||||
const yPos = input.centerline - height / 2;
|
||||
|
||||
var connectionTop = input.connectionOffsetY;
|
||||
var connectionBottom = input.connectionHeight + connectionTop;
|
||||
var connectionRight = input.xPos + input.connectionWidth;
|
||||
const connectionTop = input.connectionOffsetY;
|
||||
const connectionBottom = input.connectionHeight + connectionTop;
|
||||
const connectionRight = input.xPos + input.connectionWidth;
|
||||
|
||||
this.inlinePath_ += Blockly.utils.svgPaths.moveTo(connectionRight, yPos) +
|
||||
Blockly.utils.svgPaths.lineOnAxis('v', connectionTop) +
|
||||
input.shape.pathDown +
|
||||
Blockly.utils.svgPaths.lineOnAxis('v', height - connectionBottom) +
|
||||
Blockly.utils.svgPaths.lineOnAxis('h', width - input.connectionWidth) +
|
||||
Blockly.utils.svgPaths.lineOnAxis('v', -height) +
|
||||
'z';
|
||||
this.inlinePath_ += svgPaths.moveTo(connectionRight, yPos) +
|
||||
svgPaths.lineOnAxis('v', connectionTop) + input.shape.pathDown +
|
||||
svgPaths.lineOnAxis('v', height - connectionBottom) +
|
||||
svgPaths.lineOnAxis('h', width - input.connectionWidth) +
|
||||
svgPaths.lineOnAxis('v', -height) + 'z';
|
||||
|
||||
this.positionInlineInputConnection_(input);
|
||||
};
|
||||
@@ -373,21 +363,21 @@ Blockly.blockRendering.Drawer.prototype.drawInlineInput_ = function(input) {
|
||||
* Position the connection on an inline value input, taking into account
|
||||
* RTL and the small gap between the parent block and child block which lets the
|
||||
* parent block's dark path show through.
|
||||
* @param {Blockly.blockRendering.InlineInput} input The information about
|
||||
* @param {InlineInput} input The information about
|
||||
* the input that the connection is on.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.positionInlineInputConnection_ = function(input) {
|
||||
var yPos = input.centerline - input.height / 2;
|
||||
Drawer.prototype.positionInlineInputConnection_ = function(input) {
|
||||
const yPos = input.centerline - input.height / 2;
|
||||
// Move the connection.
|
||||
if (input.connectionModel) {
|
||||
// xPos already contains info about startX
|
||||
var connX = input.xPos + input.connectionWidth + input.connectionOffsetX;
|
||||
let connX = input.xPos + input.connectionWidth + input.connectionOffsetX;
|
||||
if (this.info_.RTL) {
|
||||
connX *= -1;
|
||||
}
|
||||
input.connectionModel.setOffsetInBlock(connX,
|
||||
yPos + input.connectionOffsetY);
|
||||
input.connectionModel.setOffsetInBlock(
|
||||
connX, yPos + input.connectionOffsetY);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -395,13 +385,13 @@ Blockly.blockRendering.Drawer.prototype.positionInlineInputConnection_ = functio
|
||||
* Position the connection on a statement input, taking into account
|
||||
* RTL and the small gap between the parent block and child block which lets the
|
||||
* parent block's dark path show through.
|
||||
* @param {!Blockly.blockRendering.Row} row The row that the connection is on.
|
||||
* @param {!Row} row The row that the connection is on.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.positionStatementInputConnection_ = function(row) {
|
||||
var input = row.getLastInput();
|
||||
Drawer.prototype.positionStatementInputConnection_ = function(row) {
|
||||
const input = row.getLastInput();
|
||||
if (input.connectionModel) {
|
||||
var connX = row.xPos + row.statementEdge + input.notchOffset;
|
||||
let connX = row.xPos + row.statementEdge + input.notchOffset;
|
||||
if (this.info_.RTL) {
|
||||
connX *= -1;
|
||||
}
|
||||
@@ -413,13 +403,13 @@ Blockly.blockRendering.Drawer.prototype.positionStatementInputConnection_ = func
|
||||
* Position the connection on an external value input, taking into account
|
||||
* RTL and the small gap between the parent block and child block which lets the
|
||||
* parent block's dark path show through.
|
||||
* @param {!Blockly.blockRendering.Row} row The row that the connection is on.
|
||||
* @param {!Row} row The row that the connection is on.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.positionExternalValueConnection_ = function(row) {
|
||||
var input = row.getLastInput();
|
||||
Drawer.prototype.positionExternalValueConnection_ = function(row) {
|
||||
const input = row.getLastInput();
|
||||
if (input.connectionModel) {
|
||||
var connX = row.xPos + row.width;
|
||||
let connX = row.xPos + row.width;
|
||||
if (this.info_.RTL) {
|
||||
connX *= -1;
|
||||
}
|
||||
@@ -431,11 +421,11 @@ Blockly.blockRendering.Drawer.prototype.positionExternalValueConnection_ = funct
|
||||
* Position the previous connection on a block.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.positionPreviousConnection_ = function() {
|
||||
var topRow = this.info_.topRow;
|
||||
Drawer.prototype.positionPreviousConnection_ = function() {
|
||||
const topRow = this.info_.topRow;
|
||||
if (topRow.connection) {
|
||||
var x = topRow.xPos + topRow.notchOffset;
|
||||
var connX = (this.info_.RTL ? -x : x);
|
||||
const x = topRow.xPos + topRow.notchOffset;
|
||||
const connX = (this.info_.RTL ? -x : x);
|
||||
topRow.connection.connectionModel.setOffsetInBlock(connX, 0);
|
||||
}
|
||||
};
|
||||
@@ -444,13 +434,13 @@ Blockly.blockRendering.Drawer.prototype.positionPreviousConnection_ = function()
|
||||
* Position the next connection on a block.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.positionNextConnection_ = function() {
|
||||
var bottomRow = this.info_.bottomRow;
|
||||
Drawer.prototype.positionNextConnection_ = function() {
|
||||
const bottomRow = this.info_.bottomRow;
|
||||
|
||||
if (bottomRow.connection) {
|
||||
var connInfo = bottomRow.connection;
|
||||
var x = connInfo.xPos; // Already contains info about startX.
|
||||
var connX = (this.info_.RTL ? -x : x);
|
||||
const connInfo = bottomRow.connection;
|
||||
const x = connInfo.xPos; // Already contains info about startX.
|
||||
const connX = (this.info_.RTL ? -x : x);
|
||||
connInfo.connectionModel.setOffsetInBlock(connX, bottomRow.baseline);
|
||||
}
|
||||
};
|
||||
@@ -459,11 +449,13 @@ Blockly.blockRendering.Drawer.prototype.positionNextConnection_ = function() {
|
||||
* Position the output connection on a block.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.Drawer.prototype.positionOutputConnection_ = function() {
|
||||
Drawer.prototype.positionOutputConnection_ = function() {
|
||||
if (this.info_.outputConnection) {
|
||||
var x = this.info_.startX + this.info_.outputConnection.connectionOffsetX;
|
||||
var connX = this.info_.RTL ? -x : x;
|
||||
this.block_.outputConnection.setOffsetInBlock(connX,
|
||||
this.info_.outputConnection.connectionOffsetY);
|
||||
const x = this.info_.startX + this.info_.outputConnection.connectionOffsetX;
|
||||
const connX = this.info_.RTL ? -x : x;
|
||||
this.block_.outputConnection.setOffsetInBlock(
|
||||
connX, this.info_.outputConnection.connectionOffsetY);
|
||||
}
|
||||
};
|
||||
|
||||
exports = Drawer;
|
||||
|
||||
@@ -10,37 +10,45 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.blockRendering.RenderInfo');
|
||||
goog.module('Blockly.blockRendering.RenderInfo');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.blockRendering.BottomRow');
|
||||
goog.require('Blockly.blockRendering.ExternalValueInput');
|
||||
goog.require('Blockly.blockRendering.Field');
|
||||
goog.require('Blockly.blockRendering.Hat');
|
||||
goog.require('Blockly.blockRendering.InlineInput');
|
||||
goog.require('Blockly.blockRendering.InputRow');
|
||||
goog.require('Blockly.blockRendering.InRowSpacer');
|
||||
goog.require('Blockly.blockRendering.JaggedEdge');
|
||||
goog.require('Blockly.blockRendering.Measurable');
|
||||
goog.require('Blockly.blockRendering.NextConnection');
|
||||
goog.require('Blockly.blockRendering.OutputConnection');
|
||||
goog.require('Blockly.blockRendering.PreviousConnection');
|
||||
goog.require('Blockly.blockRendering.RoundCorner');
|
||||
goog.require('Blockly.blockRendering.Row');
|
||||
goog.require('Blockly.blockRendering.SpacerRow');
|
||||
goog.require('Blockly.blockRendering.SquareCorner');
|
||||
goog.require('Blockly.blockRendering.StatementInput');
|
||||
goog.require('Blockly.blockRendering.TopRow');
|
||||
goog.require('Blockly.blockRendering.Types');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.inputTypes');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
const BottomRow = goog.require('Blockly.blockRendering.BottomRow');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const ConstantProvider = goog.requireType('Blockly.blockRendering.ConstantProvider');
|
||||
const ExternalValueInput = goog.require('Blockly.blockRendering.ExternalValueInput');
|
||||
const Field = goog.require('Blockly.blockRendering.Field');
|
||||
const Hat = goog.require('Blockly.blockRendering.Hat');
|
||||
const Icon = goog.require('Blockly.blockRendering.Icon');
|
||||
const InlineInput = goog.require('Blockly.blockRendering.InlineInput');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Input = goog.requireType('Blockly.Input');
|
||||
const InputRow = goog.require('Blockly.blockRendering.InputRow');
|
||||
const InRowSpacer = goog.require('Blockly.blockRendering.InRowSpacer');
|
||||
const JaggedEdge = goog.require('Blockly.blockRendering.JaggedEdge');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Measurable = goog.require('Blockly.blockRendering.Measurable');
|
||||
const NextConnection = goog.require('Blockly.blockRendering.NextConnection');
|
||||
const OutputConnection = goog.require('Blockly.blockRendering.OutputConnection');
|
||||
const PreviousConnection = goog.require('Blockly.blockRendering.PreviousConnection');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const RenderedConnection = goog.requireType('Blockly.RenderedConnection');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Renderer = goog.requireType('Blockly.blockRendering.Renderer');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const RoundCorner = goog.require('Blockly.blockRendering.RoundCorner');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Row = goog.require('Blockly.blockRendering.Row');
|
||||
const SpacerRow = goog.require('Blockly.blockRendering.SpacerRow');
|
||||
const SquareCorner = goog.require('Blockly.blockRendering.SquareCorner');
|
||||
const StatementInput = goog.require('Blockly.blockRendering.StatementInput');
|
||||
const TopRow = goog.require('Blockly.blockRendering.TopRow');
|
||||
const Types = goog.require('Blockly.blockRendering.Types');
|
||||
const {ALIGN} = goog.require('Blockly.constants');
|
||||
const {DUMMY, STATEMENT, VALUE} = goog.require('Blockly.inputTypes');
|
||||
|
||||
goog.requireType('Blockly.blockRendering.ConstantProvider');
|
||||
goog.requireType('Blockly.blockRendering.Icon');
|
||||
goog.requireType('Blockly.blockRendering.Renderer');
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.Input');
|
||||
goog.requireType('Blockly.RenderedConnection');
|
||||
|
||||
|
||||
/**
|
||||
@@ -50,24 +58,24 @@ goog.requireType('Blockly.RenderedConnection');
|
||||
* may choose to rerender when getSize() is called). However, calling it
|
||||
* repeatedly may be expensive.
|
||||
*
|
||||
* @param {!Blockly.blockRendering.Renderer} renderer The renderer in use.
|
||||
* @param {!Blockly.BlockSvg} block The block to measure.
|
||||
* @param {!Renderer} renderer The renderer in use.
|
||||
* @param {!BlockSvg} block The block to measure.
|
||||
* @constructor
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo = function(renderer, block) {
|
||||
const RenderInfo = function(renderer, block) {
|
||||
this.block_ = block;
|
||||
|
||||
/**
|
||||
* The block renderer in use.
|
||||
* @type {!Blockly.blockRendering.Renderer}
|
||||
* @type {!Renderer}
|
||||
* @protected
|
||||
*/
|
||||
this.renderer_ = renderer;
|
||||
|
||||
/**
|
||||
* The renderer's constant provider.
|
||||
* @type {!Blockly.blockRendering.ConstantProvider}
|
||||
* @type {!ConstantProvider}
|
||||
* @protected
|
||||
*/
|
||||
this.constants_ = this.renderer_.getConstants();
|
||||
@@ -75,12 +83,13 @@ Blockly.blockRendering.RenderInfo = function(renderer, block) {
|
||||
/**
|
||||
* A measurable representing the output connection if the block has one.
|
||||
* Otherwise null.
|
||||
* @type {Blockly.blockRendering.OutputConnection}
|
||||
* @type {OutputConnection}
|
||||
*/
|
||||
this.outputConnection = !block.outputConnection ? null :
|
||||
new Blockly.blockRendering.OutputConnection(
|
||||
this.outputConnection = !block.outputConnection ?
|
||||
null :
|
||||
new OutputConnection(
|
||||
this.constants_,
|
||||
/** @type {Blockly.RenderedConnection} */(block.outputConnection));
|
||||
/** @type {RenderedConnection} */ (block.outputConnection));
|
||||
|
||||
/**
|
||||
* Whether the block should be rendered as a single line, either because it's
|
||||
@@ -135,33 +144,33 @@ Blockly.blockRendering.RenderInfo = function(renderer, block) {
|
||||
|
||||
/**
|
||||
* An array of Row objects containing sizing information.
|
||||
* @type {!Array<!Blockly.blockRendering.Row>}
|
||||
* @type {!Array<!Row>}
|
||||
*/
|
||||
this.rows = [];
|
||||
|
||||
/**
|
||||
* An array of input rows on the block.
|
||||
* @type {!Array<!Blockly.blockRendering.InputRow>}
|
||||
* @type {!Array<!InputRow>}
|
||||
*/
|
||||
this.inputRows = [];
|
||||
|
||||
/**
|
||||
* An array of measurable objects containing hidden icons.
|
||||
* @type {!Array<!Blockly.blockRendering.Icon>}
|
||||
* @type {!Array<!Icon>}
|
||||
*/
|
||||
this.hiddenIcons = [];
|
||||
|
||||
/**
|
||||
* An object with rendering information about the top row of the block.
|
||||
* @type {!Blockly.blockRendering.TopRow}
|
||||
* @type {!TopRow}
|
||||
*/
|
||||
this.topRow = new Blockly.blockRendering.TopRow(this.constants_);
|
||||
this.topRow = new TopRow(this.constants_);
|
||||
|
||||
/**
|
||||
* An object with rendering information about the bottom row of the block.
|
||||
* @type {!Blockly.blockRendering.BottomRow}
|
||||
* @type {!BottomRow}
|
||||
*/
|
||||
this.bottomRow = new Blockly.blockRendering.BottomRow(this.constants_);
|
||||
this.bottomRow = new BottomRow(this.constants_);
|
||||
|
||||
// The position of the start point for drawing, relative to the block's
|
||||
// location.
|
||||
@@ -171,10 +180,10 @@ Blockly.blockRendering.RenderInfo = function(renderer, block) {
|
||||
|
||||
/**
|
||||
* Get the block renderer in use.
|
||||
* @return {!Blockly.blockRendering.Renderer} The block renderer in use.
|
||||
* @return {!Renderer} The block renderer in use.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.getRenderer = function() {
|
||||
RenderInfo.prototype.getRenderer = function() {
|
||||
return this.renderer_;
|
||||
};
|
||||
|
||||
@@ -188,7 +197,7 @@ Blockly.blockRendering.RenderInfo.prototype.getRenderer = function() {
|
||||
*
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.measure = function() {
|
||||
RenderInfo.prototype.measure = function() {
|
||||
this.createRows_();
|
||||
this.addElemSpacing_();
|
||||
this.addRowSpacing_();
|
||||
@@ -202,16 +211,16 @@ Blockly.blockRendering.RenderInfo.prototype.measure = function() {
|
||||
* block.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.createRows_ = function() {
|
||||
RenderInfo.prototype.createRows_ = function() {
|
||||
this.populateTopRow_();
|
||||
this.rows.push(this.topRow);
|
||||
var activeRow = new Blockly.blockRendering.InputRow(this.constants_);
|
||||
let activeRow = new InputRow(this.constants_);
|
||||
this.inputRows.push(activeRow);
|
||||
|
||||
// Icons always go on the first row, before anything else.
|
||||
var icons = this.block_.getIcons();
|
||||
for (var i = 0, icon; (icon = icons[i]); i++) {
|
||||
var iconInfo = new Blockly.blockRendering.Icon(this.constants_, icon);
|
||||
const icons = this.block_.getIcons();
|
||||
for (let i = 0, icon; (icon = icons[i]); i++) {
|
||||
const iconInfo = new Icon(this.constants_, icon);
|
||||
if (this.isCollapsed && icon.collapseHidden) {
|
||||
this.hiddenIcons.push(iconInfo);
|
||||
} else {
|
||||
@@ -219,24 +228,23 @@ Blockly.blockRendering.RenderInfo.prototype.createRows_ = function() {
|
||||
}
|
||||
}
|
||||
|
||||
var lastInput = null;
|
||||
let lastInput = null;
|
||||
// Loop across all of the inputs on the block, creating objects for anything
|
||||
// that needs to be rendered and breaking the block up into visual rows.
|
||||
for (var i = 0, input; (input = this.block_.inputList[i]); i++) {
|
||||
for (let i = 0, input; (input = this.block_.inputList[i]); i++) {
|
||||
if (!input.isVisible()) {
|
||||
continue;
|
||||
}
|
||||
if (this.shouldStartNewRow_(input, lastInput)) {
|
||||
// Finish this row and create a new one.
|
||||
this.rows.push(activeRow);
|
||||
activeRow = new Blockly.blockRendering.InputRow(this.constants_);
|
||||
activeRow = new InputRow(this.constants_);
|
||||
this.inputRows.push(activeRow);
|
||||
}
|
||||
|
||||
// All of the fields in an input go on the same row.
|
||||
for (var j = 0, field; (field = input.fieldRow[j]); j++) {
|
||||
activeRow.elements.push(
|
||||
new Blockly.blockRendering.Field(this.constants_, field, input));
|
||||
for (let j = 0, field; (field = input.fieldRow[j]); j++) {
|
||||
activeRow.elements.push(new Field(this.constants_, field, input));
|
||||
}
|
||||
this.addInput_(input, activeRow);
|
||||
lastInput = input;
|
||||
@@ -244,8 +252,7 @@ Blockly.blockRendering.RenderInfo.prototype.createRows_ = function() {
|
||||
|
||||
if (this.isCollapsed) {
|
||||
activeRow.hasJaggedEdge = true;
|
||||
activeRow.elements.push(
|
||||
new Blockly.blockRendering.JaggedEdge(this.constants_));
|
||||
activeRow.elements.push(new JaggedEdge(this.constants_));
|
||||
}
|
||||
|
||||
if (activeRow.elements.length || activeRow.hasDummyInput) {
|
||||
@@ -259,31 +266,31 @@ Blockly.blockRendering.RenderInfo.prototype.createRows_ = function() {
|
||||
* Create all non-spacer elements that belong on the top row.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.populateTopRow_ = function() {
|
||||
var hasPrevious = !!this.block_.previousConnection;
|
||||
var hasHat = (this.block_.hat ?
|
||||
this.block_.hat === 'cap' : this.constants_.ADD_START_HATS) &&
|
||||
RenderInfo.prototype.populateTopRow_ = function() {
|
||||
const hasPrevious = !!this.block_.previousConnection;
|
||||
const hasHat = (this.block_.hat ? this.block_.hat === 'cap' :
|
||||
this.constants_.ADD_START_HATS) &&
|
||||
!this.outputConnection && !hasPrevious;
|
||||
|
||||
var cornerClass = this.topRow.hasLeftSquareCorner(this.block_) ?
|
||||
Blockly.blockRendering.SquareCorner : Blockly.blockRendering.RoundCorner;
|
||||
let cornerClass =
|
||||
this.topRow.hasLeftSquareCorner(this.block_) ? SquareCorner : RoundCorner;
|
||||
this.topRow.elements.push(new cornerClass(this.constants_));
|
||||
|
||||
if (hasHat) {
|
||||
var hat = new Blockly.blockRendering.Hat(this.constants_);
|
||||
const hat = new Hat(this.constants_);
|
||||
this.topRow.elements.push(hat);
|
||||
this.topRow.capline = hat.ascenderHeight;
|
||||
} else if (hasPrevious) {
|
||||
this.topRow.hasPreviousConnection = true;
|
||||
this.topRow.connection = new Blockly.blockRendering.PreviousConnection(
|
||||
this.topRow.connection = new PreviousConnection(
|
||||
this.constants_,
|
||||
/** @type {Blockly.RenderedConnection} */
|
||||
/** @type {RenderedConnection} */
|
||||
(this.block_.previousConnection));
|
||||
this.topRow.elements.push(this.topRow.connection);
|
||||
}
|
||||
|
||||
var precedesStatement = this.block_.inputList.length &&
|
||||
this.block_.inputList[0].type == Blockly.inputTypes.STATEMENT;
|
||||
const precedesStatement = this.block_.inputList.length &&
|
||||
this.block_.inputList[0].type == STATEMENT;
|
||||
|
||||
// This is the minimum height for the row. If one of its elements has a
|
||||
// greater height it will be overwritten in the compute pass.
|
||||
@@ -294,8 +301,8 @@ Blockly.blockRendering.RenderInfo.prototype.populateTopRow_ = function() {
|
||||
this.topRow.minHeight = this.constants_.TOP_ROW_MIN_HEIGHT;
|
||||
}
|
||||
|
||||
cornerClass = this.topRow.hasRightSquareCorner(this.block_) ?
|
||||
Blockly.blockRendering.SquareCorner : Blockly.blockRendering.RoundCorner;
|
||||
cornerClass = this.topRow.hasRightSquareCorner(this.block_) ? SquareCorner :
|
||||
RoundCorner;
|
||||
this.topRow.elements.push(new cornerClass(this.constants_, 'right'));
|
||||
};
|
||||
|
||||
@@ -303,79 +310,72 @@ Blockly.blockRendering.RenderInfo.prototype.populateTopRow_ = function() {
|
||||
* Create all non-spacer elements that belong on the bottom row.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.populateBottomRow_ = function() {
|
||||
RenderInfo.prototype.populateBottomRow_ = function() {
|
||||
this.bottomRow.hasNextConnection = !!this.block_.nextConnection;
|
||||
|
||||
var followsStatement = this.block_.inputList.length &&
|
||||
this.block_.inputList[this.block_.inputList.length - 1].type ==
|
||||
Blockly.inputTypes.STATEMENT;
|
||||
const followsStatement = this.block_.inputList.length &&
|
||||
this.block_.inputList[this.block_.inputList.length - 1].type == STATEMENT;
|
||||
|
||||
// This is the minimum height for the row. If one of its elements has a
|
||||
// greater height it will be overwritten in the compute pass.
|
||||
if (followsStatement) {
|
||||
this.bottomRow.minHeight =
|
||||
this.constants_.BOTTOM_ROW_AFTER_STATEMENT_MIN_HEIGHT;
|
||||
this.constants_.BOTTOM_ROW_AFTER_STATEMENT_MIN_HEIGHT;
|
||||
} else {
|
||||
this.bottomRow.minHeight = this.constants_.BOTTOM_ROW_MIN_HEIGHT;
|
||||
}
|
||||
|
||||
var leftSquareCorner = this.bottomRow.hasLeftSquareCorner(this.block_);
|
||||
const leftSquareCorner = this.bottomRow.hasLeftSquareCorner(this.block_);
|
||||
|
||||
if (leftSquareCorner) {
|
||||
this.bottomRow.elements.push(
|
||||
new Blockly.blockRendering.SquareCorner(this.constants_));
|
||||
this.bottomRow.elements.push(new SquareCorner(this.constants_));
|
||||
} else {
|
||||
this.bottomRow.elements.push(
|
||||
new Blockly.blockRendering.RoundCorner(this.constants_));
|
||||
this.bottomRow.elements.push(new RoundCorner(this.constants_));
|
||||
}
|
||||
|
||||
if (this.bottomRow.hasNextConnection) {
|
||||
this.bottomRow.connection = new Blockly.blockRendering.NextConnection(
|
||||
this.bottomRow.connection = new NextConnection(
|
||||
this.constants_,
|
||||
/** @type {Blockly.RenderedConnection} */ (this.block_.nextConnection));
|
||||
/** @type {RenderedConnection} */ (this.block_.nextConnection));
|
||||
this.bottomRow.elements.push(this.bottomRow.connection);
|
||||
}
|
||||
|
||||
var rightSquareCorner = this.bottomRow.hasRightSquareCorner(this.block_);
|
||||
const rightSquareCorner = this.bottomRow.hasRightSquareCorner(this.block_);
|
||||
|
||||
if (rightSquareCorner) {
|
||||
this.bottomRow.elements.push(
|
||||
new Blockly.blockRendering.SquareCorner(this.constants_, 'right'));
|
||||
this.bottomRow.elements.push(new SquareCorner(this.constants_, 'right'));
|
||||
} else {
|
||||
this.bottomRow.elements.push(
|
||||
new Blockly.blockRendering.RoundCorner(this.constants_, 'right'));
|
||||
this.bottomRow.elements.push(new RoundCorner(this.constants_, 'right'));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add an input element to the active row, if needed, and record the type of the
|
||||
* input on the row.
|
||||
* @param {!Blockly.Input} input The input to record information about.
|
||||
* @param {!Blockly.blockRendering.Row} activeRow The row that is currently being
|
||||
* @param {!Input} input The input to record information about.
|
||||
* @param {!Row} activeRow The row that is currently being
|
||||
* populated.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.addInput_ = function(input, activeRow) {
|
||||
RenderInfo.prototype.addInput_ = function(input, activeRow) {
|
||||
// Non-dummy inputs have visual representations onscreen.
|
||||
if (this.isInline && input.type == Blockly.inputTypes.VALUE) {
|
||||
activeRow.elements.push(
|
||||
new Blockly.blockRendering.InlineInput(this.constants_, input));
|
||||
if (this.isInline && input.type == VALUE) {
|
||||
activeRow.elements.push(new InlineInput(this.constants_, input));
|
||||
activeRow.hasInlineInput = true;
|
||||
} else if (input.type == Blockly.inputTypes.STATEMENT) {
|
||||
activeRow.elements.push(
|
||||
new Blockly.blockRendering.StatementInput(this.constants_, input));
|
||||
} else if (input.type == STATEMENT) {
|
||||
activeRow.elements.push(new StatementInput(this.constants_, input));
|
||||
activeRow.hasStatement = true;
|
||||
} else if (input.type == Blockly.inputTypes.VALUE) {
|
||||
activeRow.elements.push(
|
||||
new Blockly.blockRendering.ExternalValueInput(this.constants_, input));
|
||||
} else if (input.type == VALUE) {
|
||||
activeRow.elements.push(new ExternalValueInput(this.constants_, input));
|
||||
activeRow.hasExternalInput = true;
|
||||
} else if (input.type == Blockly.inputTypes.DUMMY) {
|
||||
} else if (input.type == DUMMY) {
|
||||
// Dummy inputs have no visual representation, but the information is still
|
||||
// important.
|
||||
activeRow.minHeight = Math.max(activeRow.minHeight,
|
||||
activeRow.minHeight = Math.max(
|
||||
activeRow.minHeight,
|
||||
input.getSourceBlock() && input.getSourceBlock().isShadow() ?
|
||||
this.constants_.DUMMY_INPUT_SHADOW_MIN_HEIGHT :
|
||||
this.constants_.DUMMY_INPUT_MIN_HEIGHT);
|
||||
this.constants_.DUMMY_INPUT_SHADOW_MIN_HEIGHT :
|
||||
this.constants_.DUMMY_INPUT_MIN_HEIGHT);
|
||||
activeRow.hasDummyInput = true;
|
||||
}
|
||||
if (activeRow.align == null) {
|
||||
@@ -385,25 +385,23 @@ Blockly.blockRendering.RenderInfo.prototype.addInput_ = function(input, activeRo
|
||||
|
||||
/**
|
||||
* Decide whether to start a new row between the two Blockly.Inputs.
|
||||
* @param {!Blockly.Input} input The first input to consider
|
||||
* @param {Blockly.Input} lastInput The input that follows.
|
||||
* @param {!Input} input The first input to consider
|
||||
* @param {Input} lastInput The input that follows.
|
||||
* @return {boolean} True if the next input should be rendered on a new row.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.shouldStartNewRow_ = function(input, lastInput) {
|
||||
RenderInfo.prototype.shouldStartNewRow_ = function(input, lastInput) {
|
||||
// If this is the first input, just add to the existing row.
|
||||
// That row is either empty or has some icons in it.
|
||||
if (!lastInput) {
|
||||
return false;
|
||||
}
|
||||
// A statement input or an input following one always gets a new row.
|
||||
if (input.type == Blockly.inputTypes.STATEMENT ||
|
||||
lastInput.type == Blockly.inputTypes.STATEMENT) {
|
||||
if (input.type == STATEMENT || lastInput.type == STATEMENT) {
|
||||
return true;
|
||||
}
|
||||
// Value and dummy inputs get new row if inputs are not inlined.
|
||||
if (input.type == Blockly.inputTypes.VALUE ||
|
||||
input.type == Blockly.inputTypes.DUMMY) {
|
||||
if (input.type == VALUE || input.type == DUMMY) {
|
||||
return !this.isInline;
|
||||
}
|
||||
return false;
|
||||
@@ -413,29 +411,28 @@ Blockly.blockRendering.RenderInfo.prototype.shouldStartNewRow_ = function(input,
|
||||
* Add horizontal spacing between and around elements within each row.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.addElemSpacing_ = function() {
|
||||
for (var i = 0, row; (row = this.rows[i]); i++) {
|
||||
var oldElems = row.elements;
|
||||
RenderInfo.prototype.addElemSpacing_ = function() {
|
||||
for (let i = 0, row; (row = this.rows[i]); i++) {
|
||||
const oldElems = row.elements;
|
||||
row.elements = [];
|
||||
// No spacing needed before the corner on the top row or the bottom row.
|
||||
if (row.startsWithElemSpacer()) {
|
||||
// There's a spacer before the first element in the row.
|
||||
row.elements.push(new Blockly.blockRendering.InRowSpacer(
|
||||
row.elements.push(new InRowSpacer(
|
||||
this.constants_, this.getInRowSpacing_(null, oldElems[0])));
|
||||
}
|
||||
if (!oldElems.length) {
|
||||
continue;
|
||||
}
|
||||
for (var e = 0; e < oldElems.length - 1; e++) {
|
||||
for (let e = 0; e < oldElems.length - 1; e++) {
|
||||
row.elements.push(oldElems[e]);
|
||||
var spacing = this.getInRowSpacing_(oldElems[e], oldElems[e + 1]);
|
||||
row.elements.push(
|
||||
new Blockly.blockRendering.InRowSpacer(this.constants_, spacing));
|
||||
const spacing = this.getInRowSpacing_(oldElems[e], oldElems[e + 1]);
|
||||
row.elements.push(new InRowSpacer(this.constants_, spacing));
|
||||
}
|
||||
row.elements.push(oldElems[oldElems.length - 1]);
|
||||
if (row.endsWithElemSpacer()) {
|
||||
// There's a spacer after the last element in the row.
|
||||
row.elements.push(new Blockly.blockRendering.InRowSpacer(
|
||||
row.elements.push(new InRowSpacer(
|
||||
this.constants_,
|
||||
this.getInRowSpacing_(oldElems[oldElems.length - 1], null)));
|
||||
}
|
||||
@@ -446,42 +443,40 @@ Blockly.blockRendering.RenderInfo.prototype.addElemSpacing_ = function() {
|
||||
* Calculate the width of a spacer element in a row based on the previous and
|
||||
* next elements in that row. For instance, extra padding is added between two
|
||||
* editable fields.
|
||||
* @param {Blockly.blockRendering.Measurable} prev The element before the
|
||||
* @param {Measurable} prev The element before the
|
||||
* spacer.
|
||||
* @param {Blockly.blockRendering.Measurable} next The element after the spacer.
|
||||
* @param {Measurable} next The element after the spacer.
|
||||
* @return {number} The size of the spacing between the two elements.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.getInRowSpacing_ = function(prev, next) {
|
||||
RenderInfo.prototype.getInRowSpacing_ = function(prev, next) {
|
||||
if (!prev) {
|
||||
// Statement input padding.
|
||||
if (next && Blockly.blockRendering.Types.isStatementInput(next)) {
|
||||
if (next && Types.isStatementInput(next)) {
|
||||
return this.constants_.STATEMENT_INPUT_PADDING_LEFT;
|
||||
}
|
||||
}
|
||||
// Between inputs and the end of the row.
|
||||
if (prev && Blockly.blockRendering.Types.isInput(prev) && !next) {
|
||||
if (Blockly.blockRendering.Types.isExternalInput(prev)) {
|
||||
if (prev && Types.isInput(prev) && !next) {
|
||||
if (Types.isExternalInput(prev)) {
|
||||
return this.constants_.NO_PADDING;
|
||||
} else if (Blockly.blockRendering.Types.isInlineInput(prev)) {
|
||||
} else if (Types.isInlineInput(prev)) {
|
||||
return this.constants_.LARGE_PADDING;
|
||||
} else if (Blockly.blockRendering.Types.isStatementInput(prev)) {
|
||||
} else if (Types.isStatementInput(prev)) {
|
||||
return this.constants_.NO_PADDING;
|
||||
}
|
||||
}
|
||||
|
||||
// Spacing between a square corner and a previous or next connection
|
||||
if (prev && Blockly.blockRendering.Types.isLeftSquareCorner(prev) && next) {
|
||||
if (Blockly.blockRendering.Types.isPreviousConnection(next) ||
|
||||
Blockly.blockRendering.Types.isNextConnection(next)) {
|
||||
if (prev && Types.isLeftSquareCorner(prev) && next) {
|
||||
if (Types.isPreviousConnection(next) || Types.isNextConnection(next)) {
|
||||
return next.notchOffset;
|
||||
}
|
||||
}
|
||||
|
||||
// Spacing between a rounded corner and a previous or next connection.
|
||||
if (prev && Blockly.blockRendering.Types.isLeftRoundedCorner(prev) && next) {
|
||||
if (Blockly.blockRendering.Types.isPreviousConnection(next) ||
|
||||
Blockly.blockRendering.Types.isNextConnection(next)) {
|
||||
if (prev && Types.isLeftRoundedCorner(prev) && next) {
|
||||
if (Types.isPreviousConnection(next) || Types.isNextConnection(next)) {
|
||||
return next.notchOffset - this.constants_.CORNER_RADIUS;
|
||||
}
|
||||
}
|
||||
@@ -490,21 +485,21 @@ Blockly.blockRendering.RenderInfo.prototype.getInRowSpacing_ = function(prev, ne
|
||||
};
|
||||
|
||||
/**
|
||||
* Figure out where the right edge of the block and right edge of statement inputs
|
||||
* should be placed.
|
||||
* Figure out where the right edge of the block and right edge of statement
|
||||
* inputs should be placed.
|
||||
* @protected
|
||||
*/
|
||||
// TODO: More cleanup.
|
||||
Blockly.blockRendering.RenderInfo.prototype.computeBounds_ = function() {
|
||||
var widestStatementRowFields = 0;
|
||||
var blockWidth = 0;
|
||||
var widestRowWithConnectedBlocks = 0;
|
||||
for (var i = 0, row; (row = this.rows[i]); i++) {
|
||||
RenderInfo.prototype.computeBounds_ = function() {
|
||||
let widestStatementRowFields = 0;
|
||||
let blockWidth = 0;
|
||||
let widestRowWithConnectedBlocks = 0;
|
||||
for (let i = 0, row; (row = this.rows[i]); i++) {
|
||||
row.measure();
|
||||
blockWidth = Math.max(blockWidth, row.width);
|
||||
if (row.hasStatement) {
|
||||
var statementInput = row.getLastInput();
|
||||
var innerWidth = row.width - statementInput.width;
|
||||
const statementInput = row.getLastInput();
|
||||
const innerWidth = row.width - statementInput.width;
|
||||
widestStatementRowFields = Math.max(widestStatementRowFields, innerWidth);
|
||||
}
|
||||
widestRowWithConnectedBlocks =
|
||||
@@ -514,7 +509,7 @@ Blockly.blockRendering.RenderInfo.prototype.computeBounds_ = function() {
|
||||
this.statementEdge = widestStatementRowFields;
|
||||
this.width = blockWidth;
|
||||
|
||||
for (var i = 0, row; (row = this.rows[i]); i++) {
|
||||
for (let i = 0, row; (row = this.rows[i]); i++) {
|
||||
if (row.hasStatement) {
|
||||
row.statementEdge = this.statementEdge;
|
||||
}
|
||||
@@ -535,19 +530,19 @@ Blockly.blockRendering.RenderInfo.prototype.computeBounds_ = function() {
|
||||
* the sizes of all rows.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.alignRowElements_ = function() {
|
||||
for (var i = 0, row; (row = this.rows[i]); i++) {
|
||||
RenderInfo.prototype.alignRowElements_ = function() {
|
||||
for (let i = 0, row; (row = this.rows[i]); i++) {
|
||||
if (row.hasStatement) {
|
||||
this.alignStatementRow_(
|
||||
/** @type {!Blockly.blockRendering.InputRow} */ (row));
|
||||
/** @type {!InputRow} */ (row));
|
||||
} else {
|
||||
var currentWidth = row.width;
|
||||
var desiredWidth = this.getDesiredRowWidth_(row);
|
||||
var missingSpace = desiredWidth - currentWidth;
|
||||
const currentWidth = row.width;
|
||||
const desiredWidth = this.getDesiredRowWidth_(row);
|
||||
const missingSpace = desiredWidth - currentWidth;
|
||||
if (missingSpace > 0) {
|
||||
this.addAlignmentPadding_(row, missingSpace);
|
||||
}
|
||||
if (Blockly.blockRendering.Types.isTopOrBottomRow(row)) {
|
||||
if (Types.isTopOrBottomRow(row)) {
|
||||
row.widthWithConnectedBlocks = row.width;
|
||||
}
|
||||
}
|
||||
@@ -556,12 +551,11 @@ Blockly.blockRendering.RenderInfo.prototype.alignRowElements_ = function() {
|
||||
|
||||
/**
|
||||
* Calculate the desired width of an input row.
|
||||
* @param {!Blockly.blockRendering.Row} _row The input row.
|
||||
* @param {!Row} _row The input row.
|
||||
* @return {number} The desired width of the input row.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.getDesiredRowWidth_ = function(
|
||||
_row) {
|
||||
RenderInfo.prototype.getDesiredRowWidth_ = function(_row) {
|
||||
return this.width - this.startX;
|
||||
};
|
||||
|
||||
@@ -569,27 +563,26 @@ Blockly.blockRendering.RenderInfo.prototype.getDesiredRowWidth_ = function(
|
||||
* Modify the given row to add the given amount of padding around its fields.
|
||||
* The exact location of the padding is based on the alignment property of the
|
||||
* last input in the field.
|
||||
* @param {Blockly.blockRendering.Row} row The row to add padding to.
|
||||
* @param {Row} row The row to add padding to.
|
||||
* @param {number} missingSpace How much padding to add.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.addAlignmentPadding_ = function(row,
|
||||
missingSpace) {
|
||||
var firstSpacer = row.getFirstSpacer();
|
||||
var lastSpacer = row.getLastSpacer();
|
||||
RenderInfo.prototype.addAlignmentPadding_ = function(row, missingSpace) {
|
||||
const firstSpacer = row.getFirstSpacer();
|
||||
const lastSpacer = row.getLastSpacer();
|
||||
if (row.hasExternalInput || row.hasStatement) {
|
||||
row.widthWithConnectedBlocks += missingSpace;
|
||||
}
|
||||
|
||||
// Decide where the extra padding goes.
|
||||
if (row.align == Blockly.constants.ALIGN.LEFT) {
|
||||
if (row.align == ALIGN.LEFT) {
|
||||
// Add padding to the end of the row.
|
||||
lastSpacer.width += missingSpace;
|
||||
} else if (row.align == Blockly.constants.ALIGN.CENTRE) {
|
||||
} else if (row.align == ALIGN.CENTRE) {
|
||||
// Split the padding between the beginning and end of the row.
|
||||
firstSpacer.width += missingSpace / 2;
|
||||
lastSpacer.width += missingSpace / 2;
|
||||
} else if (row.align == Blockly.constants.ALIGN.RIGHT) {
|
||||
} else if (row.align == ALIGN.RIGHT) {
|
||||
// Add padding at the beginning of the row.
|
||||
firstSpacer.width += missingSpace;
|
||||
} else {
|
||||
@@ -602,15 +595,15 @@ Blockly.blockRendering.RenderInfo.prototype.addAlignmentPadding_ = function(row,
|
||||
/**
|
||||
* Align the elements of a statement row based on computed bounds.
|
||||
* Unlike other types of rows, statement rows add space in multiple places.
|
||||
* @param {!Blockly.blockRendering.InputRow} row The statement row to resize.
|
||||
* @param {!InputRow} row The statement row to resize.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.alignStatementRow_ = function(row) {
|
||||
var statementInput = row.getLastInput();
|
||||
var currentWidth = row.width - statementInput.width;
|
||||
var desiredWidth = this.statementEdge;
|
||||
RenderInfo.prototype.alignStatementRow_ = function(row) {
|
||||
const statementInput = row.getLastInput();
|
||||
let currentWidth = row.width - statementInput.width;
|
||||
let desiredWidth = this.statementEdge;
|
||||
// Add padding before the statement input.
|
||||
var missingSpace = desiredWidth - currentWidth;
|
||||
const missingSpace = desiredWidth - currentWidth;
|
||||
if (missingSpace > 0) {
|
||||
this.addAlignmentPadding_(row, missingSpace);
|
||||
}
|
||||
@@ -621,19 +614,19 @@ Blockly.blockRendering.RenderInfo.prototype.alignStatementRow_ = function(row) {
|
||||
statementInput.width += (desiredWidth - currentWidth);
|
||||
statementInput.height = Math.max(statementInput.height, row.height);
|
||||
row.width += (desiredWidth - currentWidth);
|
||||
row.widthWithConnectedBlocks = Math.max(row.width,
|
||||
this.statementEdge + row.connectedBlockWidths);
|
||||
row.widthWithConnectedBlocks =
|
||||
Math.max(row.width, this.statementEdge + row.connectedBlockWidths);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add spacers between rows and set their sizes.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.addRowSpacing_ = function() {
|
||||
var oldRows = this.rows;
|
||||
RenderInfo.prototype.addRowSpacing_ = function() {
|
||||
const oldRows = this.rows;
|
||||
this.rows = [];
|
||||
|
||||
for (var r = 0; r < oldRows.length; r++) {
|
||||
for (let r = 0; r < oldRows.length; r++) {
|
||||
this.rows.push(oldRows[r]);
|
||||
if (r != oldRows.length - 1) {
|
||||
this.rows.push(this.makeSpacerRow_(oldRows[r], oldRows[r + 1]));
|
||||
@@ -643,16 +636,15 @@ Blockly.blockRendering.RenderInfo.prototype.addRowSpacing_ = function() {
|
||||
|
||||
/**
|
||||
* Create a spacer row to go between prev and next, and set its size.
|
||||
* @param {!Blockly.blockRendering.Row} prev The previous row.
|
||||
* @param {!Blockly.blockRendering.Row} next The next row.
|
||||
* @return {!Blockly.blockRendering.SpacerRow} The newly created spacer row.
|
||||
* @param {!Row} prev The previous row.
|
||||
* @param {!Row} next The next row.
|
||||
* @return {!SpacerRow} The newly created spacer row.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.makeSpacerRow_ = function(prev, next) {
|
||||
var height = this.getSpacerRowHeight_(prev, next);
|
||||
var width = this.getSpacerRowWidth_(prev, next);
|
||||
var spacer = new Blockly.blockRendering.SpacerRow(
|
||||
this.constants_, height, width);
|
||||
RenderInfo.prototype.makeSpacerRow_ = function(prev, next) {
|
||||
const height = this.getSpacerRowHeight_(prev, next);
|
||||
const width = this.getSpacerRowWidth_(prev, next);
|
||||
const spacer = new SpacerRow(this.constants_, height, width);
|
||||
if (prev.hasStatement) {
|
||||
spacer.followsStatement = true;
|
||||
}
|
||||
@@ -664,25 +656,23 @@ Blockly.blockRendering.RenderInfo.prototype.makeSpacerRow_ = function(prev, next
|
||||
|
||||
/**
|
||||
* Calculate the width of a spacer row.
|
||||
* @param {!Blockly.blockRendering.Row} _prev The row before the spacer.
|
||||
* @param {!Blockly.blockRendering.Row} _next The row after the spacer.
|
||||
* @param {!Row} _prev The row before the spacer.
|
||||
* @param {!Row} _next The row after the spacer.
|
||||
* @return {number} The desired width of the spacer row between these two rows.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.getSpacerRowWidth_ = function(
|
||||
_prev, _next) {
|
||||
RenderInfo.prototype.getSpacerRowWidth_ = function(_prev, _next) {
|
||||
return this.width - this.startX;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the height of a spacer row.
|
||||
* @param {!Blockly.blockRendering.Row} _prev The row before the spacer.
|
||||
* @param {!Blockly.blockRendering.Row} _next The row after the spacer.
|
||||
* @param {!Row} _prev The row before the spacer.
|
||||
* @param {!Row} _next The row after the spacer.
|
||||
* @return {number} The desired height of the spacer row between these two rows.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.getSpacerRowHeight_ = function(
|
||||
_prev, _next) {
|
||||
RenderInfo.prototype.getSpacerRowHeight_ = function(_prev, _next) {
|
||||
return this.constants_.MEDIUM_PADDING;
|
||||
};
|
||||
|
||||
@@ -691,26 +681,25 @@ Blockly.blockRendering.RenderInfo.prototype.getSpacerRowHeight_ = function(
|
||||
* This base implementation puts the centerline at the middle of the row
|
||||
* vertically, with no special cases. You will likely need extra logic to
|
||||
* handle (at minimum) top and bottom rows.
|
||||
* @param {!Blockly.blockRendering.Row} row The row containing the element.
|
||||
* @param {!Blockly.blockRendering.Measurable} elem The element to place.
|
||||
* @param {!Row} row The row containing the element.
|
||||
* @param {!Measurable} elem The element to place.
|
||||
* @return {number} The desired centerline of the given element, as an offset
|
||||
* from the top left of the block.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.getElemCenterline_ = function(row,
|
||||
elem) {
|
||||
if (Blockly.blockRendering.Types.isSpacer(elem)) {
|
||||
RenderInfo.prototype.getElemCenterline_ = function(row, elem) {
|
||||
if (Types.isSpacer(elem)) {
|
||||
return row.yPos + elem.height / 2;
|
||||
}
|
||||
if (Blockly.blockRendering.Types.isBottomRow(row)) {
|
||||
var baseline = row.yPos + row.height - row.descenderHeight;
|
||||
if (Blockly.blockRendering.Types.isNextConnection(elem)) {
|
||||
if (Types.isBottomRow(row)) {
|
||||
const baseline = row.yPos + row.height - row.descenderHeight;
|
||||
if (Types.isNextConnection(elem)) {
|
||||
return baseline + elem.height / 2;
|
||||
}
|
||||
return baseline - elem.height / 2;
|
||||
}
|
||||
if (Blockly.blockRendering.Types.isTopRow(row)) {
|
||||
if (Blockly.blockRendering.Types.isHat(elem)) {
|
||||
if (Types.isTopRow(row)) {
|
||||
if (Types.isHat(elem)) {
|
||||
return row.capline - elem.height / 2;
|
||||
}
|
||||
return row.capline + elem.height / 2;
|
||||
@@ -721,15 +710,14 @@ Blockly.blockRendering.RenderInfo.prototype.getElemCenterline_ = function(row,
|
||||
/**
|
||||
* Record final position information on elements on the given row, for use in
|
||||
* drawing. At minimum this records xPos and centerline on each element.
|
||||
* @param {!Blockly.blockRendering.Row} row The row containing the elements.
|
||||
* @param {!Row} row The row containing the elements.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.recordElemPositions_ = function(
|
||||
row) {
|
||||
var xCursor = row.xPos;
|
||||
for (var j = 0, elem; (elem = row.elements[j]); j++) {
|
||||
RenderInfo.prototype.recordElemPositions_ = function(row) {
|
||||
let xCursor = row.xPos;
|
||||
for (let j = 0, elem; (elem = row.elements[j]); j++) {
|
||||
// Now that row heights are finalized, make spacers use the row height.
|
||||
if (Blockly.blockRendering.Types.isSpacer(elem)) {
|
||||
if (Types.isSpacer(elem)) {
|
||||
elem.height = row.height;
|
||||
}
|
||||
elem.xPos = xCursor;
|
||||
@@ -743,13 +731,13 @@ Blockly.blockRendering.RenderInfo.prototype.recordElemPositions_ = function(
|
||||
* store the y position of each row, and record the height of the full block.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.blockRendering.RenderInfo.prototype.finalize_ = function() {
|
||||
RenderInfo.prototype.finalize_ = function() {
|
||||
// Performance note: this could be combined with the draw pass, if the time
|
||||
// that this takes is excessive. But it shouldn't be, because it only
|
||||
// accesses and sets properties that already exist on the objects.
|
||||
var widestRowWithConnectedBlocks = 0;
|
||||
var yCursor = 0;
|
||||
for (var i = 0, row; (row = this.rows[i]); i++) {
|
||||
let widestRowWithConnectedBlocks = 0;
|
||||
let yCursor = 0;
|
||||
for (let i = 0, row; (row = this.rows[i]); i++) {
|
||||
row.yPos = yCursor;
|
||||
row.xPos = this.startX;
|
||||
yCursor += row.height;
|
||||
@@ -761,9 +749,9 @@ Blockly.blockRendering.RenderInfo.prototype.finalize_ = function() {
|
||||
if (this.outputConnection && this.block_.nextConnection &&
|
||||
this.block_.nextConnection.isConnected()) {
|
||||
// Include width of connected block in value to stack width measurement.
|
||||
widestRowWithConnectedBlocks =
|
||||
Math.max(widestRowWithConnectedBlocks,
|
||||
this.block_.nextConnection.targetBlock().getHeightWidth().width);
|
||||
widestRowWithConnectedBlocks = Math.max(
|
||||
widestRowWithConnectedBlocks,
|
||||
this.block_.nextConnection.targetBlock().getHeightWidth().width);
|
||||
}
|
||||
|
||||
this.widthWithChildren = widestRowWithConnectedBlocks + this.startX;
|
||||
@@ -772,3 +760,5 @@ Blockly.blockRendering.RenderInfo.prototype.finalize_ = function() {
|
||||
this.startY = this.topRow.capline;
|
||||
this.bottomRow.baseline = yCursor - this.bottomRow.descenderHeight;
|
||||
};
|
||||
|
||||
exports = RenderInfo;
|
||||
|
||||
@@ -15,8 +15,6 @@ goog.provide('Blockly.blockRendering.MarkerSvg');
|
||||
|
||||
goog.require('Blockly.ASTNode');
|
||||
goog.require('Blockly.connectionTypes');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.Events');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.MarkerMove');
|
||||
|
||||
@@ -20,8 +20,6 @@ goog.require('Blockly.blockRendering.MarkerSvg');
|
||||
goog.require('Blockly.blockRendering.PathObject');
|
||||
goog.require('Blockly.blockRendering.RenderInfo');
|
||||
goog.require('Blockly.connectionTypes');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.InsertionMarkerManager');
|
||||
goog.require('Blockly.IRegistrable');
|
||||
|
||||
|
||||
@@ -19,8 +19,6 @@ goog.require('Blockly.blockRendering.InputRow');
|
||||
goog.require('Blockly.blockRendering.InRowSpacer');
|
||||
goog.require('Blockly.blockRendering.RenderInfo');
|
||||
goog.require('Blockly.blockRendering.Types');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.geras.InlineInput');
|
||||
goog.require('Blockly.geras.StatementInput');
|
||||
goog.require('Blockly.inputTypes');
|
||||
|
||||
@@ -15,8 +15,6 @@ goog.provide('Blockly.zelos.ConstantProvider');
|
||||
|
||||
goog.require('Blockly.blockRendering.ConstantProvider');
|
||||
goog.require('Blockly.connectionTypes');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.utils.colour');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.object');
|
||||
|
||||
@@ -18,8 +18,6 @@ goog.require('Blockly.blockRendering.InRowSpacer');
|
||||
goog.require('Blockly.blockRendering.Measurable');
|
||||
goog.require('Blockly.blockRendering.RenderInfo');
|
||||
goog.require('Blockly.blockRendering.Types');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.FieldImage');
|
||||
goog.require('Blockly.FieldLabel');
|
||||
goog.require('Blockly.FieldTextInput');
|
||||
|
||||
@@ -15,8 +15,6 @@ goog.provide('Blockly.zelos.Renderer');
|
||||
goog.require('Blockly.blockRendering');
|
||||
goog.require('Blockly.blockRendering.Renderer');
|
||||
goog.require('Blockly.connectionTypes');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.InsertionMarkerManager');
|
||||
goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.zelos.ConstantProvider');
|
||||
|
||||
@@ -11,27 +11,28 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.ShortcutRegistry');
|
||||
goog.module('Blockly.ShortcutRegistry');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.utils.KeyCodes');
|
||||
goog.require('Blockly.utils.object');
|
||||
|
||||
goog.requireType('Blockly.Workspace');
|
||||
const KeyCodes = goog.require('Blockly.utils.KeyCodes');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Workspace = goog.requireType('Blockly.Workspace');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
|
||||
|
||||
/**
|
||||
* Class for the registry of keyboard shortcuts. This is intended to be a
|
||||
* singleton. You should not create a new instance, and only access this class
|
||||
* from Blockly.ShortcutRegistry.registry.
|
||||
* from ShortcutRegistry.registry.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.ShortcutRegistry = function() {
|
||||
const ShortcutRegistry = function() {
|
||||
// Singleton instance should be registered once.
|
||||
Blockly.ShortcutRegistry.registry = this;
|
||||
ShortcutRegistry.registry = this;
|
||||
|
||||
/**
|
||||
* Registry of all keyboard shortcuts, keyed by name of shortcut.
|
||||
* @type {!Object<string, !Blockly.ShortcutRegistry.KeyboardShortcut>}
|
||||
* @type {!Object<string, !ShortcutRegistry.KeyboardShortcut>}
|
||||
* @private
|
||||
*/
|
||||
this.registry_ = Object.create(null);
|
||||
@@ -46,39 +47,38 @@ Blockly.ShortcutRegistry = function() {
|
||||
|
||||
/**
|
||||
* Enum of valid modifiers.
|
||||
* @enum {!Blockly.utils.KeyCodes<number>}
|
||||
* @enum {!KeyCodes<number>}
|
||||
*/
|
||||
Blockly.ShortcutRegistry.modifierKeys = {
|
||||
'Shift': Blockly.utils.KeyCodes.SHIFT,
|
||||
'Control': Blockly.utils.KeyCodes.CTRL,
|
||||
'Alt': Blockly.utils.KeyCodes.ALT,
|
||||
'Meta': Blockly.utils.KeyCodes.META
|
||||
ShortcutRegistry.modifierKeys = {
|
||||
'Shift': KeyCodes.SHIFT,
|
||||
'Control': KeyCodes.CTRL,
|
||||
'Alt': KeyCodes.ALT,
|
||||
'Meta': KeyCodes.META
|
||||
};
|
||||
|
||||
/**
|
||||
* A keyboard shortcut.
|
||||
* @typedef {{
|
||||
* callback: ((function(!Blockly.Workspace, Event,
|
||||
* !Blockly.ShortcutRegistry.KeyboardShortcut):boolean)|undefined),
|
||||
* callback: ((function(!Workspace, Event,
|
||||
* !ShortcutRegistry.KeyboardShortcut):boolean)|undefined),
|
||||
* name: string,
|
||||
* preconditionFn: ((function(!Blockly.Workspace):boolean)|undefined),
|
||||
* preconditionFn: ((function(!Workspace):boolean)|undefined),
|
||||
* metadata: (Object|undefined)
|
||||
* }}
|
||||
*/
|
||||
Blockly.ShortcutRegistry.KeyboardShortcut;
|
||||
ShortcutRegistry.KeyboardShortcut;
|
||||
|
||||
/**
|
||||
* Registers a keyboard shortcut.
|
||||
* @param {!Blockly.ShortcutRegistry.KeyboardShortcut} shortcut The
|
||||
* @param {!ShortcutRegistry.KeyboardShortcut} shortcut The
|
||||
* shortcut for this key code.
|
||||
* @param {boolean=} opt_allowOverrides True to prevent a warning when
|
||||
* overriding an already registered item.
|
||||
* @throws {Error} if a shortcut with the same name already exists.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ShortcutRegistry.prototype.register = function(
|
||||
shortcut, opt_allowOverrides) {
|
||||
var registeredShortcut = this.registry_[shortcut.name];
|
||||
ShortcutRegistry.prototype.register = function(shortcut, opt_allowOverrides) {
|
||||
const registeredShortcut = this.registry_[shortcut.name];
|
||||
if (registeredShortcut && !opt_allowOverrides) {
|
||||
throw new Error(
|
||||
'Shortcut with name "' + shortcut.name + '" already exists.');
|
||||
@@ -93,8 +93,8 @@ Blockly.ShortcutRegistry.prototype.register = function(
|
||||
* @return {boolean} True if an item was unregistered, false otherwise.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ShortcutRegistry.prototype.unregister = function(shortcutName) {
|
||||
var shortcut = this.registry_[shortcutName];
|
||||
ShortcutRegistry.prototype.unregister = function(shortcutName) {
|
||||
const shortcut = this.registry_[shortcutName];
|
||||
|
||||
if (!shortcut) {
|
||||
console.warn(
|
||||
@@ -110,9 +110,9 @@ Blockly.ShortcutRegistry.prototype.unregister = function(shortcutName) {
|
||||
|
||||
/**
|
||||
* Adds a mapping between a keycode and a keyboard shortcut.
|
||||
* @param {string|Blockly.utils.KeyCodes} keyCode The key code for the keyboard
|
||||
* @param {string|KeyCodes} keyCode The key code for the keyboard
|
||||
* shortcut. If registering a key code with a modifier (ex: ctrl+c) use
|
||||
* Blockly.ShortcutRegistry.registry.createSerializedKey;
|
||||
* ShortcutRegistry.registry.createSerializedKey;
|
||||
* @param {string} shortcutName The name of the shortcut to execute when the
|
||||
* given keycode is pressed.
|
||||
* @param {boolean=} opt_allowCollision True to prevent an error when adding a
|
||||
@@ -120,10 +120,10 @@ Blockly.ShortcutRegistry.prototype.unregister = function(shortcutName) {
|
||||
* @throws {Error} if the given key code is already mapped to a shortcut.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ShortcutRegistry.prototype.addKeyMapping = function(
|
||||
ShortcutRegistry.prototype.addKeyMapping = function(
|
||||
keyCode, shortcutName, opt_allowCollision) {
|
||||
keyCode = String(keyCode);
|
||||
var shortcutNames = this.keyMap_[keyCode];
|
||||
const shortcutNames = this.keyMap_[keyCode];
|
||||
if (shortcutNames && !opt_allowCollision) {
|
||||
throw new Error(
|
||||
'Shortcut with name "' + shortcutName + '" collides with shortcuts ' +
|
||||
@@ -139,7 +139,7 @@ Blockly.ShortcutRegistry.prototype.addKeyMapping = function(
|
||||
* Removes a mapping between a keycode and a keyboard shortcut.
|
||||
* @param {string} keyCode The key code for the keyboard shortcut. If
|
||||
* registering a key code with a modifier (ex: ctrl+c) use
|
||||
* Blockly.ShortcutRegistry.registry.createSerializedKey;
|
||||
* ShortcutRegistry.registry.createSerializedKey;
|
||||
* @param {string} shortcutName The name of the shortcut to execute when the
|
||||
* given keycode is pressed.
|
||||
* @param {boolean=} opt_quiet True to not console warn when there is no
|
||||
@@ -147,9 +147,9 @@ Blockly.ShortcutRegistry.prototype.addKeyMapping = function(
|
||||
* @return {boolean} True if a key mapping was removed, false otherwise.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ShortcutRegistry.prototype.removeKeyMapping = function(
|
||||
ShortcutRegistry.prototype.removeKeyMapping = function(
|
||||
keyCode, shortcutName, opt_quiet) {
|
||||
var shortcutNames = this.keyMap_[keyCode];
|
||||
const shortcutNames = this.keyMap_[keyCode];
|
||||
|
||||
if (!shortcutNames && !opt_quiet) {
|
||||
console.warn(
|
||||
@@ -158,7 +158,7 @@ Blockly.ShortcutRegistry.prototype.removeKeyMapping = function(
|
||||
return false;
|
||||
}
|
||||
|
||||
var shortcutIdx = shortcutNames.indexOf(shortcutName);
|
||||
const shortcutIdx = shortcutNames.indexOf(shortcutName);
|
||||
if (shortcutIdx > -1) {
|
||||
shortcutNames.splice(shortcutIdx, 1);
|
||||
if (shortcutNames.length == 0) {
|
||||
@@ -167,7 +167,8 @@ Blockly.ShortcutRegistry.prototype.removeKeyMapping = function(
|
||||
return true;
|
||||
}
|
||||
if (!opt_quiet) {
|
||||
console.warn('No keyboard shortcut with name "' + shortcutName +
|
||||
console.warn(
|
||||
'No keyboard shortcut with name "' + shortcutName +
|
||||
'" registered with key code "' + keyCode + '"');
|
||||
}
|
||||
return false;
|
||||
@@ -175,13 +176,14 @@ Blockly.ShortcutRegistry.prototype.removeKeyMapping = function(
|
||||
|
||||
/**
|
||||
* Removes all the key mappings for a shortcut with the given name.
|
||||
* Useful when changing the default key mappings and the key codes registered to the shortcut are
|
||||
* unknown.
|
||||
* @param {string} shortcutName The name of the shortcut to remove from the key map.
|
||||
* Useful when changing the default key mappings and the key codes registered to
|
||||
* the shortcut are unknown.
|
||||
* @param {string} shortcutName The name of the shortcut to remove from the key
|
||||
* map.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ShortcutRegistry.prototype.removeAllKeyMappings = function(shortcutName) {
|
||||
for (var keyCode in this.keyMap_) {
|
||||
ShortcutRegistry.prototype.removeAllKeyMappings = function(shortcutName) {
|
||||
for (const keyCode in this.keyMap_) {
|
||||
this.removeKeyMapping(keyCode, shortcutName, true);
|
||||
}
|
||||
};
|
||||
@@ -192,46 +194,46 @@ Blockly.ShortcutRegistry.prototype.removeAllKeyMappings = function(shortcutName)
|
||||
* shortcut names.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ShortcutRegistry.prototype.setKeyMap = function(keyMap) {
|
||||
ShortcutRegistry.prototype.setKeyMap = function(keyMap) {
|
||||
this.keyMap_ = keyMap;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the current key map.
|
||||
* @return {!Object<string,!Array<!Blockly.ShortcutRegistry.KeyboardShortcut>>}
|
||||
* The object holding key codes to Blockly.ShortcutRegistry.KeyboardShortcut.
|
||||
* @return {!Object<string,!Array<!ShortcutRegistry.KeyboardShortcut>>}
|
||||
* The object holding key codes to ShortcutRegistry.KeyboardShortcut.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ShortcutRegistry.prototype.getKeyMap = function() {
|
||||
return Blockly.utils.object.deepMerge(Object.create(null), this.keyMap_);
|
||||
ShortcutRegistry.prototype.getKeyMap = function() {
|
||||
return object.deepMerge(Object.create(null), this.keyMap_);
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the registry of keyboard shortcuts.
|
||||
* @return {!Object<string, !Blockly.ShortcutRegistry.KeyboardShortcut>}
|
||||
* @return {!Object<string, !ShortcutRegistry.KeyboardShortcut>}
|
||||
* The registry of keyboard shortcuts.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ShortcutRegistry.prototype.getRegistry = function() {
|
||||
return Blockly.utils.object.deepMerge(Object.create(null), this.registry_);
|
||||
ShortcutRegistry.prototype.getRegistry = function() {
|
||||
return object.deepMerge(Object.create(null), this.registry_);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles key down events.
|
||||
* @param {!Blockly.Workspace} workspace The main workspace where the event was
|
||||
* @param {!Workspace} workspace The main workspace where the event was
|
||||
* captured.
|
||||
* @param {!Event} e The key down event.
|
||||
* @return {boolean} True if the event was handled, false otherwise.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ShortcutRegistry.prototype.onKeyDown = function(workspace, e) {
|
||||
var key = this.serializeKeyEvent_(e);
|
||||
var shortcutNames = this.getShortcutNamesByKeyCode(key);
|
||||
ShortcutRegistry.prototype.onKeyDown = function(workspace, e) {
|
||||
const key = this.serializeKeyEvent_(e);
|
||||
const shortcutNames = this.getShortcutNamesByKeyCode(key);
|
||||
if (!shortcutNames) {
|
||||
return false;
|
||||
}
|
||||
for (var i = 0, shortcutName; (shortcutName = shortcutNames[i]); i++) {
|
||||
var shortcut = this.registry_[shortcutName];
|
||||
for (let i = 0, shortcutName; (shortcutName = shortcutNames[i]); i++) {
|
||||
const shortcut = this.registry_[shortcutName];
|
||||
if (!shortcut.preconditionFn || shortcut.preconditionFn(workspace)) {
|
||||
// If the key has been handled, stop processing shortcuts.
|
||||
if (shortcut.callback && shortcut.callback(workspace, e, shortcut)) {
|
||||
@@ -249,8 +251,7 @@ Blockly.ShortcutRegistry.prototype.onKeyDown = function(workspace, e) {
|
||||
* given keyCode is used. Undefined if no shortcuts exist.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ShortcutRegistry.prototype.getShortcutNamesByKeyCode = function(
|
||||
keyCode) {
|
||||
ShortcutRegistry.prototype.getShortcutNamesByKeyCode = function(keyCode) {
|
||||
return this.keyMap_[keyCode] || [];
|
||||
};
|
||||
|
||||
@@ -262,12 +263,11 @@ Blockly.ShortcutRegistry.prototype.getShortcutNamesByKeyCode = function(
|
||||
* registered under.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ShortcutRegistry.prototype.getKeyCodesByShortcutName = function(
|
||||
shortcutName) {
|
||||
var keys = [];
|
||||
for (var keyCode in this.keyMap_) {
|
||||
var shortcuts = this.keyMap_[keyCode];
|
||||
var shortcutIdx = shortcuts.indexOf(shortcutName);
|
||||
ShortcutRegistry.prototype.getKeyCodesByShortcutName = function(shortcutName) {
|
||||
const keys = [];
|
||||
for (const keyCode in this.keyMap_) {
|
||||
const shortcuts = this.keyMap_[keyCode];
|
||||
const shortcutIdx = shortcuts.indexOf(shortcutName);
|
||||
if (shortcutIdx > -1) {
|
||||
keys.push(keyCode);
|
||||
}
|
||||
@@ -281,9 +281,9 @@ Blockly.ShortcutRegistry.prototype.getKeyCodesByShortcutName = function(
|
||||
* @return {string} The serialized key code for the given event.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ShortcutRegistry.prototype.serializeKeyEvent_ = function(e) {
|
||||
var serializedKey = '';
|
||||
for (var modifier in Blockly.ShortcutRegistry.modifierKeys) {
|
||||
ShortcutRegistry.prototype.serializeKeyEvent_ = function(e) {
|
||||
let serializedKey = '';
|
||||
for (const modifier in ShortcutRegistry.modifierKeys) {
|
||||
if (e.getModifierState(modifier)) {
|
||||
if (serializedKey != '') {
|
||||
serializedKey += '+';
|
||||
@@ -305,11 +305,9 @@ Blockly.ShortcutRegistry.prototype.serializeKeyEvent_ = function(e) {
|
||||
* @throws {Error} if the modifier is not in the valid modifiers list.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ShortcutRegistry.prototype.checkModifiers_ = function(
|
||||
modifiers) {
|
||||
var validModifiers = Blockly.utils.object.values(
|
||||
Blockly.ShortcutRegistry.modifierKeys);
|
||||
for (var i = 0, modifier; (modifier = modifiers[i]); i++) {
|
||||
ShortcutRegistry.prototype.checkModifiers_ = function(modifiers) {
|
||||
const validModifiers = object.values(ShortcutRegistry.modifierKeys);
|
||||
for (let i = 0, modifier; (modifier = modifiers[i]); i++) {
|
||||
if (validModifiers.indexOf(modifier) < 0) {
|
||||
throw new Error(modifier + ' is not a valid modifier key.');
|
||||
}
|
||||
@@ -321,19 +319,17 @@ Blockly.ShortcutRegistry.prototype.checkModifiers_ = function(
|
||||
* @param {number} keyCode Number code representing the key.
|
||||
* @param {?Array<string>} modifiers List of modifier key codes to be used with
|
||||
* the key. All valid modifiers can be found in the
|
||||
* Blockly.ShortcutRegistry.modifierKeys.
|
||||
* ShortcutRegistry.modifierKeys.
|
||||
* @return {string} The serialized key code for the given modifiers and key.
|
||||
* @public
|
||||
*/
|
||||
Blockly.ShortcutRegistry.prototype.createSerializedKey = function(
|
||||
keyCode, modifiers) {
|
||||
var serializedKey = '';
|
||||
ShortcutRegistry.prototype.createSerializedKey = function(keyCode, modifiers) {
|
||||
let serializedKey = '';
|
||||
|
||||
if (modifiers) {
|
||||
this.checkModifiers_(modifiers);
|
||||
for (var modifier in Blockly.ShortcutRegistry.modifierKeys) {
|
||||
var modifierKeyCode =
|
||||
Blockly.ShortcutRegistry.modifierKeys[modifier];
|
||||
for (const modifier in ShortcutRegistry.modifierKeys) {
|
||||
const modifierKeyCode = ShortcutRegistry.modifierKeys[modifier];
|
||||
if (modifiers.indexOf(modifierKeyCode) > -1) {
|
||||
if (serializedKey != '') {
|
||||
serializedKey += '+';
|
||||
@@ -352,4 +348,6 @@ Blockly.ShortcutRegistry.prototype.createSerializedKey = function(
|
||||
};
|
||||
|
||||
// Creates and assigns the singleton instance.
|
||||
new Blockly.ShortcutRegistry();
|
||||
new ShortcutRegistry();
|
||||
|
||||
exports = ShortcutRegistry;
|
||||
|
||||
@@ -12,47 +12,50 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.ThemeManager');
|
||||
goog.module('Blockly.ThemeManager');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Theme');
|
||||
|
||||
goog.requireType('Blockly.Workspace');
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Theme = goog.requireType('Blockly.Theme');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Workspace = goog.requireType('Blockly.Workspace');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
|
||||
|
||||
/**
|
||||
* Class for storing and updating a workspace's theme and UI components.
|
||||
* @param {!Blockly.WorkspaceSvg} workspace The main workspace.
|
||||
* @param {!Blockly.Theme} theme The workspace theme.
|
||||
* @param {!WorkspaceSvg} workspace The main workspace.
|
||||
* @param {!Theme} theme The workspace theme.
|
||||
* @constructor
|
||||
* @package
|
||||
*/
|
||||
Blockly.ThemeManager = function(workspace, theme) {
|
||||
|
||||
const ThemeManager = function(workspace, theme) {
|
||||
/**
|
||||
* The main workspace.
|
||||
* @type {!Blockly.WorkspaceSvg}
|
||||
* @type {!WorkspaceSvg}
|
||||
* @private
|
||||
*/
|
||||
this.workspace_ = workspace;
|
||||
|
||||
/**
|
||||
* The Blockly theme to use.
|
||||
* @type {!Blockly.Theme}
|
||||
* @type {!Theme}
|
||||
* @private
|
||||
*/
|
||||
this.theme_ = theme;
|
||||
|
||||
/**
|
||||
* A list of workspaces that are subscribed to this theme.
|
||||
* @type {!Array<Blockly.Workspace>}
|
||||
* @type {!Array<Workspace>}
|
||||
* @private
|
||||
*/
|
||||
this.subscribedWorkspaces_ = [];
|
||||
|
||||
/**
|
||||
* A map of subscribed UI components, keyed by component name.
|
||||
* @type {!Object<string, !Array<!Blockly.ThemeManager.Component>>}
|
||||
* @type {!Object<string, !Array<!ThemeManager.Component>>}
|
||||
* @private
|
||||
*/
|
||||
this.componentDB_ = Object.create(null);
|
||||
@@ -61,51 +64,51 @@ Blockly.ThemeManager = function(workspace, theme) {
|
||||
/**
|
||||
* A Blockly UI component type.
|
||||
* @typedef {{
|
||||
* element:!Element,
|
||||
* propertyName:string
|
||||
* }}
|
||||
*/
|
||||
Blockly.ThemeManager.Component;
|
||||
* element:!Element,
|
||||
* propertyName:string
|
||||
* }}
|
||||
*/
|
||||
ThemeManager.Component;
|
||||
|
||||
/**
|
||||
* Get the workspace theme.
|
||||
* @return {!Blockly.Theme} The workspace theme.
|
||||
* @return {!Theme} The workspace theme.
|
||||
* @package
|
||||
*/
|
||||
Blockly.ThemeManager.prototype.getTheme = function() {
|
||||
ThemeManager.prototype.getTheme = function() {
|
||||
return this.theme_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the workspace theme, and refresh the workspace and all components.
|
||||
* @param {!Blockly.Theme} theme The workspace theme.
|
||||
* @param {!Theme} theme The workspace theme.
|
||||
* @package
|
||||
*/
|
||||
Blockly.ThemeManager.prototype.setTheme = function(theme) {
|
||||
var prevTheme = this.theme_;
|
||||
ThemeManager.prototype.setTheme = function(theme) {
|
||||
const prevTheme = this.theme_;
|
||||
this.theme_ = theme;
|
||||
|
||||
// Set the theme name onto the injection div.
|
||||
var injectionDiv = this.workspace_.getInjectionDiv();
|
||||
const injectionDiv = this.workspace_.getInjectionDiv();
|
||||
if (injectionDiv) {
|
||||
if (prevTheme) {
|
||||
Blockly.utils.dom.removeClass(injectionDiv, prevTheme.getClassName());
|
||||
dom.removeClass(injectionDiv, prevTheme.getClassName());
|
||||
}
|
||||
Blockly.utils.dom.addClass(injectionDiv, this.theme_.getClassName());
|
||||
dom.addClass(injectionDiv, this.theme_.getClassName());
|
||||
}
|
||||
|
||||
// Refresh all subscribed workspaces.
|
||||
for (var i = 0, workspace; (workspace = this.subscribedWorkspaces_[i]); i++) {
|
||||
for (let i = 0, workspace; (workspace = this.subscribedWorkspaces_[i]); i++) {
|
||||
workspace.refreshTheme();
|
||||
}
|
||||
|
||||
// Refresh all registered Blockly UI components.
|
||||
for (var i = 0, keys = Object.keys(this.componentDB_),
|
||||
key; (key = keys[i]); i++) {
|
||||
for (var j = 0, component; (component = this.componentDB_[key][j]); j++) {
|
||||
var element = component.element;
|
||||
var propertyName = component.propertyName;
|
||||
var style = this.theme_ && this.theme_.getComponentStyle(key);
|
||||
for (let i = 0, keys = Object.keys(this.componentDB_), key; (key = keys[i]);
|
||||
i++) {
|
||||
for (let j = 0, component; (component = this.componentDB_[key][j]); j++) {
|
||||
const element = component.element;
|
||||
const propertyName = component.propertyName;
|
||||
const style = this.theme_ && this.theme_.getComponentStyle(key);
|
||||
element.style[propertyName] = style || '';
|
||||
}
|
||||
}
|
||||
@@ -116,20 +119,20 @@ Blockly.ThemeManager.prototype.setTheme = function(theme) {
|
||||
/**
|
||||
* Subscribe a workspace to changes to the selected theme. If a new theme is
|
||||
* set, the workspace is called to refresh its blocks.
|
||||
* @param {!Blockly.Workspace} workspace The workspace to subscribe.
|
||||
* @param {!Workspace} workspace The workspace to subscribe.
|
||||
* @package
|
||||
*/
|
||||
Blockly.ThemeManager.prototype.subscribeWorkspace = function(workspace) {
|
||||
ThemeManager.prototype.subscribeWorkspace = function(workspace) {
|
||||
this.subscribedWorkspaces_.push(workspace);
|
||||
};
|
||||
|
||||
/**
|
||||
* Unsubscribe a workspace to changes to the selected theme.
|
||||
* @param {!Blockly.Workspace} workspace The workspace to unsubscribe.
|
||||
* @param {!Workspace} workspace The workspace to unsubscribe.
|
||||
* @package
|
||||
*/
|
||||
Blockly.ThemeManager.prototype.unsubscribeWorkspace = function(workspace) {
|
||||
var index = this.subscribedWorkspaces_.indexOf(workspace);
|
||||
ThemeManager.prototype.unsubscribeWorkspace = function(workspace) {
|
||||
const index = this.subscribedWorkspaces_.indexOf(workspace);
|
||||
if (index < 0) {
|
||||
throw Error('Cannot unsubscribe a workspace that hasn\'t been subscribed.');
|
||||
}
|
||||
@@ -145,20 +148,18 @@ Blockly.ThemeManager.prototype.unsubscribeWorkspace = function(workspace) {
|
||||
* @param {string} propertyName The inline style property name to update.
|
||||
* @package
|
||||
*/
|
||||
Blockly.ThemeManager.prototype.subscribe = function(element, componentName,
|
||||
propertyName) {
|
||||
ThemeManager.prototype.subscribe = function(
|
||||
element, componentName, propertyName) {
|
||||
if (!this.componentDB_[componentName]) {
|
||||
this.componentDB_[componentName] = [];
|
||||
}
|
||||
|
||||
// Add the element to our component map.
|
||||
this.componentDB_[componentName].push({
|
||||
element: element,
|
||||
propertyName: propertyName
|
||||
});
|
||||
this.componentDB_[componentName].push(
|
||||
{element: element, propertyName: propertyName});
|
||||
|
||||
// Initialize the element with its corresponding theme style.
|
||||
var style = this.theme_ && this.theme_.getComponentStyle(componentName);
|
||||
const style = this.theme_ && this.theme_.getComponentStyle(componentName);
|
||||
element.style[propertyName] = style || '';
|
||||
};
|
||||
|
||||
@@ -167,15 +168,15 @@ Blockly.ThemeManager.prototype.subscribe = function(element, componentName,
|
||||
* @param {Element} element The element to unsubscribe.
|
||||
* @package
|
||||
*/
|
||||
Blockly.ThemeManager.prototype.unsubscribe = function(element) {
|
||||
ThemeManager.prototype.unsubscribe = function(element) {
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
// Go through all component, and remove any references to this element.
|
||||
var componentNames = Object.keys(this.componentDB_);
|
||||
for (var c = 0, componentName; (componentName = componentNames[c]); c++) {
|
||||
var elements = this.componentDB_[componentName];
|
||||
for (var i = elements.length - 1; i >= 0; i--) {
|
||||
const componentNames = Object.keys(this.componentDB_);
|
||||
for (let c = 0, componentName; (componentName = componentNames[c]); c++) {
|
||||
const elements = this.componentDB_[componentName];
|
||||
for (let i = elements.length - 1; i >= 0; i--) {
|
||||
if (elements[i].element === element) {
|
||||
elements.splice(i, 1);
|
||||
}
|
||||
@@ -192,9 +193,11 @@ Blockly.ThemeManager.prototype.unsubscribe = function(element) {
|
||||
* @package
|
||||
* @suppress {checkTypes}
|
||||
*/
|
||||
Blockly.ThemeManager.prototype.dispose = function() {
|
||||
ThemeManager.prototype.dispose = function() {
|
||||
this.owner_ = null;
|
||||
this.theme_ = null;
|
||||
this.subscribedWorkspaces_ = null;
|
||||
this.componentDB_ = null;
|
||||
};
|
||||
|
||||
exports = ThemeManager;
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
*/
|
||||
goog.provide('Blockly.Touch');
|
||||
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.internalConstants');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.global');
|
||||
goog.require('Blockly.utils.string');
|
||||
@@ -107,8 +106,7 @@ Blockly.longStart = function(e, gesture) {
|
||||
if (gesture) {
|
||||
gesture.handleRightClick(e);
|
||||
}
|
||||
|
||||
}, Blockly.LONGPRESS);
|
||||
}, Blockly.internalConstants.LONGPRESS);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,13 +14,12 @@ goog.provide('Blockly.Trashcan');
|
||||
|
||||
goog.require('Blockly.browserEvents');
|
||||
goog.require('Blockly.ComponentManager');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.DeleteArea');
|
||||
goog.require('Blockly.Events');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.TrashcanOpen');
|
||||
goog.require('Blockly.IAutoHideable');
|
||||
goog.require('Blockly.internalConstants');
|
||||
goog.require('Blockly.IPositionable');
|
||||
goog.require('Blockly.Options');
|
||||
goog.require('Blockly.registry');
|
||||
@@ -316,17 +315,18 @@ Blockly.Trashcan.prototype.createDom = function() {
|
||||
},
|
||||
clip);
|
||||
var body = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.IMAGE,
|
||||
{
|
||||
'width': Blockly.SPRITE.width,
|
||||
Blockly.utils.Svg.IMAGE, {
|
||||
'width': Blockly.internalConstants.SPRITE.width,
|
||||
'x': -this.SPRITE_LEFT_,
|
||||
'height': Blockly.SPRITE.height,
|
||||
'height': Blockly.internalConstants.SPRITE.height,
|
||||
'y': -this.SPRITE_TOP_,
|
||||
'clip-path': 'url(#blocklyTrashBodyClipPath' + rnd + ')'
|
||||
},
|
||||
this.svgGroup_);
|
||||
body.setAttributeNS(Blockly.utils.dom.XLINK_NS, 'xlink:href',
|
||||
this.workspace_.options.pathToMedia + Blockly.SPRITE.url);
|
||||
body.setAttributeNS(
|
||||
Blockly.utils.dom.XLINK_NS, 'xlink:href',
|
||||
this.workspace_.options.pathToMedia +
|
||||
Blockly.internalConstants.SPRITE.url);
|
||||
|
||||
clip = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.CLIPPATH,
|
||||
@@ -336,17 +336,18 @@ Blockly.Trashcan.prototype.createDom = function() {
|
||||
Blockly.utils.Svg.RECT,
|
||||
{'width': this.WIDTH_, 'height': this.LID_HEIGHT_}, clip);
|
||||
this.svgLid_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.IMAGE,
|
||||
{
|
||||
'width': Blockly.SPRITE.width,
|
||||
Blockly.utils.Svg.IMAGE, {
|
||||
'width': Blockly.internalConstants.SPRITE.width,
|
||||
'x': -this.SPRITE_LEFT_,
|
||||
'height': Blockly.SPRITE.height,
|
||||
'height': Blockly.internalConstants.SPRITE.height,
|
||||
'y': -this.SPRITE_TOP_,
|
||||
'clip-path': 'url(#blocklyTrashLidClipPath' + rnd + ')'
|
||||
},
|
||||
this.svgGroup_);
|
||||
this.svgLid_.setAttributeNS(Blockly.utils.dom.XLINK_NS, 'xlink:href',
|
||||
this.workspace_.options.pathToMedia + Blockly.SPRITE.url);
|
||||
this.svgLid_.setAttributeNS(
|
||||
Blockly.utils.dom.XLINK_NS, 'xlink:href',
|
||||
this.workspace_.options.pathToMedia +
|
||||
Blockly.internalConstants.SPRITE.url);
|
||||
|
||||
// bindEventWithChecks_ quashes events too aggressively. See:
|
||||
// https://groups.google.com/forum/#!topic/blockly/QF4yB9Wx00s
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
*/
|
||||
goog.provide('Blockly.utils');
|
||||
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.internalConstants');
|
||||
goog.require('Blockly.Msg');
|
||||
goog.require('Blockly.utils.colour');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
@@ -194,13 +193,13 @@ Blockly.utils.getScrollDeltaPixels = function(e) {
|
||||
};
|
||||
case 0x01: // Line mode.
|
||||
return {
|
||||
x: e.deltaX * Blockly.LINE_MODE_MULTIPLIER,
|
||||
y: e.deltaY * Blockly.LINE_MODE_MULTIPLIER
|
||||
x: e.deltaX * Blockly.internalConstants.LINE_MODE_MULTIPLIER,
|
||||
y: e.deltaY * Blockly.internalConstants.LINE_MODE_MULTIPLIER
|
||||
};
|
||||
case 0x02: // Page mode.
|
||||
return {
|
||||
x: e.deltaX * Blockly.PAGE_MODE_MULTIPLIER,
|
||||
y: e.deltaY * Blockly.PAGE_MODE_MULTIPLIER
|
||||
x: e.deltaX * Blockly.internalConstants.PAGE_MODE_MULTIPLIER,
|
||||
y: e.deltaY * Blockly.internalConstants.PAGE_MODE_MULTIPLIER
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -634,8 +633,9 @@ Blockly.utils.parseBlockColour = function(colour) {
|
||||
if (!isNaN(hue) && 0 <= hue && hue <= 360) {
|
||||
return {
|
||||
hue: hue,
|
||||
hex: Blockly.utils.colour.hsvToHex(hue, Blockly.HSV_SATURATION,
|
||||
Blockly.HSV_VALUE * 255)
|
||||
hex: Blockly.utils.colour.hsvToHex(
|
||||
hue, Blockly.internalConstants.HSV_SATURATION,
|
||||
Blockly.internalConstants.HSV_VALUE * 255)
|
||||
};
|
||||
} else {
|
||||
var hex = Blockly.utils.colour.parse(dereferenced);
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
* @name Blockly.utils.colour
|
||||
* @namespace
|
||||
*/
|
||||
goog.provide('Blockly.utils.colour');
|
||||
goog.module('Blockly.utils.colour');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
|
||||
/**
|
||||
@@ -30,9 +31,9 @@ goog.provide('Blockly.utils.colour');
|
||||
* @return {?string} A string containing a hex representation of the colour,
|
||||
* or null if can't be parsed.
|
||||
*/
|
||||
Blockly.utils.colour.parse = function(str) {
|
||||
const parse = function(str) {
|
||||
str = String(str).toLowerCase().trim();
|
||||
var hex = Blockly.utils.colour.names[str];
|
||||
let hex = names[str];
|
||||
if (hex) {
|
||||
// e.g. 'red'
|
||||
return hex;
|
||||
@@ -47,18 +48,19 @@ Blockly.utils.colour.parse = function(str) {
|
||||
// e.g. '#0f8'
|
||||
return ['#', hex[1], hex[1], hex[2], hex[2], hex[3], hex[3]].join('');
|
||||
}
|
||||
var rgb = str.match(/^(?:rgb)?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/);
|
||||
const rgb = str.match(/^(?:rgb)?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/);
|
||||
if (rgb) {
|
||||
// e.g. 'rgb(0, 128, 255)'
|
||||
var r = Number(rgb[1]);
|
||||
var g = Number(rgb[2]);
|
||||
var b = Number(rgb[3]);
|
||||
const r = Number(rgb[1]);
|
||||
const g = Number(rgb[2]);
|
||||
const b = Number(rgb[3]);
|
||||
if (r >= 0 && r < 256 && g >= 0 && g < 256 && b >= 0 && b < 256) {
|
||||
return Blockly.utils.colour.rgbToHex(r, g, b);
|
||||
return rgbToHex(r, g, b);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
exports.parse = parse;
|
||||
|
||||
/**
|
||||
* Converts a colour from RGB to hex representation.
|
||||
@@ -67,13 +69,14 @@ Blockly.utils.colour.parse = function(str) {
|
||||
* @param {number} b Amount of blue, int between 0 and 255.
|
||||
* @return {string} Hex representation of the colour.
|
||||
*/
|
||||
Blockly.utils.colour.rgbToHex = function(r, g, b) {
|
||||
var rgb = (r << 16) | (g << 8) | b;
|
||||
const rgbToHex = function(r, g, b) {
|
||||
const rgb = (r << 16) | (g << 8) | b;
|
||||
if (r < 0x10) {
|
||||
return '#' + (0x1000000 | rgb).toString(16).substr(1);
|
||||
}
|
||||
return '#' + rgb.toString(16);
|
||||
};
|
||||
exports.rgbToHex = rgbToHex;
|
||||
|
||||
/**
|
||||
* Converts a colour to RGB.
|
||||
@@ -81,19 +84,20 @@ Blockly.utils.colour.rgbToHex = function(r, g, b) {
|
||||
* colour format ('#ff0000', 'red', '0xff000', etc).
|
||||
* @return {!Array<number>} RGB representation of the colour.
|
||||
*/
|
||||
Blockly.utils.colour.hexToRgb = function(colour) {
|
||||
var hex = Blockly.utils.colour.parse(colour);
|
||||
const hexToRgb = function(colour) {
|
||||
const hex = parse(colour);
|
||||
if (!hex) {
|
||||
return [0, 0, 0];
|
||||
}
|
||||
|
||||
var rgb = parseInt(hex.substr(1), 16);
|
||||
var r = rgb >> 16;
|
||||
var g = (rgb >> 8) & 255;
|
||||
var b = rgb & 255;
|
||||
const rgb = parseInt(hex.substr(1), 16);
|
||||
const r = rgb >> 16;
|
||||
const g = (rgb >> 8) & 255;
|
||||
const b = rgb & 255;
|
||||
|
||||
return [r, g, b];
|
||||
};
|
||||
exports.hexToRgb = hexToRgb;
|
||||
|
||||
/**
|
||||
* Converts an HSV triplet to hex representation.
|
||||
@@ -102,20 +106,20 @@ Blockly.utils.colour.hexToRgb = function(colour) {
|
||||
* @param {number} v Brightness in [0, 255].
|
||||
* @return {string} Hex representation of the colour.
|
||||
*/
|
||||
Blockly.utils.colour.hsvToHex = function(h, s, v) {
|
||||
var red = 0;
|
||||
var green = 0;
|
||||
var blue = 0;
|
||||
const hsvToHex = function(h, s, v) {
|
||||
let red = 0;
|
||||
let green = 0;
|
||||
let blue = 0;
|
||||
if (s == 0) {
|
||||
red = v;
|
||||
green = v;
|
||||
blue = v;
|
||||
} else {
|
||||
var sextant = Math.floor(h / 60);
|
||||
var remainder = (h / 60) - sextant;
|
||||
var val1 = v * (1 - s);
|
||||
var val2 = v * (1 - (s * remainder));
|
||||
var val3 = v * (1 - (s * (1 - remainder)));
|
||||
const sextant = Math.floor(h / 60);
|
||||
const remainder = (h / 60) - sextant;
|
||||
const val1 = v * (1 - s);
|
||||
const val2 = v * (1 - (s * remainder));
|
||||
const val3 = v * (1 - (s * (1 - remainder)));
|
||||
switch (sextant) {
|
||||
case 1:
|
||||
red = val2;
|
||||
@@ -150,9 +154,9 @@ Blockly.utils.colour.hsvToHex = function(h, s, v) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Blockly.utils.colour.rgbToHex(
|
||||
Math.floor(red), Math.floor(green), Math.floor(blue));
|
||||
return rgbToHex(Math.floor(red), Math.floor(green), Math.floor(blue));
|
||||
};
|
||||
exports.hsvToHex = hsvToHex;
|
||||
|
||||
/**
|
||||
* Blend two colours together, using the specified factor to indicate the
|
||||
@@ -163,22 +167,23 @@ Blockly.utils.colour.hsvToHex = function(h, s, v) {
|
||||
* Values should be in the range [0, 1].
|
||||
* @return {?string} Combined colour represented in hex.
|
||||
*/
|
||||
Blockly.utils.colour.blend = function(colour1, colour2, factor) {
|
||||
var hex1 = Blockly.utils.colour.parse(colour1);
|
||||
const blend = function(colour1, colour2, factor) {
|
||||
const hex1 = parse(colour1);
|
||||
if (!hex1) {
|
||||
return null;
|
||||
}
|
||||
var hex2 = Blockly.utils.colour.parse(colour2);
|
||||
const hex2 = parse(colour2);
|
||||
if (!hex2) {
|
||||
return null;
|
||||
}
|
||||
var rgb1 = Blockly.utils.colour.hexToRgb(hex1);
|
||||
var rgb2 = Blockly.utils.colour.hexToRgb(hex2);
|
||||
var r = Math.round(rgb2[0] + factor * (rgb1[0] - rgb2[0]));
|
||||
var g = Math.round(rgb2[1] + factor * (rgb1[1] - rgb2[1]));
|
||||
var b = Math.round(rgb2[2] + factor * (rgb1[2] - rgb2[2]));
|
||||
return Blockly.utils.colour.rgbToHex(r, g, b);
|
||||
const rgb1 = hexToRgb(hex1);
|
||||
const rgb2 = hexToRgb(hex2);
|
||||
const r = Math.round(rgb2[0] + factor * (rgb1[0] - rgb2[0]));
|
||||
const g = Math.round(rgb2[1] + factor * (rgb1[1] - rgb2[1]));
|
||||
const b = Math.round(rgb2[2] + factor * (rgb1[2] - rgb2[2]));
|
||||
return rgbToHex(r, g, b);
|
||||
};
|
||||
exports.blend = blend;
|
||||
|
||||
/**
|
||||
* A map that contains the 16 basic colour keywords as defined by W3C:
|
||||
@@ -188,7 +193,7 @@ Blockly.utils.colour.blend = function(colour1, colour2, factor) {
|
||||
*
|
||||
* @type {!Object<string, string>}
|
||||
*/
|
||||
Blockly.utils.colour.names = {
|
||||
const names = {
|
||||
'aqua': '#00ffff',
|
||||
'black': '#000000',
|
||||
'blue': '#0000ff',
|
||||
@@ -206,3 +211,4 @@ Blockly.utils.colour.names = {
|
||||
'white': '#ffffff',
|
||||
'yellow': '#ffff00'
|
||||
};
|
||||
exports.names = names;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user