mirror of
https://github.com/google/blockly.git
synced 2026-01-10 02:17:09 +01:00
Merge branch 'goog_module' of github.com:google/blockly into module_aria
This commit is contained in:
27
.github/workflows/tag_module_cleanup.yml
vendored
27
.github/workflows/tag_module_cleanup.yml
vendored
@@ -19,17 +19,20 @@ jobs:
|
||||
- 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,
|
||||
// Note that pull requests are considered issues and "shared"
|
||||
// actions for both features, like manipulating labels and
|
||||
// milestones are provided within the issues API.
|
||||
await github.issues.update({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
// 2021 q3 release milestone.
|
||||
// https://github.com/google/blockly/milestone/18
|
||||
milestone: 18
|
||||
})
|
||||
await github.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
// Sets the labels
|
||||
labels: ['type: cleanup']
|
||||
}
|
||||
await github.issues.update(issuesUpdateParams)
|
||||
})
|
||||
|
||||
865
core/block.js
865
core/block.js
File diff suppressed because it is too large
Load Diff
@@ -8,8 +8,9 @@
|
||||
* @fileoverview A class that manages a surface for dragging blocks. When a
|
||||
* block drag is started, we move the block (and children) to a separate DOM
|
||||
* element that we move around using translate3d. At the end of the drag, the
|
||||
* blocks are put back in into the SVG they came from. This helps performance by
|
||||
* avoiding repainting the entire SVG on every mouse move while dragging blocks.
|
||||
* blocks are put back in into the SVG they came from. This helps
|
||||
* performance by avoiding repainting the entire SVG on every mouse move
|
||||
* while dragging blocks.
|
||||
* @author picklesrus
|
||||
*/
|
||||
|
||||
@@ -19,9 +20,9 @@ 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');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
@@ -94,16 +95,16 @@ BlockDragSurfaceSvg.prototype.createDom = function() {
|
||||
if (this.SVG_) {
|
||||
return; // Already created.
|
||||
}
|
||||
this.SVG_ = createSvgElement(
|
||||
SVG, {
|
||||
'xmlns': SVG_NS,
|
||||
'xmlns:html': HTML_NS,
|
||||
'xmlns:xlink': XLINK_NS,
|
||||
this.SVG_ = dom.createSvgElement(
|
||||
Svg.SVG, {
|
||||
'xmlns': dom.SVG_NS,
|
||||
'xmlns:html': dom.HTML_NS,
|
||||
'xmlns:xlink': dom.XLINK_NS,
|
||||
'version': '1.1',
|
||||
'class': 'blocklyBlockDragSurface'
|
||||
},
|
||||
this.container_);
|
||||
this.dragGroup_ = createSvgElement(G, {}, this.SVG_);
|
||||
this.dragGroup_ = dom.createSvgElement(Svg.G, {}, this.SVG_);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -157,7 +158,7 @@ BlockDragSurfaceSvg.prototype.translateSurfaceInternal_ = function() {
|
||||
y = y.toFixed(0);
|
||||
this.SVG_.style.display = 'block';
|
||||
|
||||
setCssTransform(this.SVG_, 'translate3d(' + x + 'px, ' + y + 'px, 0)');
|
||||
dom.setCssTransform(this.SVG_, 'translate3d(' + x + 'px, ' + y + 'px, 0)');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -191,7 +192,7 @@ BlockDragSurfaceSvg.prototype.translateSurface = function(x, y) {
|
||||
* @return {!Coordinate} Current translation of the surface.
|
||||
*/
|
||||
BlockDragSurfaceSvg.prototype.getSurfaceTranslation = function() {
|
||||
const xy = getRelativeXY(/** @type {!SVGElement} */ (this.SVG_));
|
||||
const xy = utils.getRelativeXY(/** @type {!SVGElement} */ (this.SVG_));
|
||||
return new Coordinate(xy.x / this.scale_, xy.y / this.scale_);
|
||||
};
|
||||
|
||||
|
||||
@@ -17,13 +17,14 @@ goog.module.declareLegacyNamespace();
|
||||
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');
|
||||
const IBlockDragger = goog.requireType('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 common = goog.require('Blockly.common');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const events = goog.require('Blockly.Events');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
@@ -332,7 +333,7 @@ BlockDragger.prototype.maybeDeleteBlock_ = function() {
|
||||
// Fire a move event, so we know where to go back to for an undo.
|
||||
this.fireMoveEvent_();
|
||||
this.draggingBlock_.dispose(false, true);
|
||||
Blockly.draggingConnections = [];
|
||||
common.draggingConnections.length = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
203
core/blockly.js
203
core/blockly.js
@@ -17,6 +17,8 @@
|
||||
goog.provide('Blockly');
|
||||
|
||||
goog.require('Blockly.browserEvents');
|
||||
goog.require('Blockly.clipboard');
|
||||
goog.require('Blockly.common');
|
||||
goog.require('Blockly.ComponentManager');
|
||||
goog.require('Blockly.connectionTypes');
|
||||
goog.require('Blockly.constants');
|
||||
@@ -55,7 +57,6 @@ goog.require('Blockly.WorkspaceSvg');
|
||||
goog.require('Blockly.Xml');
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.Connection');
|
||||
goog.requireType('Blockly.ICopyable');
|
||||
goog.requireType('Blockly.Workspace');
|
||||
|
||||
@@ -71,12 +72,20 @@ goog.requireType('Blockly.Workspace');
|
||||
*/
|
||||
Blockly.VERSION = 'uncompiled';
|
||||
|
||||
/**
|
||||
* The main workspace most recently used.
|
||||
* Set by Blockly.WorkspaceSvg.prototype.markFocused
|
||||
* @type {Blockly.Workspace}
|
||||
*/
|
||||
Blockly.mainWorkspace = null;
|
||||
// Add a getter and setter pair for Blockly.mainWorkspace, for legacy reasons.
|
||||
Object.defineProperty(Blockly, 'mainWorkspace', {
|
||||
set: function(x) {
|
||||
Blockly.utils.deprecation.warn(
|
||||
'Blockly.mainWorkspace', 'September 2021', 'September 2022');
|
||||
Blockly.common.setMainWorkspace(x);
|
||||
},
|
||||
get: function() {
|
||||
Blockly.utils.deprecation.warn(
|
||||
'Blockly.mainWorkspace', 'September 2021', 'September 2022',
|
||||
'Blockly.getMainWorkspace()');
|
||||
return Blockly.common.getMainWorkspace();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Currently selected block.
|
||||
@@ -84,48 +93,6 @@ Blockly.mainWorkspace = null;
|
||||
*/
|
||||
Blockly.selected = null;
|
||||
|
||||
/**
|
||||
* All of the connections on blocks that are currently being dragged.
|
||||
* @type {!Array<!Blockly.Connection>}
|
||||
* @package
|
||||
*/
|
||||
Blockly.draggingConnections = [];
|
||||
|
||||
/**
|
||||
* Contents of the local clipboard.
|
||||
* @type {Element}
|
||||
* @private
|
||||
*/
|
||||
Blockly.clipboardXml_ = null;
|
||||
|
||||
/**
|
||||
* Source of the local clipboard.
|
||||
* @type {Blockly.WorkspaceSvg}
|
||||
* @private
|
||||
*/
|
||||
Blockly.clipboardSource_ = null;
|
||||
|
||||
/**
|
||||
* Map of types to type counts for the clipboard object and descendants.
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
Blockly.clipboardTypeCounts_ = null;
|
||||
|
||||
/**
|
||||
* Cached value for whether 3D is supported.
|
||||
* @type {?boolean}
|
||||
* @private
|
||||
*/
|
||||
Blockly.cache3dSupported_ = null;
|
||||
|
||||
/**
|
||||
* Container element to render the WidgetDiv, DropDownDiv and Tooltip.
|
||||
* @type {?Element}
|
||||
* @package
|
||||
*/
|
||||
Blockly.parentContainer = null;
|
||||
|
||||
/**
|
||||
* Returns the dimensions of the specified SVG image.
|
||||
* @param {!SVGElement} svg SVG image.
|
||||
@@ -136,9 +103,7 @@ Blockly.svgSize = function(svg) {
|
||||
// When removing this function, remove svg.cachedWidth_ and svg.cachedHeight_
|
||||
// from setCachedParentSvgSize.
|
||||
Blockly.utils.deprecation.warn(
|
||||
'Blockly.svgSize',
|
||||
'March 2021',
|
||||
'March 2022',
|
||||
'Blockly.svgSize', 'March 2021', 'March 2022',
|
||||
'workspace.getCachedParentSvgSize');
|
||||
svg = /** @type {?} */ (svg);
|
||||
return new Blockly.utils.Size(svg.cachedWidth_, svg.cachedHeight_);
|
||||
@@ -195,7 +160,7 @@ Blockly.svgResize = function(workspace) {
|
||||
// TODO (https://github.com/google/blockly/issues/1998) handle cases where there
|
||||
// are multiple workspaces and non-main workspaces are able to accept input.
|
||||
Blockly.onKeyDown = function(e) {
|
||||
var mainWorkspace = Blockly.mainWorkspace;
|
||||
var mainWorkspace = Blockly.common.getMainWorkspace();
|
||||
if (!mainWorkspace) {
|
||||
return;
|
||||
}
|
||||
@@ -220,7 +185,8 @@ Blockly.deleteBlock = function(selected) {
|
||||
Blockly.Events.setGroup(true);
|
||||
Blockly.hideChaff();
|
||||
if (selected.outputConnection) {
|
||||
// Do not attempt to heal rows (https://github.com/google/blockly/issues/4832)
|
||||
// Do not attempt to heal rows
|
||||
// (https://github.com/google/blockly/issues/4832)
|
||||
selected.dispose(false, true);
|
||||
} else {
|
||||
selected.dispose(/* heal */ true, true);
|
||||
@@ -234,39 +200,14 @@ Blockly.deleteBlock = function(selected) {
|
||||
* @param {!Blockly.ICopyable} toCopy Block or Workspace Comment to be copied.
|
||||
* @package
|
||||
*/
|
||||
Blockly.copy = function(toCopy) {
|
||||
var data = toCopy.toCopyData();
|
||||
if (data) {
|
||||
Blockly.clipboardXml_ = data.xml;
|
||||
Blockly.clipboardSource_ = data.source;
|
||||
Blockly.clipboardTypeCounts_ = data.typeCounts;
|
||||
}
|
||||
};
|
||||
Blockly.copy = Blockly.clipboard.copy;
|
||||
|
||||
/**
|
||||
* Paste a block or workspace comment on to the main workspace.
|
||||
* @return {boolean} True if the paste was successful, false otherwise.
|
||||
* @package
|
||||
*/
|
||||
Blockly.paste = function() {
|
||||
if (!Blockly.clipboardXml_) {
|
||||
return false;
|
||||
}
|
||||
// Pasting always pastes to the main workspace, even if the copy
|
||||
// started in a flyout workspace.
|
||||
var workspace = Blockly.clipboardSource_;
|
||||
if (workspace.isFlyout) {
|
||||
workspace = workspace.targetWorkspace;
|
||||
}
|
||||
if (Blockly.clipboardTypeCounts_ &&
|
||||
workspace.isCapacityAvailable(Blockly.clipboardTypeCounts_)) {
|
||||
Blockly.Events.setGroup(true);
|
||||
workspace.paste(Blockly.clipboardXml_);
|
||||
Blockly.Events.setGroup(false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
Blockly.paste = Blockly.clipboard.paste;
|
||||
|
||||
/**
|
||||
* Duplicate this block and its children, or a workspace comment.
|
||||
@@ -274,19 +215,7 @@ Blockly.paste = function() {
|
||||
* copied.
|
||||
* @package
|
||||
*/
|
||||
Blockly.duplicate = function(toDuplicate) {
|
||||
// Save the clipboard.
|
||||
var clipboardXml = Blockly.clipboardXml_;
|
||||
var clipboardSource = Blockly.clipboardSource_;
|
||||
|
||||
// Create a duplicate via a copy/paste operation.
|
||||
Blockly.copy(toDuplicate);
|
||||
toDuplicate.workspace.paste(Blockly.clipboardXml_);
|
||||
|
||||
// Restore the clipboard.
|
||||
Blockly.clipboardXml_ = clipboardXml;
|
||||
Blockly.clipboardSource_ = clipboardSource;
|
||||
};
|
||||
Blockly.duplicate = Blockly.clipboard.duplicate;
|
||||
|
||||
/**
|
||||
* Cancel the native context menu, unless the focus is on an HTML input widget.
|
||||
@@ -310,7 +239,7 @@ Blockly.hideChaff = function(opt_onlyClosePopups) {
|
||||
Blockly.DropDownDiv.hideWithoutAnimation();
|
||||
|
||||
var onlyClosePopups = !!opt_onlyClosePopups;
|
||||
var workspace = Blockly.getMainWorkspace();
|
||||
var workspace = Blockly.common.getMainWorkspace();
|
||||
var autoHideables = workspace.getComponentManager().getComponents(
|
||||
Blockly.ComponentManager.Capability.AUTOHIDEABLE, true);
|
||||
autoHideables.forEach(function(autoHideable) {
|
||||
@@ -324,9 +253,7 @@ Blockly.hideChaff = function(opt_onlyClosePopups) {
|
||||
* Blockly instances on a page.
|
||||
* @return {!Blockly.Workspace} The main workspace.
|
||||
*/
|
||||
Blockly.getMainWorkspace = function() {
|
||||
return /** @type {!Blockly.Workspace} */ (Blockly.mainWorkspace);
|
||||
};
|
||||
Blockly.getMainWorkspace = Blockly.common.getMainWorkspace;
|
||||
|
||||
/**
|
||||
* Wrapper to window.alert() that app developers may override to
|
||||
@@ -402,9 +329,7 @@ Blockly.defineBlocksWithJsonArray = function(jsonArray) {
|
||||
'Block definition #' + i + ' in JSON array' +
|
||||
' overwrites prior definition of "' + typename + '".');
|
||||
}
|
||||
Blockly.Blocks[typename] = {
|
||||
init: Blockly.jsonInitFactory_(elem)
|
||||
};
|
||||
Blockly.Blocks[typename] = {init: Blockly.jsonInitFactory_(elem)};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -430,78 +355,6 @@ Blockly.hueToHex = function(hue) {
|
||||
Blockly.internalConstants.HSV_VALUE * 255);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks old colour constants are not overwritten by the host application.
|
||||
* If a constant is overwritten, it prints a console warning directing the
|
||||
* developer to use the equivalent Msg constant.
|
||||
* @package
|
||||
*/
|
||||
Blockly.checkBlockColourConstants = function() {
|
||||
Blockly.checkBlockColourConstant_(
|
||||
'LOGIC_HUE', ['Blocks', 'logic', 'HUE'], undefined);
|
||||
Blockly.checkBlockColourConstant_(
|
||||
'LOGIC_HUE', ['Constants', 'Logic', 'HUE'], 210);
|
||||
Blockly.checkBlockColourConstant_(
|
||||
'LOOPS_HUE', ['Blocks', 'loops', 'HUE'], undefined);
|
||||
Blockly.checkBlockColourConstant_(
|
||||
'LOOPS_HUE', ['Constants', 'Loops', 'HUE'], 120);
|
||||
Blockly.checkBlockColourConstant_(
|
||||
'MATH_HUE', ['Blocks', 'math', 'HUE'], undefined);
|
||||
Blockly.checkBlockColourConstant_(
|
||||
'MATH_HUE', ['Constants', 'Math', 'HUE'], 230);
|
||||
Blockly.checkBlockColourConstant_(
|
||||
'TEXTS_HUE', ['Blocks', 'texts', 'HUE'], undefined);
|
||||
Blockly.checkBlockColourConstant_(
|
||||
'TEXTS_HUE', ['Constants', 'Text', 'HUE'], 160);
|
||||
Blockly.checkBlockColourConstant_(
|
||||
'LISTS_HUE', ['Blocks', 'lists', 'HUE'], undefined);
|
||||
Blockly.checkBlockColourConstant_(
|
||||
'LISTS_HUE', ['Constants', 'Lists', 'HUE'], 260);
|
||||
Blockly.checkBlockColourConstant_(
|
||||
'COLOUR_HUE', ['Blocks', 'colour', 'HUE'], undefined);
|
||||
Blockly.checkBlockColourConstant_(
|
||||
'COLOUR_HUE', ['Constants', 'Colour', 'HUE'], 20);
|
||||
Blockly.checkBlockColourConstant_(
|
||||
'VARIABLES_HUE', ['Blocks', 'variables', 'HUE'], undefined);
|
||||
Blockly.checkBlockColourConstant_(
|
||||
'VARIABLES_HUE', ['Constants', 'Variables', 'HUE'], 330);
|
||||
// Blockly.Blocks.variables_dynamic.HUE never existed.
|
||||
Blockly.checkBlockColourConstant_(
|
||||
'VARIABLES_DYNAMIC_HUE', ['Constants', 'VariablesDynamic', 'HUE'], 310);
|
||||
Blockly.checkBlockColourConstant_(
|
||||
'PROCEDURES_HUE', ['Blocks', 'procedures', 'HUE'], undefined);
|
||||
// Blockly.Constants.Procedures.HUE never existed.
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks for a constant in the Blockly namespace, verifying it is undefined or
|
||||
* has the old/original value. Prints a warning if this is not true.
|
||||
* @param {string} msgName The Msg constant identifier.
|
||||
* @param {!Array<string>} blocklyNamePath The name parts of the tested
|
||||
* constant.
|
||||
* @param {number|undefined} expectedValue The expected value of the constant.
|
||||
* @private
|
||||
*/
|
||||
Blockly.checkBlockColourConstant_ = function(
|
||||
msgName, blocklyNamePath, expectedValue) {
|
||||
var namePath = 'Blockly';
|
||||
var value = Blockly;
|
||||
for (var i = 0; i < blocklyNamePath.length; ++i) {
|
||||
namePath += '.' + blocklyNamePath[i];
|
||||
if (value) {
|
||||
value = value[blocklyNamePath[i]];
|
||||
}
|
||||
}
|
||||
|
||||
if (value && value !== expectedValue) {
|
||||
var warningPattern = (expectedValue === undefined) ?
|
||||
'%1 has been removed. Use Blockly.Msg["%2"].' :
|
||||
'%1 is deprecated and unused. Override Blockly.Msg["%2"].';
|
||||
var warning = warningPattern.replace('%1', namePath).replace('%2', msgName);
|
||||
console.warn(warning);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the parent container. This is the container element that the WidgetDiv,
|
||||
* DropDownDiv, and Tooltip are rendered into the first time `Blockly.inject`
|
||||
@@ -509,9 +362,7 @@ Blockly.checkBlockColourConstant_ = function(
|
||||
* This method is a NOP if called after the first ``Blockly.inject``.
|
||||
* @param {!Element} container The container element.
|
||||
*/
|
||||
Blockly.setParentContainer = function(container) {
|
||||
Blockly.parentContainer = container;
|
||||
};
|
||||
Blockly.setParentContainer = Blockly.common.setParentContainer;
|
||||
|
||||
/** Aliases. */
|
||||
|
||||
|
||||
25
core/blockly_options.js
Normal file
25
core/blockly_options.js
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2016 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Object that defines user-specified options for the workspace.
|
||||
* @author fenichel@google.com (Rachel Fenichel)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.BlocklyOptions');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
|
||||
/**
|
||||
* Blockly options.
|
||||
* This interface is further described in
|
||||
* `typings/parts/blockly-interfaces.d.ts`.
|
||||
* @interface
|
||||
*/
|
||||
const BlocklyOptions = function() {};
|
||||
|
||||
exports = BlocklyOptions;
|
||||
@@ -10,19 +10,20 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.browserEvents');
|
||||
goog.module('Blockly.browserEvents');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Touch');
|
||||
goog.require('Blockly.utils.global');
|
||||
const Touch = goog.require('Blockly.Touch');
|
||||
const global = goog.require('Blockly.utils.global');
|
||||
|
||||
|
||||
/**
|
||||
* Blockly opaque event data used to unbind events when using
|
||||
* `Blockly.browserEvents.bind` and
|
||||
* `Blockly.browserEvents.conditionalBind`.
|
||||
* `bind` and `conditionalBind`.
|
||||
* @typedef {!Array<!Array>}
|
||||
*/
|
||||
Blockly.browserEvents.Data;
|
||||
let Data;
|
||||
exports.Data = Data;
|
||||
|
||||
/**
|
||||
* Bind an event handler that can be ignored if it is not part of the active
|
||||
@@ -40,24 +41,24 @@ Blockly.browserEvents.Data;
|
||||
* should prevent the default handler. False by default. If
|
||||
* opt_noPreventDefault is provided, opt_noCaptureIdentifier must also be
|
||||
* provided.
|
||||
* @return {!Blockly.browserEvents.Data} Opaque data that can be passed to
|
||||
* @return {!Data} Opaque data that can be passed to
|
||||
* unbindEvent_.
|
||||
* @public
|
||||
*/
|
||||
Blockly.browserEvents.conditionalBind = function(
|
||||
const conditionalBind = function(
|
||||
node, name, thisObject, func, opt_noCaptureIdentifier,
|
||||
opt_noPreventDefault) {
|
||||
var handled = false;
|
||||
var wrapFunc = function(e) {
|
||||
var captureIdentifier = !opt_noCaptureIdentifier;
|
||||
let handled = false;
|
||||
const wrapFunc = function(e) {
|
||||
const captureIdentifier = !opt_noCaptureIdentifier;
|
||||
// Handle each touch point separately. If the event was a mouse event, this
|
||||
// will hand back an array with one element, which we're fine handling.
|
||||
var events = Blockly.Touch.splitEventByTouches(e);
|
||||
for (var i = 0, event; (event = events[i]); i++) {
|
||||
if (captureIdentifier && !Blockly.Touch.shouldHandleEvent(event)) {
|
||||
const events = Touch.splitEventByTouches(e);
|
||||
for (let i = 0; i < events.length; i++) {
|
||||
const event = events[i];
|
||||
if (captureIdentifier && !Touch.shouldHandleEvent(event)) {
|
||||
continue;
|
||||
}
|
||||
Blockly.Touch.setClientFromTouch(event);
|
||||
Touch.setClientFromTouch(event);
|
||||
if (thisObject) {
|
||||
func.call(thisObject, event);
|
||||
} else {
|
||||
@@ -67,10 +68,10 @@ Blockly.browserEvents.conditionalBind = function(
|
||||
}
|
||||
};
|
||||
|
||||
var bindData = [];
|
||||
if (Blockly.utils.global['PointerEvent'] &&
|
||||
(name in Blockly.Touch.TOUCH_MAP)) {
|
||||
for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) {
|
||||
const bindData = [];
|
||||
if (global['PointerEvent'] && (name in Touch.TOUCH_MAP)) {
|
||||
for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) {
|
||||
const type = Touch.TOUCH_MAP[name][i];
|
||||
node.addEventListener(type, wrapFunc, false);
|
||||
bindData.push([node, type, wrapFunc]);
|
||||
}
|
||||
@@ -79,17 +80,18 @@ Blockly.browserEvents.conditionalBind = function(
|
||||
bindData.push([node, name, wrapFunc]);
|
||||
|
||||
// Add equivalent touch event.
|
||||
if (name in Blockly.Touch.TOUCH_MAP) {
|
||||
var touchWrapFunc = function(e) {
|
||||
if (name in Touch.TOUCH_MAP) {
|
||||
const touchWrapFunc = function(e) {
|
||||
wrapFunc(e);
|
||||
// Calling preventDefault stops the browser from scrolling/zooming the
|
||||
// page.
|
||||
var preventDef = !opt_noPreventDefault;
|
||||
const preventDef = !opt_noPreventDefault;
|
||||
if (handled && preventDef) {
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) {
|
||||
for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) {
|
||||
const type = Touch.TOUCH_MAP[name][i];
|
||||
node.addEventListener(type, touchWrapFunc, false);
|
||||
bindData.push([node, type, touchWrapFunc]);
|
||||
}
|
||||
@@ -97,6 +99,7 @@ Blockly.browserEvents.conditionalBind = function(
|
||||
}
|
||||
return bindData;
|
||||
};
|
||||
exports.conditionalBind = conditionalBind;
|
||||
|
||||
|
||||
/**
|
||||
@@ -108,12 +111,11 @@ Blockly.browserEvents.conditionalBind = function(
|
||||
* @param {string} name Event name to listen to (e.g. 'mousedown').
|
||||
* @param {?Object} thisObject The value of 'this' in the function.
|
||||
* @param {!Function} func Function to call when event is triggered.
|
||||
* @return {!Blockly.browserEvents.Data} Opaque data that can be passed to
|
||||
* @return {!Data} Opaque data that can be passed to
|
||||
* unbindEvent_.
|
||||
* @public
|
||||
*/
|
||||
Blockly.browserEvents.bind = function(node, name, thisObject, func) {
|
||||
var wrapFunc = function(e) {
|
||||
const bind = function(node, name, thisObject, func) {
|
||||
const wrapFunc = function(e) {
|
||||
if (thisObject) {
|
||||
func.call(thisObject, e);
|
||||
} else {
|
||||
@@ -121,10 +123,10 @@ Blockly.browserEvents.bind = function(node, name, thisObject, func) {
|
||||
}
|
||||
};
|
||||
|
||||
var bindData = [];
|
||||
if (Blockly.utils.global['PointerEvent'] &&
|
||||
(name in Blockly.Touch.TOUCH_MAP)) {
|
||||
for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) {
|
||||
const bindData = [];
|
||||
if (global['PointerEvent'] && (name in Touch.TOUCH_MAP)) {
|
||||
for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) {
|
||||
const type = Touch.TOUCH_MAP[name][i];
|
||||
node.addEventListener(type, wrapFunc, false);
|
||||
bindData.push([node, type, wrapFunc]);
|
||||
}
|
||||
@@ -133,12 +135,12 @@ Blockly.browserEvents.bind = function(node, name, thisObject, func) {
|
||||
bindData.push([node, name, wrapFunc]);
|
||||
|
||||
// Add equivalent touch event.
|
||||
if (name in Blockly.Touch.TOUCH_MAP) {
|
||||
var touchWrapFunc = function(e) {
|
||||
if (name in Touch.TOUCH_MAP) {
|
||||
const touchWrapFunc = function(e) {
|
||||
// Punt on multitouch events.
|
||||
if (e.changedTouches && e.changedTouches.length == 1) {
|
||||
// Map the touch event's properties to the event.
|
||||
var touchPoint = e.changedTouches[0];
|
||||
const touchPoint = e.changedTouches[0];
|
||||
e.clientX = touchPoint.clientX;
|
||||
e.clientY = touchPoint.clientY;
|
||||
}
|
||||
@@ -147,7 +149,8 @@ Blockly.browserEvents.bind = function(node, name, thisObject, func) {
|
||||
// Stop the browser from scrolling/zooming the page.
|
||||
e.preventDefault();
|
||||
};
|
||||
for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) {
|
||||
for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) {
|
||||
const type = Touch.TOUCH_MAP[name][i];
|
||||
node.addEventListener(type, touchWrapFunc, false);
|
||||
bindData.push([node, type, touchWrapFunc]);
|
||||
}
|
||||
@@ -155,21 +158,23 @@ Blockly.browserEvents.bind = function(node, name, thisObject, func) {
|
||||
}
|
||||
return bindData;
|
||||
};
|
||||
exports.bind = bind;
|
||||
|
||||
/**
|
||||
* Unbind one or more events event from a function call.
|
||||
* @param {!Blockly.browserEvents.Data} bindData Opaque data from bindEvent_.
|
||||
* @param {!Data} bindData Opaque data from bindEvent_.
|
||||
* This list is emptied during the course of calling this function.
|
||||
* @return {!Function} The function call.
|
||||
* @public
|
||||
*/
|
||||
Blockly.browserEvents.unbind = function(bindData) {
|
||||
const unbind = function(bindData) {
|
||||
let func;
|
||||
while (bindData.length) {
|
||||
var bindDatum = bindData.pop();
|
||||
var node = bindDatum[0];
|
||||
var name = bindDatum[1];
|
||||
var func = bindDatum[2];
|
||||
const bindDatum = bindData.pop();
|
||||
const node = bindDatum[0];
|
||||
const name = bindDatum[1];
|
||||
func = bindDatum[2];
|
||||
node.removeEventListener(name, func, false);
|
||||
}
|
||||
return func;
|
||||
};
|
||||
exports.unbind = unbind;
|
||||
|
||||
455
core/bubble.js
455
core/bubble.js
@@ -10,42 +10,49 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Bubble');
|
||||
goog.module('Blockly.Bubble');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.browserEvents');
|
||||
goog.require('Blockly.IBubble');
|
||||
goog.require('Blockly.Scrollbar');
|
||||
goog.require('Blockly.Touch');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.math');
|
||||
goog.require('Blockly.utils.Size');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
goog.require('Blockly.utils.userAgent');
|
||||
// TODO(#5073): Fix Blockly requires for Blockly.hideChaff()
|
||||
// const Blockly = goog.require('Blockly');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockDragSurfaceSvg = goog.requireType('Blockly.BlockDragSurfaceSvg');
|
||||
/* 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 IBubble = goog.requireType('Blockly.IBubble');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const MetricsManager = goog.requireType('Blockly.MetricsManager');
|
||||
const Scrollbar = goog.require('Blockly.Scrollbar');
|
||||
const Size = goog.require('Blockly.utils.Size');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
const Touch = goog.require('Blockly.Touch');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const browserEvents = goog.require('Blockly.browserEvents');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const math = goog.require('Blockly.utils.math');
|
||||
const userAgent = goog.require('Blockly.utils.userAgent');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Workspace');
|
||||
|
||||
goog.requireType('Blockly.BlockDragSurfaceSvg');
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.MetricsManager');
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
|
||||
|
||||
/**
|
||||
* Class for UI bubble.
|
||||
* @param {!Blockly.WorkspaceSvg} workspace The workspace on which to draw the
|
||||
* @param {!WorkspaceSvg} workspace The workspace on which to draw the
|
||||
* bubble.
|
||||
* @param {!Element} content SVG content for the bubble.
|
||||
* @param {!Element} shape SVG element to avoid eclipsing.
|
||||
* @param {!Blockly.utils.Coordinate} anchorXY Absolute position of bubble's
|
||||
* @param {!Coordinate} anchorXY Absolute position of bubble's
|
||||
* anchor point.
|
||||
* @param {?number} bubbleWidth Width of bubble, or null if not resizable.
|
||||
* @param {?number} bubbleHeight Height of bubble, or null if not resizable.
|
||||
* @implements {Blockly.IBubble}
|
||||
* @implements {IBubble}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Bubble = function(
|
||||
const Bubble = function(
|
||||
workspace, content, shape, anchorXY, bubbleWidth, bubbleHeight) {
|
||||
this.workspace_ = workspace;
|
||||
this.content_ = content;
|
||||
@@ -67,14 +74,14 @@ Blockly.Bubble = function(
|
||||
|
||||
/**
|
||||
* Mouse down on bubbleBack_ event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.onMouseDownBubbleWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Mouse down on resizeGroup_ event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.onMouseDownResizeWrapper_ = null;
|
||||
@@ -87,20 +94,20 @@ Blockly.Bubble = function(
|
||||
*/
|
||||
this.disposed = false;
|
||||
|
||||
var angle = Blockly.Bubble.ARROW_ANGLE;
|
||||
let angle = Bubble.ARROW_ANGLE;
|
||||
if (this.workspace_.RTL) {
|
||||
angle = -angle;
|
||||
}
|
||||
this.arrow_radians_ = Blockly.utils.math.toRadians(angle);
|
||||
this.arrow_radians_ = math.toRadians(angle);
|
||||
|
||||
var canvas = workspace.getBubbleCanvas();
|
||||
const canvas = workspace.getBubbleCanvas();
|
||||
canvas.appendChild(this.createDom_(content, !!(bubbleWidth && bubbleHeight)));
|
||||
|
||||
this.setAnchorLocation(anchorXY);
|
||||
if (!bubbleWidth || !bubbleHeight) {
|
||||
var bBox = /** @type {SVGLocatable} */ (this.content_).getBBox();
|
||||
bubbleWidth = bBox.width + 2 * Blockly.Bubble.BORDER_WIDTH;
|
||||
bubbleHeight = bBox.height + 2 * Blockly.Bubble.BORDER_WIDTH;
|
||||
const bBox = /** @type {SVGLocatable} */ (this.content_).getBBox();
|
||||
bubbleWidth = bBox.width + 2 * Bubble.BORDER_WIDTH;
|
||||
bubbleHeight = bBox.height + 2 * Bubble.BORDER_WIDTH;
|
||||
}
|
||||
this.setBubbleSize(bubbleWidth, bubbleHeight);
|
||||
|
||||
@@ -113,55 +120,55 @@ Blockly.Bubble = function(
|
||||
/**
|
||||
* Width of the border around the bubble.
|
||||
*/
|
||||
Blockly.Bubble.BORDER_WIDTH = 6;
|
||||
Bubble.BORDER_WIDTH = 6;
|
||||
|
||||
/**
|
||||
* Determines the thickness of the base of the arrow in relation to the size
|
||||
* of the bubble. Higher numbers result in thinner arrows.
|
||||
*/
|
||||
Blockly.Bubble.ARROW_THICKNESS = 5;
|
||||
Bubble.ARROW_THICKNESS = 5;
|
||||
|
||||
/**
|
||||
* The number of degrees that the arrow bends counter-clockwise.
|
||||
*/
|
||||
Blockly.Bubble.ARROW_ANGLE = 20;
|
||||
Bubble.ARROW_ANGLE = 20;
|
||||
|
||||
/**
|
||||
* The sharpness of the arrow's bend. Higher numbers result in smoother arrows.
|
||||
*/
|
||||
Blockly.Bubble.ARROW_BEND = 4;
|
||||
Bubble.ARROW_BEND = 4;
|
||||
|
||||
/**
|
||||
* Distance between arrow point and anchor point.
|
||||
*/
|
||||
Blockly.Bubble.ANCHOR_RADIUS = 8;
|
||||
Bubble.ANCHOR_RADIUS = 8;
|
||||
|
||||
/**
|
||||
* Mouse up event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.onMouseUpWrapper_ = null;
|
||||
Bubble.onMouseUpWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Mouse move event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.onMouseMoveWrapper_ = null;
|
||||
Bubble.onMouseMoveWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Stop binding to the global mouseup and mousemove events.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.unbindDragEvents_ = function() {
|
||||
if (Blockly.Bubble.onMouseUpWrapper_) {
|
||||
Blockly.browserEvents.unbind(Blockly.Bubble.onMouseUpWrapper_);
|
||||
Blockly.Bubble.onMouseUpWrapper_ = null;
|
||||
Bubble.unbindDragEvents_ = function() {
|
||||
if (Bubble.onMouseUpWrapper_) {
|
||||
browserEvents.unbind(Bubble.onMouseUpWrapper_);
|
||||
Bubble.onMouseUpWrapper_ = null;
|
||||
}
|
||||
if (Blockly.Bubble.onMouseMoveWrapper_) {
|
||||
Blockly.browserEvents.unbind(Blockly.Bubble.onMouseMoveWrapper_);
|
||||
Blockly.Bubble.onMouseMoveWrapper_ = null;
|
||||
if (Bubble.onMouseMoveWrapper_) {
|
||||
browserEvents.unbind(Bubble.onMouseMoveWrapper_);
|
||||
Bubble.onMouseMoveWrapper_ = null;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -170,23 +177,23 @@ Blockly.Bubble.unbindDragEvents_ = function() {
|
||||
* @param {!Event} _e Mouse up event.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.bubbleMouseUp_ = function(_e) {
|
||||
Blockly.Touch.clearTouchIdentifier();
|
||||
Blockly.Bubble.unbindDragEvents_();
|
||||
Bubble.bubbleMouseUp_ = function(_e) {
|
||||
Touch.clearTouchIdentifier();
|
||||
Bubble.unbindDragEvents_();
|
||||
};
|
||||
|
||||
/**
|
||||
* Flag to stop incremental rendering during construction.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.prototype.rendered_ = false;
|
||||
Bubble.prototype.rendered_ = false;
|
||||
|
||||
/**
|
||||
* Absolute coordinate of anchor point, in workspace coordinates.
|
||||
* @type {Blockly.utils.Coordinate}
|
||||
* @type {Coordinate}
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.prototype.anchorXY_ = null;
|
||||
Bubble.prototype.anchorXY_ = null;
|
||||
|
||||
/**
|
||||
* Relative X coordinate of bubble with respect to the anchor's centre,
|
||||
@@ -194,32 +201,32 @@ Blockly.Bubble.prototype.anchorXY_ = null;
|
||||
* In RTL mode the initial value is negated.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.prototype.relativeLeft_ = 0;
|
||||
Bubble.prototype.relativeLeft_ = 0;
|
||||
|
||||
/**
|
||||
* Relative Y coordinate of bubble with respect to the anchor's centre, in
|
||||
* workspace units.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.prototype.relativeTop_ = 0;
|
||||
Bubble.prototype.relativeTop_ = 0;
|
||||
|
||||
/**
|
||||
* Width of bubble, in workspace units.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.prototype.width_ = 0;
|
||||
Bubble.prototype.width_ = 0;
|
||||
|
||||
/**
|
||||
* Height of bubble, in workspace units.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.prototype.height_ = 0;
|
||||
Bubble.prototype.height_ = 0;
|
||||
|
||||
/**
|
||||
* Automatically position and reposition the bubble.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.prototype.autoLayout_ = true;
|
||||
Bubble.prototype.autoLayout_ = true;
|
||||
|
||||
/**
|
||||
* Create the bubble's DOM.
|
||||
@@ -228,7 +235,7 @@ Blockly.Bubble.prototype.autoLayout_ = true;
|
||||
* @return {!SVGElement} The bubble's SVG group.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.prototype.createDom_ = function(content, hasResize) {
|
||||
Bubble.prototype.createDom_ = function(content, hasResize) {
|
||||
/* Create the bubble. Here's the markup that will be generated:
|
||||
<g>
|
||||
<g filter="url(#blocklyEmbossFilter837493)">
|
||||
@@ -243,42 +250,39 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) {
|
||||
[...content goes here...]
|
||||
</g>
|
||||
*/
|
||||
this.bubbleGroup_ =
|
||||
Blockly.utils.dom.createSvgElement(Blockly.utils.Svg.G, {}, null);
|
||||
var filter = {
|
||||
this.bubbleGroup_ = dom.createSvgElement(Svg.G, {}, null);
|
||||
let filter = {
|
||||
'filter': 'url(#' +
|
||||
this.workspace_.getRenderer().getConstants().embossFilterId + ')'
|
||||
};
|
||||
if (Blockly.utils.userAgent.JAVA_FX) {
|
||||
if (userAgent.JAVA_FX) {
|
||||
// Multiple reports that JavaFX can't handle filters.
|
||||
// https://github.com/google/blockly/issues/99
|
||||
filter = {};
|
||||
}
|
||||
var bubbleEmboss = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.G, filter, this.bubbleGroup_);
|
||||
this.bubbleArrow_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.PATH, {}, bubbleEmboss);
|
||||
this.bubbleBack_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.RECT, {
|
||||
const bubbleEmboss = dom.createSvgElement(Svg.G, filter, this.bubbleGroup_);
|
||||
this.bubbleArrow_ = dom.createSvgElement(Svg.PATH, {}, bubbleEmboss);
|
||||
this.bubbleBack_ = dom.createSvgElement(
|
||||
Svg.RECT, {
|
||||
'class': 'blocklyDraggable',
|
||||
'x': 0,
|
||||
'y': 0,
|
||||
'rx': Blockly.Bubble.BORDER_WIDTH,
|
||||
'ry': Blockly.Bubble.BORDER_WIDTH
|
||||
'rx': Bubble.BORDER_WIDTH,
|
||||
'ry': Bubble.BORDER_WIDTH
|
||||
},
|
||||
bubbleEmboss);
|
||||
if (hasResize) {
|
||||
this.resizeGroup_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.G,
|
||||
this.resizeGroup_ = dom.createSvgElement(
|
||||
Svg.G,
|
||||
{'class': this.workspace_.RTL ? 'blocklyResizeSW' : 'blocklyResizeSE'},
|
||||
this.bubbleGroup_);
|
||||
var resizeSize = 2 * Blockly.Bubble.BORDER_WIDTH;
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.POLYGON,
|
||||
const resizeSize = 2 * Bubble.BORDER_WIDTH;
|
||||
dom.createSvgElement(
|
||||
Svg.POLYGON,
|
||||
{'points': '0,x x,x x,0'.replace(/x/g, resizeSize.toString())},
|
||||
this.resizeGroup_);
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.LINE, {
|
||||
dom.createSvgElement(
|
||||
Svg.LINE, {
|
||||
'class': 'blocklyResizeLine',
|
||||
'x1': resizeSize / 3,
|
||||
'y1': resizeSize - 1,
|
||||
@@ -286,8 +290,8 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) {
|
||||
'y2': resizeSize / 3
|
||||
},
|
||||
this.resizeGroup_);
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.LINE, {
|
||||
dom.createSvgElement(
|
||||
Svg.LINE, {
|
||||
'class': 'blocklyResizeLine',
|
||||
'x1': resizeSize * 2 / 3,
|
||||
'y1': resizeSize - 1,
|
||||
@@ -300,10 +304,10 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) {
|
||||
}
|
||||
|
||||
if (!this.workspace_.options.readOnly) {
|
||||
this.onMouseDownBubbleWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
this.onMouseDownBubbleWrapper_ = browserEvents.conditionalBind(
|
||||
this.bubbleBack_, 'mousedown', this, this.bubbleMouseDown_);
|
||||
if (this.resizeGroup_) {
|
||||
this.onMouseDownResizeWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
this.onMouseDownResizeWrapper_ = browserEvents.conditionalBind(
|
||||
this.resizeGroup_, 'mousedown', this, this.resizeMouseDown_);
|
||||
}
|
||||
}
|
||||
@@ -315,7 +319,7 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) {
|
||||
* Return the root node of the bubble's SVG group.
|
||||
* @return {!SVGElement} The root SVG node of the bubble's group.
|
||||
*/
|
||||
Blockly.Bubble.prototype.getSvgRoot = function() {
|
||||
Bubble.prototype.getSvgRoot = function() {
|
||||
return this.bubbleGroup_;
|
||||
};
|
||||
|
||||
@@ -323,7 +327,7 @@ Blockly.Bubble.prototype.getSvgRoot = function() {
|
||||
* Expose the block's ID on the bubble's top-level SVG group.
|
||||
* @param {string} id ID of block.
|
||||
*/
|
||||
Blockly.Bubble.prototype.setSvgId = function(id) {
|
||||
Bubble.prototype.setSvgId = function(id) {
|
||||
if (this.bubbleGroup_.dataset) {
|
||||
this.bubbleGroup_.dataset['blockId'] = id;
|
||||
}
|
||||
@@ -334,8 +338,8 @@ Blockly.Bubble.prototype.setSvgId = function(id) {
|
||||
* @param {!Event} e Mouse down event.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.prototype.bubbleMouseDown_ = function(e) {
|
||||
var gesture = this.workspace_.getGesture(e);
|
||||
Bubble.prototype.bubbleMouseDown_ = function(e) {
|
||||
const gesture = this.workspace_.getGesture(e);
|
||||
if (gesture) {
|
||||
gesture.handleBubbleStart(e, this);
|
||||
}
|
||||
@@ -346,7 +350,7 @@ Blockly.Bubble.prototype.bubbleMouseDown_ = function(e) {
|
||||
* @param {!Event} _e Mouse event.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Bubble.prototype.showContextMenu = function(_e) {
|
||||
Bubble.prototype.showContextMenu = function(_e) {
|
||||
// NOP on bubbles, but used by the bubble dragger to pass events to
|
||||
// workspace comments.
|
||||
};
|
||||
@@ -356,7 +360,7 @@ Blockly.Bubble.prototype.showContextMenu = function(_e) {
|
||||
* @return {boolean} True if deletable.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Bubble.prototype.isDeletable = function() {
|
||||
Bubble.prototype.isDeletable = function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -365,7 +369,7 @@ Blockly.Bubble.prototype.isDeletable = function() {
|
||||
* @param {boolean} _enable True if the bubble is about to be deleted, false
|
||||
* otherwise.
|
||||
*/
|
||||
Blockly.Bubble.prototype.setDeleteStyle = function(_enable) {
|
||||
Bubble.prototype.setDeleteStyle = function(_enable) {
|
||||
// NOP if bubble is not deletable.
|
||||
};
|
||||
|
||||
@@ -374,10 +378,10 @@ Blockly.Bubble.prototype.setDeleteStyle = function(_enable) {
|
||||
* @param {!Event} e Mouse down event.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.prototype.resizeMouseDown_ = function(e) {
|
||||
Bubble.prototype.resizeMouseDown_ = function(e) {
|
||||
this.promote();
|
||||
Blockly.Bubble.unbindDragEvents_();
|
||||
if (Blockly.utils.isRightButton(e)) {
|
||||
Bubble.unbindDragEvents_();
|
||||
if (utils.isRightButton(e)) {
|
||||
// No right-click.
|
||||
e.stopPropagation();
|
||||
return;
|
||||
@@ -385,12 +389,12 @@ Blockly.Bubble.prototype.resizeMouseDown_ = function(e) {
|
||||
// Left-click (or middle click)
|
||||
this.workspace_.startDrag(
|
||||
e,
|
||||
new Blockly.utils.Coordinate(
|
||||
new Coordinate(
|
||||
this.workspace_.RTL ? -this.width_ : this.width_, this.height_));
|
||||
|
||||
Blockly.Bubble.onMouseUpWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
document, 'mouseup', this, Blockly.Bubble.bubbleMouseUp_);
|
||||
Blockly.Bubble.onMouseMoveWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
Bubble.onMouseUpWrapper_ = browserEvents.conditionalBind(
|
||||
document, 'mouseup', this, Bubble.bubbleMouseUp_);
|
||||
Bubble.onMouseMoveWrapper_ = browserEvents.conditionalBind(
|
||||
document, 'mousemove', this, this.resizeMouseMove_);
|
||||
Blockly.hideChaff();
|
||||
// This event has been handled. No need to bubble up to the document.
|
||||
@@ -402,9 +406,9 @@ Blockly.Bubble.prototype.resizeMouseDown_ = function(e) {
|
||||
* @param {!Event} e Mouse move event.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.prototype.resizeMouseMove_ = function(e) {
|
||||
Bubble.prototype.resizeMouseMove_ = function(e) {
|
||||
this.autoLayout_ = false;
|
||||
var newXY = this.workspace_.moveDrag(e);
|
||||
const newXY = this.workspace_.moveDrag(e);
|
||||
this.setBubbleSize(this.workspace_.RTL ? -newXY.x : newXY.x, newXY.y);
|
||||
if (this.workspace_.RTL) {
|
||||
// RTL requires the bubble to move its left edge.
|
||||
@@ -416,7 +420,7 @@ Blockly.Bubble.prototype.resizeMouseMove_ = function(e) {
|
||||
* Register a function as a callback event for when the bubble is resized.
|
||||
* @param {!Function} callback The function to call on resize.
|
||||
*/
|
||||
Blockly.Bubble.prototype.registerResizeEvent = function(callback) {
|
||||
Bubble.prototype.registerResizeEvent = function(callback) {
|
||||
this.resizeCallback_ = callback;
|
||||
};
|
||||
|
||||
@@ -424,7 +428,7 @@ Blockly.Bubble.prototype.registerResizeEvent = function(callback) {
|
||||
* Register a function as a callback event for when the bubble is moved.
|
||||
* @param {!Function} callback The function to call on move.
|
||||
*/
|
||||
Blockly.Bubble.prototype.registerMoveEvent = function(callback) {
|
||||
Bubble.prototype.registerMoveEvent = function(callback) {
|
||||
this.moveCallback_ = callback;
|
||||
};
|
||||
|
||||
@@ -433,8 +437,8 @@ Blockly.Bubble.prototype.registerMoveEvent = function(callback) {
|
||||
* @return {boolean} Whether or not the bubble has been moved.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Bubble.prototype.promote = function() {
|
||||
var svgGroup = this.bubbleGroup_.parentNode;
|
||||
Bubble.prototype.promote = function() {
|
||||
const svgGroup = this.bubbleGroup_.parentNode;
|
||||
if (svgGroup.lastChild !== this.bubbleGroup_) {
|
||||
svgGroup.appendChild(this.bubbleGroup_);
|
||||
return true;
|
||||
@@ -445,9 +449,9 @@ Blockly.Bubble.prototype.promote = function() {
|
||||
/**
|
||||
* Notification that the anchor has moved.
|
||||
* Update the arrow and bubble accordingly.
|
||||
* @param {!Blockly.utils.Coordinate} xy Absolute location.
|
||||
* @param {!Coordinate} xy Absolute location.
|
||||
*/
|
||||
Blockly.Bubble.prototype.setAnchorLocation = function(xy) {
|
||||
Bubble.prototype.setAnchorLocation = function(xy) {
|
||||
this.anchorXY_ = xy;
|
||||
if (this.rendered_) {
|
||||
this.positionBubble_();
|
||||
@@ -458,34 +462,36 @@ Blockly.Bubble.prototype.setAnchorLocation = function(xy) {
|
||||
* Position the bubble so that it does not fall off-screen.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.prototype.layoutBubble_ = function() {
|
||||
Bubble.prototype.layoutBubble_ = function() {
|
||||
// Get the metrics in workspace units.
|
||||
var viewMetrics = this.workspace_.getMetricsManager().getViewMetrics(true);
|
||||
const viewMetrics = this.workspace_.getMetricsManager().getViewMetrics(true);
|
||||
|
||||
var optimalLeft = this.getOptimalRelativeLeft_(viewMetrics);
|
||||
var optimalTop = this.getOptimalRelativeTop_(viewMetrics);
|
||||
var bbox = this.shape_.getBBox();
|
||||
const optimalLeft = this.getOptimalRelativeLeft_(viewMetrics);
|
||||
const optimalTop = this.getOptimalRelativeTop_(viewMetrics);
|
||||
const bbox = this.shape_.getBBox();
|
||||
|
||||
var topPosition = {
|
||||
const topPosition = {
|
||||
x: optimalLeft,
|
||||
y: -this.height_ -
|
||||
this.workspace_.getRenderer().getConstants().MIN_BLOCK_HEIGHT
|
||||
};
|
||||
var startPosition = {x: -this.width_ - 30, y: optimalTop};
|
||||
var endPosition = {x: bbox.width, y: optimalTop};
|
||||
var bottomPosition = {x: optimalLeft, y: bbox.height};
|
||||
const startPosition = {x: -this.width_ - 30, y: optimalTop};
|
||||
const endPosition = {x: bbox.width, y: optimalTop};
|
||||
const bottomPosition = {x: optimalLeft, y: bbox.height};
|
||||
|
||||
var closerPosition = bbox.width < bbox.height ? endPosition : bottomPosition;
|
||||
var fartherPosition = bbox.width < bbox.height ? bottomPosition : endPosition;
|
||||
const closerPosition =
|
||||
bbox.width < bbox.height ? endPosition : bottomPosition;
|
||||
const fartherPosition =
|
||||
bbox.width < bbox.height ? bottomPosition : endPosition;
|
||||
|
||||
var topPositionOverlap = this.getOverlap_(topPosition, viewMetrics);
|
||||
var startPositionOverlap = this.getOverlap_(startPosition, viewMetrics);
|
||||
var closerPositionOverlap = this.getOverlap_(closerPosition, viewMetrics);
|
||||
var fartherPositionOverlap = this.getOverlap_(fartherPosition, viewMetrics);
|
||||
const topPositionOverlap = this.getOverlap_(topPosition, viewMetrics);
|
||||
const startPositionOverlap = this.getOverlap_(startPosition, viewMetrics);
|
||||
const closerPositionOverlap = this.getOverlap_(closerPosition, viewMetrics);
|
||||
const fartherPositionOverlap = this.getOverlap_(fartherPosition, viewMetrics);
|
||||
|
||||
// Set the position to whichever position shows the most of the bubble,
|
||||
// with tiebreaks going in the order: top > start > close > far.
|
||||
var mostOverlap = Math.max(
|
||||
const mostOverlap = Math.max(
|
||||
topPositionOverlap, startPositionOverlap, closerPositionOverlap,
|
||||
fartherPositionOverlap);
|
||||
if (topPositionOverlap == mostOverlap) {
|
||||
@@ -515,20 +521,23 @@ Blockly.Bubble.prototype.layoutBubble_ = function() {
|
||||
* workspace (what percentage of the bubble is visible).
|
||||
* @param {!{x: number, y: number}} relativeMin The position of the top-left
|
||||
* corner of the bubble relative to the anchor point.
|
||||
* @param {!Blockly.MetricsManager.ContainerRegion} viewMetrics The view metrics
|
||||
* @param {!MetricsManager.ContainerRegion} viewMetrics The view metrics
|
||||
* of the workspace the bubble will appear in.
|
||||
* @return {number} The percentage of the bubble that is visible.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.prototype.getOverlap_ = function(relativeMin, viewMetrics) {
|
||||
Bubble.prototype.getOverlap_ = function(relativeMin, viewMetrics) {
|
||||
// The position of the top-left corner of the bubble in workspace units.
|
||||
var bubbleMin = {
|
||||
const bubbleMin = {
|
||||
x: this.workspace_.RTL ? (this.anchorXY_.x - relativeMin.x - this.width_) :
|
||||
(relativeMin.x + this.anchorXY_.x),
|
||||
y: relativeMin.y + this.anchorXY_.y
|
||||
};
|
||||
// The position of the bottom-right corner of the bubble in workspace units.
|
||||
var bubbleMax = {x: bubbleMin.x + this.width_, y: bubbleMin.y + this.height_};
|
||||
const bubbleMax = {
|
||||
x: bubbleMin.x + this.width_,
|
||||
y: bubbleMin.y + this.height_
|
||||
};
|
||||
|
||||
// We could adjust these values to account for the scrollbars, but the
|
||||
// bubbles should have been adjusted to not collide with them anyway, so
|
||||
@@ -536,16 +545,16 @@ Blockly.Bubble.prototype.getOverlap_ = function(relativeMin, viewMetrics) {
|
||||
// calculation.
|
||||
|
||||
// The position of the top-left corner of the workspace.
|
||||
var workspaceMin = {x: viewMetrics.left, y: viewMetrics.top};
|
||||
const workspaceMin = {x: viewMetrics.left, y: viewMetrics.top};
|
||||
// The position of the bottom-right corner of the workspace.
|
||||
var workspaceMax = {
|
||||
const workspaceMax = {
|
||||
x: viewMetrics.left + viewMetrics.width,
|
||||
y: viewMetrics.top + viewMetrics.height
|
||||
};
|
||||
|
||||
var overlapWidth = Math.min(bubbleMax.x, workspaceMax.x) -
|
||||
const overlapWidth = Math.min(bubbleMax.x, workspaceMax.x) -
|
||||
Math.max(bubbleMin.x, workspaceMin.x);
|
||||
var overlapHeight = Math.min(bubbleMax.y, workspaceMax.y) -
|
||||
const overlapHeight = Math.min(bubbleMax.y, workspaceMax.y) -
|
||||
Math.max(bubbleMin.y, workspaceMin.y);
|
||||
return Math.max(
|
||||
0,
|
||||
@@ -557,14 +566,14 @@ Blockly.Bubble.prototype.getOverlap_ = function(relativeMin, viewMetrics) {
|
||||
* Calculate what the optimal horizontal position of the top-left corner of the
|
||||
* bubble is (relative to the anchor point) so that the most area of the
|
||||
* bubble is shown.
|
||||
* @param {!Blockly.MetricsManager.ContainerRegion} viewMetrics The view metrics
|
||||
* @param {!MetricsManager.ContainerRegion} viewMetrics The view metrics
|
||||
* of the workspace the bubble will appear in.
|
||||
* @return {number} The optimal horizontal position of the top-left corner
|
||||
* of the bubble.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.prototype.getOptimalRelativeLeft_ = function(viewMetrics) {
|
||||
var relativeLeft = -this.width_ / 4;
|
||||
Bubble.prototype.getOptimalRelativeLeft_ = function(viewMetrics) {
|
||||
let relativeLeft = -this.width_ / 4;
|
||||
|
||||
// No amount of sliding left or right will give us a better overlap.
|
||||
if (this.width_ > viewMetrics.width) {
|
||||
@@ -573,24 +582,14 @@ Blockly.Bubble.prototype.getOptimalRelativeLeft_ = function(viewMetrics) {
|
||||
|
||||
if (this.workspace_.RTL) {
|
||||
// Bubble coordinates are flipped in RTL.
|
||||
var bubbleRight = this.anchorXY_.x - relativeLeft;
|
||||
var bubbleLeft = bubbleRight - this.width_;
|
||||
const bubbleRight = this.anchorXY_.x - relativeLeft;
|
||||
const bubbleLeft = bubbleRight - this.width_;
|
||||
|
||||
var workspaceRight = viewMetrics.left + viewMetrics.width;
|
||||
var workspaceLeft = viewMetrics.left +
|
||||
const workspaceRight = viewMetrics.left + viewMetrics.width;
|
||||
const workspaceLeft = viewMetrics.left +
|
||||
// Thickness in workspace units.
|
||||
(Blockly.Scrollbar.scrollbarThickness / this.workspace_.scale);
|
||||
} else {
|
||||
var bubbleLeft = relativeLeft + this.anchorXY_.x;
|
||||
var bubbleRight = bubbleLeft + this.width_;
|
||||
(Scrollbar.scrollbarThickness / this.workspace_.scale);
|
||||
|
||||
var workspaceLeft = viewMetrics.left;
|
||||
var workspaceRight = viewMetrics.left + viewMetrics.width -
|
||||
// Thickness in workspace units.
|
||||
(Blockly.Scrollbar.scrollbarThickness / this.workspace_.scale);
|
||||
}
|
||||
|
||||
if (this.workspace_.RTL) {
|
||||
if (bubbleLeft < workspaceLeft) {
|
||||
// Slide the bubble right until it is onscreen.
|
||||
relativeLeft = -(workspaceLeft - this.anchorXY_.x + this.width_);
|
||||
@@ -599,6 +598,14 @@ Blockly.Bubble.prototype.getOptimalRelativeLeft_ = function(viewMetrics) {
|
||||
relativeLeft = -(workspaceRight - this.anchorXY_.x);
|
||||
}
|
||||
} else {
|
||||
const bubbleLeft = relativeLeft + this.anchorXY_.x;
|
||||
const bubbleRight = bubbleLeft + this.width_;
|
||||
|
||||
const workspaceLeft = viewMetrics.left;
|
||||
const workspaceRight = viewMetrics.left + viewMetrics.width -
|
||||
// Thickness in workspace units.
|
||||
(Scrollbar.scrollbarThickness / this.workspace_.scale);
|
||||
|
||||
if (bubbleLeft < workspaceLeft) {
|
||||
// Slide the bubble right until it is onscreen.
|
||||
relativeLeft = workspaceLeft - this.anchorXY_.x;
|
||||
@@ -615,28 +622,28 @@ Blockly.Bubble.prototype.getOptimalRelativeLeft_ = function(viewMetrics) {
|
||||
* Calculate what the optimal vertical position of the top-left corner of
|
||||
* the bubble is (relative to the anchor point) so that the most area of the
|
||||
* bubble is shown.
|
||||
* @param {!Blockly.MetricsManager.ContainerRegion} viewMetrics The view metrics
|
||||
* @param {!MetricsManager.ContainerRegion} viewMetrics The view metrics
|
||||
* of the workspace the bubble will appear in.
|
||||
* @return {number} The optimal vertical position of the top-left corner
|
||||
* of the bubble.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.prototype.getOptimalRelativeTop_ = function(viewMetrics) {
|
||||
var relativeTop = -this.height_ / 4;
|
||||
Bubble.prototype.getOptimalRelativeTop_ = function(viewMetrics) {
|
||||
let relativeTop = -this.height_ / 4;
|
||||
|
||||
// No amount of sliding up or down will give us a better overlap.
|
||||
if (this.height_ > viewMetrics.height) {
|
||||
return relativeTop;
|
||||
}
|
||||
|
||||
var bubbleTop = this.anchorXY_.y + relativeTop;
|
||||
var bubbleBottom = bubbleTop + this.height_;
|
||||
var workspaceTop = viewMetrics.top;
|
||||
var workspaceBottom = viewMetrics.top + viewMetrics.height -
|
||||
const bubbleTop = this.anchorXY_.y + relativeTop;
|
||||
const bubbleBottom = bubbleTop + this.height_;
|
||||
const workspaceTop = viewMetrics.top;
|
||||
const workspaceBottom = viewMetrics.top + viewMetrics.height -
|
||||
// Thickness in workspace units.
|
||||
(Blockly.Scrollbar.scrollbarThickness / this.workspace_.scale);
|
||||
(Scrollbar.scrollbarThickness / this.workspace_.scale);
|
||||
|
||||
var anchorY = this.anchorXY_.y;
|
||||
const anchorY = this.anchorXY_.y;
|
||||
if (bubbleTop < workspaceTop) {
|
||||
// Slide the bubble down until it is onscreen.
|
||||
relativeTop = workspaceTop - anchorY;
|
||||
@@ -652,14 +659,14 @@ Blockly.Bubble.prototype.getOptimalRelativeTop_ = function(viewMetrics) {
|
||||
* Move the bubble to a location relative to the anchor's centre.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.prototype.positionBubble_ = function() {
|
||||
var left = this.anchorXY_.x;
|
||||
Bubble.prototype.positionBubble_ = function() {
|
||||
let left = this.anchorXY_.x;
|
||||
if (this.workspace_.RTL) {
|
||||
left -= this.relativeLeft_ + this.width_;
|
||||
} else {
|
||||
left += this.relativeLeft_;
|
||||
}
|
||||
var top = this.relativeTop_ + this.anchorXY_.y;
|
||||
const top = this.relativeTop_ + this.anchorXY_.y;
|
||||
this.moveTo(left, top);
|
||||
};
|
||||
|
||||
@@ -669,7 +676,7 @@ Blockly.Bubble.prototype.positionBubble_ = function() {
|
||||
* @param {number} y The y position to move to.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Bubble.prototype.moveTo = function(x, y) {
|
||||
Bubble.prototype.moveTo = function(x, y) {
|
||||
this.bubbleGroup_.setAttribute('transform', 'translate(' + x + ',' + y + ')');
|
||||
};
|
||||
|
||||
@@ -678,7 +685,7 @@ Blockly.Bubble.prototype.moveTo = function(x, y) {
|
||||
* @param {boolean} adding True if adding, false if removing.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Bubble.prototype.setDragging = function(adding) {
|
||||
Bubble.prototype.setDragging = function(adding) {
|
||||
if (!adding && this.moveCallback_) {
|
||||
this.moveCallback_();
|
||||
}
|
||||
@@ -686,10 +693,10 @@ Blockly.Bubble.prototype.setDragging = function(adding) {
|
||||
|
||||
/**
|
||||
* Get the dimensions of this bubble.
|
||||
* @return {!Blockly.utils.Size} The height and width of the bubble.
|
||||
* @return {!Size} The height and width of the bubble.
|
||||
*/
|
||||
Blockly.Bubble.prototype.getBubbleSize = function() {
|
||||
return new Blockly.utils.Size(this.width_, this.height_);
|
||||
Bubble.prototype.getBubbleSize = function() {
|
||||
return new Size(this.width_, this.height_);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -697,8 +704,8 @@ Blockly.Bubble.prototype.getBubbleSize = function() {
|
||||
* @param {number} width Width of the bubble.
|
||||
* @param {number} height Height of the bubble.
|
||||
*/
|
||||
Blockly.Bubble.prototype.setBubbleSize = function(width, height) {
|
||||
var doubleBorderWidth = 2 * Blockly.Bubble.BORDER_WIDTH;
|
||||
Bubble.prototype.setBubbleSize = function(width, height) {
|
||||
const doubleBorderWidth = 2 * Bubble.BORDER_WIDTH;
|
||||
// Minimum size of a bubble.
|
||||
width = Math.max(width, doubleBorderWidth + 45);
|
||||
height = Math.max(height, doubleBorderWidth + 20);
|
||||
@@ -709,7 +716,7 @@ Blockly.Bubble.prototype.setBubbleSize = function(width, height) {
|
||||
if (this.resizeGroup_) {
|
||||
if (this.workspace_.RTL) {
|
||||
// Mirror the resize group.
|
||||
var resizeSize = 2 * Blockly.Bubble.BORDER_WIDTH;
|
||||
const resizeSize = 2 * Bubble.BORDER_WIDTH;
|
||||
this.resizeGroup_.setAttribute(
|
||||
'transform',
|
||||
'translate(' + resizeSize + ',' + (height - doubleBorderWidth) +
|
||||
@@ -737,64 +744,62 @@ Blockly.Bubble.prototype.setBubbleSize = function(width, height) {
|
||||
* Draw the arrow between the bubble and the origin.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Bubble.prototype.renderArrow_ = function() {
|
||||
var steps = [];
|
||||
Bubble.prototype.renderArrow_ = function() {
|
||||
const steps = [];
|
||||
// Find the relative coordinates of the center of the bubble.
|
||||
var relBubbleX = this.width_ / 2;
|
||||
var relBubbleY = this.height_ / 2;
|
||||
const relBubbleX = this.width_ / 2;
|
||||
const relBubbleY = this.height_ / 2;
|
||||
// Find the relative coordinates of the center of the anchor.
|
||||
var relAnchorX = -this.relativeLeft_;
|
||||
var relAnchorY = -this.relativeTop_;
|
||||
let relAnchorX = -this.relativeLeft_;
|
||||
let relAnchorY = -this.relativeTop_;
|
||||
if (relBubbleX == relAnchorX && relBubbleY == relAnchorY) {
|
||||
// Null case. Bubble is directly on top of the anchor.
|
||||
// Short circuit this rather than wade through divide by zeros.
|
||||
steps.push('M ' + relBubbleX + ',' + relBubbleY);
|
||||
} else {
|
||||
// Compute the angle of the arrow's line.
|
||||
var rise = relAnchorY - relBubbleY;
|
||||
var run = relAnchorX - relBubbleX;
|
||||
const rise = relAnchorY - relBubbleY;
|
||||
let run = relAnchorX - relBubbleX;
|
||||
if (this.workspace_.RTL) {
|
||||
run *= -1;
|
||||
}
|
||||
var hypotenuse = Math.sqrt(rise * rise + run * run);
|
||||
var angle = Math.acos(run / hypotenuse);
|
||||
const hypotenuse = Math.sqrt(rise * rise + run * run);
|
||||
let angle = Math.acos(run / hypotenuse);
|
||||
if (rise < 0) {
|
||||
angle = 2 * Math.PI - angle;
|
||||
}
|
||||
// Compute a line perpendicular to the arrow.
|
||||
var rightAngle = angle + Math.PI / 2;
|
||||
let rightAngle = angle + Math.PI / 2;
|
||||
if (rightAngle > Math.PI * 2) {
|
||||
rightAngle -= Math.PI * 2;
|
||||
}
|
||||
var rightRise = Math.sin(rightAngle);
|
||||
var rightRun = Math.cos(rightAngle);
|
||||
const rightRise = Math.sin(rightAngle);
|
||||
const rightRun = Math.cos(rightAngle);
|
||||
|
||||
// Calculate the thickness of the base of the arrow.
|
||||
var bubbleSize = this.getBubbleSize();
|
||||
var thickness =
|
||||
(bubbleSize.width + bubbleSize.height) / Blockly.Bubble.ARROW_THICKNESS;
|
||||
const bubbleSize = this.getBubbleSize();
|
||||
let thickness =
|
||||
(bubbleSize.width + bubbleSize.height) / Bubble.ARROW_THICKNESS;
|
||||
thickness = Math.min(thickness, bubbleSize.width, bubbleSize.height) / 4;
|
||||
|
||||
// Back the tip of the arrow off of the anchor.
|
||||
var backoffRatio = 1 - Blockly.Bubble.ANCHOR_RADIUS / hypotenuse;
|
||||
const backoffRatio = 1 - Bubble.ANCHOR_RADIUS / hypotenuse;
|
||||
relAnchorX = relBubbleX + backoffRatio * run;
|
||||
relAnchorY = relBubbleY + backoffRatio * rise;
|
||||
|
||||
// Coordinates for the base of the arrow.
|
||||
var baseX1 = relBubbleX + thickness * rightRun;
|
||||
var baseY1 = relBubbleY + thickness * rightRise;
|
||||
var baseX2 = relBubbleX - thickness * rightRun;
|
||||
var baseY2 = relBubbleY - thickness * rightRise;
|
||||
const baseX1 = relBubbleX + thickness * rightRun;
|
||||
const baseY1 = relBubbleY + thickness * rightRise;
|
||||
const baseX2 = relBubbleX - thickness * rightRun;
|
||||
const baseY2 = relBubbleY - thickness * rightRise;
|
||||
|
||||
// Distortion to curve the arrow.
|
||||
var swirlAngle = angle + this.arrow_radians_;
|
||||
let swirlAngle = angle + this.arrow_radians_;
|
||||
if (swirlAngle > Math.PI * 2) {
|
||||
swirlAngle -= Math.PI * 2;
|
||||
}
|
||||
var swirlRise =
|
||||
Math.sin(swirlAngle) * hypotenuse / Blockly.Bubble.ARROW_BEND;
|
||||
var swirlRun =
|
||||
Math.cos(swirlAngle) * hypotenuse / Blockly.Bubble.ARROW_BEND;
|
||||
const swirlRise = Math.sin(swirlAngle) * hypotenuse / Bubble.ARROW_BEND;
|
||||
const swirlRun = Math.cos(swirlAngle) * hypotenuse / Bubble.ARROW_BEND;
|
||||
|
||||
steps.push('M' + baseX1 + ',' + baseY1);
|
||||
steps.push(
|
||||
@@ -812,7 +817,7 @@ Blockly.Bubble.prototype.renderArrow_ = function() {
|
||||
* Change the colour of a bubble.
|
||||
* @param {string} hexColour Hex code of colour.
|
||||
*/
|
||||
Blockly.Bubble.prototype.setColour = function(hexColour) {
|
||||
Bubble.prototype.setColour = function(hexColour) {
|
||||
this.bubbleBack_.setAttribute('fill', hexColour);
|
||||
this.bubbleArrow_.setAttribute('fill', hexColour);
|
||||
};
|
||||
@@ -820,28 +825,28 @@ Blockly.Bubble.prototype.setColour = function(hexColour) {
|
||||
/**
|
||||
* Dispose of this bubble.
|
||||
*/
|
||||
Blockly.Bubble.prototype.dispose = function() {
|
||||
Bubble.prototype.dispose = function() {
|
||||
if (this.onMouseDownBubbleWrapper_) {
|
||||
Blockly.browserEvents.unbind(this.onMouseDownBubbleWrapper_);
|
||||
browserEvents.unbind(this.onMouseDownBubbleWrapper_);
|
||||
}
|
||||
if (this.onMouseDownResizeWrapper_) {
|
||||
Blockly.browserEvents.unbind(this.onMouseDownResizeWrapper_);
|
||||
browserEvents.unbind(this.onMouseDownResizeWrapper_);
|
||||
}
|
||||
Blockly.Bubble.unbindDragEvents_();
|
||||
Blockly.utils.dom.removeNode(this.bubbleGroup_);
|
||||
Bubble.unbindDragEvents_();
|
||||
dom.removeNode(this.bubbleGroup_);
|
||||
this.disposed = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Bubble.prototype.moveDuringDrag = function(dragSurface, newLoc) {
|
||||
Bubble.prototype.moveDuringDrag = function(dragSurface, newLoc) {
|
||||
if (dragSurface) {
|
||||
dragSurface.translateSurface(newLoc.x, newLoc.y);
|
||||
} else {
|
||||
@@ -859,10 +864,10 @@ Blockly.Bubble.prototype.moveDuringDrag = function(dragSurface, newLoc) {
|
||||
/**
|
||||
* 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.Bubble.prototype.getRelativeToSurfaceXY = function() {
|
||||
return new Blockly.utils.Coordinate(
|
||||
Bubble.prototype.getRelativeToSurfaceXY = function() {
|
||||
return new Coordinate(
|
||||
this.workspace_.RTL ?
|
||||
-this.relativeLeft_ + this.anchorXY_.x - this.width_ :
|
||||
this.anchorXY_.x + this.relativeLeft_,
|
||||
@@ -877,7 +882,7 @@ Blockly.Bubble.prototype.getRelativeToSurfaceXY = function() {
|
||||
* otherwise.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Bubble.prototype.setAutoLayout = function(enable) {
|
||||
Bubble.prototype.setAutoLayout = function(enable) {
|
||||
this.autoLayout_ = enable;
|
||||
};
|
||||
|
||||
@@ -887,19 +892,18 @@ Blockly.Bubble.prototype.setAutoLayout = function(enable) {
|
||||
* @return {!SVGTextElement} The top-level node of the text.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Bubble.textToDom = function(text) {
|
||||
var paragraph = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.TEXT, {
|
||||
Bubble.textToDom = function(text) {
|
||||
const paragraph = dom.createSvgElement(
|
||||
Svg.TEXT, {
|
||||
'class': 'blocklyText blocklyBubbleText blocklyNoPointerEvents',
|
||||
'y': Blockly.Bubble.BORDER_WIDTH
|
||||
'y': Bubble.BORDER_WIDTH
|
||||
},
|
||||
null);
|
||||
var lines = text.split('\n');
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var tspanElement = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.TSPAN,
|
||||
{'dy': '1em', 'x': Blockly.Bubble.BORDER_WIDTH}, paragraph);
|
||||
var textNode = document.createTextNode(lines[i]);
|
||||
const lines = text.split('\n');
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const tspanElement = dom.createSvgElement(
|
||||
Svg.TSPAN, {'dy': '1em', 'x': Bubble.BORDER_WIDTH}, paragraph);
|
||||
const textNode = document.createTextNode(lines[i]);
|
||||
tspanElement.appendChild(textNode);
|
||||
}
|
||||
return paragraph;
|
||||
@@ -909,28 +913,29 @@ Blockly.Bubble.textToDom = function(text) {
|
||||
* Creates a bubble that can not be edited.
|
||||
* @param {!SVGTextElement} paragraphElement The text element for the non
|
||||
* editable bubble.
|
||||
* @param {!Blockly.BlockSvg} block The block that the bubble is attached to.
|
||||
* @param {!Blockly.utils.Coordinate} iconXY The coordinate of the icon.
|
||||
* @return {!Blockly.Bubble} The non editable bubble.
|
||||
* @param {!BlockSvg} block The block that the bubble is attached to.
|
||||
* @param {!Coordinate} iconXY The coordinate of the icon.
|
||||
* @return {!Bubble} The non editable bubble.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Bubble.createNonEditableBubble = function(
|
||||
paragraphElement, block, iconXY) {
|
||||
var bubble = new Blockly.Bubble(
|
||||
/** @type {!Blockly.WorkspaceSvg} */ (block.workspace), paragraphElement,
|
||||
Bubble.createNonEditableBubble = function(paragraphElement, block, iconXY) {
|
||||
const bubble = new Bubble(
|
||||
/** @type {!WorkspaceSvg} */ (block.workspace), paragraphElement,
|
||||
block.pathObject.svgPath,
|
||||
/** @type {!Blockly.utils.Coordinate} */ (iconXY), null, null);
|
||||
/** @type {!Coordinate} */ (iconXY), null, null);
|
||||
// Expose this bubble's block's ID on its top-level SVG group.
|
||||
bubble.setSvgId(block.id);
|
||||
if (block.RTL) {
|
||||
// Right-align the paragraph.
|
||||
// This cannot be done until the bubble is rendered on screen.
|
||||
var maxWidth = paragraphElement.getBBox().width;
|
||||
for (var i = 0, textElement; (textElement = paragraphElement.childNodes[i]);
|
||||
i++) {
|
||||
const maxWidth = paragraphElement.getBBox().width;
|
||||
for (let i = 0, textElement; (textElement = paragraphElement.childNodes[i]);
|
||||
i++) {
|
||||
textElement.setAttribute('text-anchor', 'end');
|
||||
textElement.setAttribute('x', maxWidth + Blockly.Bubble.BORDER_WIDTH);
|
||||
textElement.setAttribute('x', maxWidth + Bubble.BORDER_WIDTH);
|
||||
}
|
||||
}
|
||||
return bubble;
|
||||
};
|
||||
|
||||
exports = Bubble;
|
||||
|
||||
@@ -25,6 +25,8 @@ 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 WorkspaceCommentSvg = goog.requireType('Blockly.WorkspaceCommentSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
/** @suppress {extraRequire} */
|
||||
@@ -236,7 +238,7 @@ BubbleDragger.prototype.fireMoveEvent_ = function() {
|
||||
if (this.draggingBubble_.isComment) {
|
||||
// TODO (adodson): Resolve build errors when requiring WorkspaceCommentSvg.
|
||||
const event = new (Events.get(Events.COMMENT_MOVE))(
|
||||
/** @type {!Blockly.WorkspaceCommentSvg} */ (this.draggingBubble_));
|
||||
/** @type {!WorkspaceCommentSvg} */ (this.draggingBubble_));
|
||||
event.setOldCoordinate(this.startXY_);
|
||||
event.recordNew();
|
||||
Events.fire(event);
|
||||
|
||||
80
core/clipboard.js
Normal file
80
core/clipboard.js
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2021 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Blockly's internal clipboard for managing copy-paste.
|
||||
* @author fenichel@google.com (Rachel Fenichel)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.clipboard');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
const Events = goog.require('Blockly.Events');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const ICopyable = goog.requireType('Blockly.ICopyable');
|
||||
|
||||
/**
|
||||
* Metadata about the object that is currently on the clipboard.
|
||||
* @type {?ICopyable.CopyData}
|
||||
*/
|
||||
let copyData = null;
|
||||
|
||||
/**
|
||||
* Copy a block or workspace comment onto the local clipboard.
|
||||
* @param {!ICopyable} toCopy Block or Workspace Comment to be copied.
|
||||
*/
|
||||
const copy = function(toCopy) {
|
||||
copyData = toCopy.toCopyData();
|
||||
};
|
||||
/** @package */
|
||||
exports.copy = copy;
|
||||
|
||||
/**
|
||||
* Paste a block or workspace comment on to the main workspace.
|
||||
* @return {boolean} True if the paste was successful, false otherwise.
|
||||
*/
|
||||
const paste = function() {
|
||||
if (!copyData.xml) {
|
||||
return false;
|
||||
}
|
||||
// Pasting always pastes to the main workspace, even if the copy
|
||||
// started in a flyout workspace.
|
||||
var workspace = copyData.source;
|
||||
if (workspace.isFlyout) {
|
||||
workspace = workspace.targetWorkspace;
|
||||
}
|
||||
if (copyData.typeCounts &&
|
||||
workspace.isCapacityAvailable(copyData.typeCounts)) {
|
||||
Events.setGroup(true);
|
||||
workspace.paste(copyData.xml);
|
||||
Events.setGroup(false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
/** @package */
|
||||
exports.paste = paste;
|
||||
|
||||
/**
|
||||
* Duplicate this block and its children, or a workspace comment.
|
||||
* @param {!ICopyable} toDuplicate Block or Workspace Comment to be
|
||||
* duplicated.
|
||||
*/
|
||||
const duplicate = function(toDuplicate) {
|
||||
// Save the clipboard.
|
||||
const oldCopyData = copyData;
|
||||
|
||||
// Create a duplicate via a copy/paste operation.
|
||||
copy(toDuplicate);
|
||||
// copy() replaced the value of copyData.
|
||||
toDuplicate.workspace.paste(copyData.xml);
|
||||
|
||||
// Restore the clipboard.
|
||||
copyData = oldCopyData;
|
||||
};
|
||||
/** @package */
|
||||
exports.duplicate = duplicate;
|
||||
@@ -20,6 +20,7 @@ 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 Css = goog.require('Blockly.Css');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const Icon = goog.require('Blockly.Icon');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
@@ -27,12 +28,10 @@ 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 browserEvents = goog.require('Blockly.browserEvents');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
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} */
|
||||
@@ -70,35 +69,35 @@ const Comment = function(block) {
|
||||
|
||||
/**
|
||||
* Mouse up event data.
|
||||
* @type {?Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.onMouseUpWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Wheel event data.
|
||||
* @type {?Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.onWheelWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Change event data.
|
||||
* @type {?Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.onChangeWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Input event data.
|
||||
* @type {?Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.onInputWrapper_ = null;
|
||||
|
||||
this.createIcon();
|
||||
};
|
||||
inherits(Comment, Icon);
|
||||
object.inherits(Comment, Icon);
|
||||
|
||||
/**
|
||||
* Draw the comment icon.
|
||||
@@ -107,13 +106,13 @@ inherits(Comment, Icon);
|
||||
*/
|
||||
Comment.prototype.drawIcon_ = function(group) {
|
||||
// Circle.
|
||||
createSvgElement(
|
||||
dom.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.
|
||||
createSvgElement(
|
||||
dom.createSvgElement(
|
||||
Svg.PATH, {
|
||||
'class': 'blocklyIconSymbol',
|
||||
'd': 'm6.8,10h2c0.003,-0.617 0.271,-0.962 0.633,-1.266 2.875,-2.405' +
|
||||
@@ -122,7 +121,7 @@ Comment.prototype.drawIcon_ = function(group) {
|
||||
},
|
||||
group);
|
||||
// Dot of question mark.
|
||||
createSvgElement(
|
||||
dom.createSvgElement(
|
||||
Svg.RECT, {
|
||||
'class': 'blocklyIconSymbol',
|
||||
'x': '6.8',
|
||||
@@ -151,15 +150,15 @@ Comment.prototype.createEditor_ = function() {
|
||||
* For non-editable mode see Warning.textToDom_.
|
||||
*/
|
||||
|
||||
this.foreignObject_ = createSvgElement(
|
||||
this.foreignObject_ = dom.createSvgElement(
|
||||
Svg.FOREIGNOBJECT, {'x': Bubble.BORDER_WIDTH, 'y': Bubble.BORDER_WIDTH},
|
||||
null);
|
||||
|
||||
const body = document.createElementNS(HTML_NS, 'body');
|
||||
body.setAttribute('xmlns', HTML_NS);
|
||||
const body = document.createElementNS(dom.HTML_NS, 'body');
|
||||
body.setAttribute('xmlns', dom.HTML_NS);
|
||||
body.className = 'blocklyMinimalBody';
|
||||
|
||||
this.textarea_ = document.createElementNS(HTML_NS, 'textarea');
|
||||
this.textarea_ = document.createElementNS(dom.HTML_NS, 'textarea');
|
||||
const textarea = this.textarea_;
|
||||
textarea.className = 'blocklyCommentTextarea';
|
||||
textarea.setAttribute('dir', this.block_.RTL ? 'RTL' : 'LTR');
|
||||
@@ -172,23 +171,25 @@ 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_ =
|
||||
conditionalBind(textarea, 'mouseup', this, this.startEdit_, true, true);
|
||||
this.onMouseUpWrapper_ = browserEvents.conditionalBind(
|
||||
textarea, 'mouseup', this, this.startEdit_, true, true);
|
||||
// Don't zoom with mousewheel.
|
||||
this.onWheelWrapper_ = conditionalBind(textarea, 'wheel', this, function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
this.onWheelWrapper_ =
|
||||
browserEvents.conditionalBind(textarea, 'wheel', this, function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
this.onChangeWrapper_ =
|
||||
conditionalBind(textarea, 'change', this, function(_e) {
|
||||
browserEvents.conditionalBind(textarea, 'change', this, function(_e) {
|
||||
if (this.cachedText_ != this.model_.text) {
|
||||
Events.fire(new (Events.get(Events.BLOCK_CHANGE))(
|
||||
this.block_, 'comment', null, this.cachedText_,
|
||||
this.model_.text));
|
||||
}
|
||||
});
|
||||
this.onInputWrapper_ = conditionalBind(textarea, 'input', this, function(_e) {
|
||||
this.model_.text = textarea.value;
|
||||
});
|
||||
this.onInputWrapper_ =
|
||||
browserEvents.conditionalBind(textarea, 'input', this, function(_e) {
|
||||
this.model_.text = textarea.value;
|
||||
});
|
||||
|
||||
setTimeout(textarea.focus.bind(textarea), 0);
|
||||
|
||||
@@ -307,19 +308,19 @@ Comment.prototype.createNonEditableBubble_ = function() {
|
||||
*/
|
||||
Comment.prototype.disposeBubble_ = function() {
|
||||
if (this.onMouseUpWrapper_) {
|
||||
unbind(this.onMouseUpWrapper_);
|
||||
browserEvents.unbind(this.onMouseUpWrapper_);
|
||||
this.onMouseUpWrapper_ = null;
|
||||
}
|
||||
if (this.onWheelWrapper_) {
|
||||
unbind(this.onWheelWrapper_);
|
||||
browserEvents.unbind(this.onWheelWrapper_);
|
||||
this.onWheelWrapper_ = null;
|
||||
}
|
||||
if (this.onChangeWrapper_) {
|
||||
unbind(this.onChangeWrapper_);
|
||||
browserEvents.unbind(this.onChangeWrapper_);
|
||||
this.onChangeWrapper_ = null;
|
||||
}
|
||||
if (this.onInputWrapper_) {
|
||||
unbind(this.onInputWrapper_);
|
||||
browserEvents.unbind(this.onInputWrapper_);
|
||||
this.onInputWrapper_ = null;
|
||||
}
|
||||
this.bubble_.dispose();
|
||||
@@ -397,7 +398,7 @@ Comment.prototype.dispose = function() {
|
||||
/**
|
||||
* CSS for block comment. See css.js for use.
|
||||
*/
|
||||
register([
|
||||
Css.register([
|
||||
/* eslint-disable indent */
|
||||
'.blocklyCommentTextarea {', 'background-color: #fef49c;', 'border: 0;',
|
||||
'outline: 0;', 'margin: 0;', 'padding: 3px;', 'resize: none;',
|
||||
|
||||
82
core/common.js
Normal file
82
core/common.js
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2021 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Common functions used both internally and externally, but which
|
||||
* must not be at the top level to avoid circular dependencies.
|
||||
* @author fenichel@google.com (Rachel Fenichel)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.common');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Connection = goog.requireType('Blockly.Connection');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Workspace = goog.requireType('Blockly.Workspace');
|
||||
|
||||
|
||||
/**
|
||||
* The main workspace most recently used.
|
||||
* Set by Blockly.WorkspaceSvg.prototype.markFocused
|
||||
* @type {!Workspace}
|
||||
*/
|
||||
let mainWorkspace;
|
||||
|
||||
/**
|
||||
* Returns the last used top level workspace (based on focus). Try not to use
|
||||
* this function, particularly if there are multiple Blockly instances on a
|
||||
* page.
|
||||
* @return {!Workspace} The main workspace.
|
||||
*/
|
||||
const getMainWorkspace = function() {
|
||||
return mainWorkspace;
|
||||
};
|
||||
exports.getMainWorkspace = getMainWorkspace;
|
||||
|
||||
/**
|
||||
* Sets last used main workspace.
|
||||
* @param {!Workspace} workspace The most recently used top level workspace.
|
||||
*/
|
||||
const setMainWorkspace = function(workspace) {
|
||||
mainWorkspace = workspace;
|
||||
};
|
||||
exports.setMainWorkspace = setMainWorkspace;
|
||||
|
||||
/**
|
||||
* Container element in which to render the WidgetDiv, DropDownDiv and Tooltip.
|
||||
* @type {?Element}
|
||||
*/
|
||||
let parentContainer;
|
||||
|
||||
/**
|
||||
* Get the container element in which to render the WidgetDiv, DropDownDiv and\
|
||||
* Tooltip.
|
||||
* @return {?Element} The parent container.
|
||||
*/
|
||||
const getParentContainer = function() {
|
||||
return parentContainer;
|
||||
};
|
||||
exports.getParentContainer = getParentContainer;
|
||||
|
||||
/**
|
||||
* Set the parent container. This is the container element that the WidgetDiv,
|
||||
* DropDownDiv, and Tooltip are rendered into the first time `Blockly.inject`
|
||||
* is called.
|
||||
* This method is a NOP if called after the first ``Blockly.inject``.
|
||||
* @param {!Element} newParent The container element.
|
||||
*/
|
||||
const setParentContainer = function(newParent) {
|
||||
parentContainer = newParent;
|
||||
};
|
||||
exports.setParentContainer = setParentContainer;
|
||||
|
||||
/**
|
||||
* All of the connections on blocks that are currently being dragged.
|
||||
* @type {!Array<!Connection>}
|
||||
*/
|
||||
exports.draggingConnections = [];
|
||||
@@ -17,7 +17,7 @@ goog.module.declareLegacyNamespace();
|
||||
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');
|
||||
const IASTNodeLocationWithBlock = goog.requireType('Blockly.IASTNodeLocationWithBlock');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IConnectionChecker = goog.requireType('Blockly.IConnectionChecker');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
|
||||
@@ -16,12 +16,13 @@ goog.module.declareLegacyNamespace();
|
||||
|
||||
const Connection = goog.require('Blockly.Connection');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IConnectionChecker = goog.require('Blockly.IConnectionChecker');
|
||||
const IConnectionChecker = goog.requireType('Blockly.IConnectionChecker');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const RenderedConnection = goog.requireType('Blockly.RenderedConnection');
|
||||
const common = goog.require('Blockly.common');
|
||||
const connectionTypes = goog.require('Blockly.connectionTypes');
|
||||
const internalConstants = goog.require('Blockly.internalConstants');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
const {OPPOSITE_TYPE} = goog.require('Blockly.internalConstants');
|
||||
|
||||
|
||||
/**
|
||||
@@ -145,7 +146,7 @@ ConnectionChecker.prototype.doSafetyChecks = function(a, b) {
|
||||
}
|
||||
if (blockA == blockB) {
|
||||
return Connection.REASON_SELF_CONNECTION;
|
||||
} else if (b.type != OPPOSITE_TYPE[a.type]) {
|
||||
} else if (b.type != internalConstants.OPPOSITE_TYPE[a.type]) {
|
||||
return Connection.REASON_WRONG_TYPE;
|
||||
} else if (blockA.workspace !== blockB.workspace) {
|
||||
return Connection.REASON_DIFFERENT_WORKSPACES;
|
||||
@@ -239,7 +240,7 @@ ConnectionChecker.prototype.doDragChecks = function(a, b, distance) {
|
||||
}
|
||||
|
||||
// Don't let blocks try to connect to themselves or ones they nest.
|
||||
if (Blockly.draggingConnections.indexOf(b) != -1) {
|
||||
if (common.draggingConnections.indexOf(b) != -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -263,7 +264,7 @@ ConnectionChecker.prototype.canConnectToPrevious_ = function(a, b) {
|
||||
}
|
||||
|
||||
// Don't let blocks try to connect to themselves or ones they nest.
|
||||
if (Blockly.draggingConnections.indexOf(b) != -1) {
|
||||
if (common.draggingConnections.indexOf(b) != -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ 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 RenderedConnection = goog.requireType('Blockly.RenderedConnection');
|
||||
const connectionTypes = goog.require('Blockly.connectionTypes');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
|
||||
@@ -10,45 +10,70 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @name Blockly.ContextMenu
|
||||
* @namespace
|
||||
*/
|
||||
goog.provide('Blockly.ContextMenu');
|
||||
goog.module('Blockly.ContextMenu');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.browserEvents');
|
||||
goog.require('Blockly.Events');
|
||||
// TODO(#5073): Add Blockly require after fixing circular dependency.
|
||||
// goog.require('Blockly');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const Menu = goog.require('Blockly.Menu');
|
||||
const MenuItem = goog.require('Blockly.MenuItem');
|
||||
const Msg = goog.require('Blockly.Msg');
|
||||
const Rect = goog.require('Blockly.utils.Rect');
|
||||
const WidgetDiv = goog.require('Blockly.WidgetDiv');
|
||||
const Xml = goog.require('Blockly.Xml');
|
||||
const aria = goog.require('Blockly.utils.aria');
|
||||
const browserEvents = goog.require('Blockly.browserEvents');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const internalConstants = goog.require('Blockly.internalConstants');
|
||||
const userAgent = goog.require('Blockly.utils.userAgent');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceCommentSvg = goog.requireType('Blockly.WorkspaceCommentSvg');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockCreate');
|
||||
goog.require('Blockly.internalConstants');
|
||||
goog.require('Blockly.Menu');
|
||||
goog.require('Blockly.MenuItem');
|
||||
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.Rect');
|
||||
goog.require('Blockly.utils.userAgent');
|
||||
goog.require('Blockly.WidgetDiv');
|
||||
goog.require('Blockly.Xml');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
|
||||
|
||||
/**
|
||||
* Which block is the context menu attached to?
|
||||
* @type {Blockly.Block}
|
||||
* @type {?Block}
|
||||
*/
|
||||
Blockly.ContextMenu.currentBlock = null;
|
||||
let currentBlock = null;
|
||||
|
||||
/**
|
||||
* Gets the block the context menu is currently attached to.
|
||||
* @return {?Block} The block the context menu is attached to.
|
||||
*/
|
||||
const getCurrentBlock = function() {
|
||||
return currentBlock;
|
||||
};
|
||||
exports.getCurrentBlock = getCurrentBlock;
|
||||
|
||||
/**
|
||||
* Sets the block the context menu is currently attached to.
|
||||
* @param {?Block} block The block the context menu is attached to.
|
||||
*/
|
||||
const setCurrentBlock = function(block) {
|
||||
currentBlock = block;
|
||||
};
|
||||
exports.setCurrentBlock = setCurrentBlock;
|
||||
|
||||
// Ad JS accessors for backwards compatibility.
|
||||
Object.defineProperty(exports, 'currentBlock', {
|
||||
get: getCurrentBlock,
|
||||
set: setCurrentBlock,
|
||||
});
|
||||
|
||||
/**
|
||||
* Menu object.
|
||||
* @type {Blockly.Menu}
|
||||
* @private
|
||||
* @type {Menu}
|
||||
*/
|
||||
Blockly.ContextMenu.menu_ = null;
|
||||
let menu_ = null;
|
||||
|
||||
/**
|
||||
* Construct the menu based on the list of options and show the menu.
|
||||
@@ -56,47 +81,51 @@ Blockly.ContextMenu.menu_ = null;
|
||||
* @param {!Array<!Object>} options Array of menu options.
|
||||
* @param {boolean} rtl True if RTL, false if LTR.
|
||||
*/
|
||||
Blockly.ContextMenu.show = function(e, options, rtl) {
|
||||
Blockly.WidgetDiv.show(Blockly.ContextMenu, rtl, Blockly.ContextMenu.dispose);
|
||||
const show = function(e, options, rtl) {
|
||||
WidgetDiv.show(exports, rtl, dispose);
|
||||
if (!options.length) {
|
||||
Blockly.ContextMenu.hide();
|
||||
hide();
|
||||
return;
|
||||
}
|
||||
var menu = Blockly.ContextMenu.populate_(options, rtl);
|
||||
Blockly.ContextMenu.menu_ = menu;
|
||||
const menu = populate_(options, rtl);
|
||||
menu_ = menu;
|
||||
|
||||
Blockly.ContextMenu.position_(menu, e, rtl);
|
||||
position_(menu, e, rtl);
|
||||
// 1ms delay is required for focusing on context menus because some other
|
||||
// mouse event is still waiting in the queue and clears focus.
|
||||
setTimeout(function() {menu.focus();}, 1);
|
||||
Blockly.ContextMenu.currentBlock = null; // May be set by Blockly.Block.
|
||||
setTimeout(function() {
|
||||
menu.focus();
|
||||
}, 1);
|
||||
currentBlock = null; // May be set by Blockly.Block.
|
||||
};
|
||||
exports.show = show;
|
||||
|
||||
/**
|
||||
* Create the context menu object and populate it with the given options.
|
||||
* @param {!Array<!Object>} options Array of menu options.
|
||||
* @param {boolean} rtl True if RTL, false if LTR.
|
||||
* @return {!Blockly.Menu} The menu that will be shown on right click.
|
||||
* @return {!Menu} The menu that will be shown on right click.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ContextMenu.populate_ = function(options, rtl) {
|
||||
const populate_ = function(options, rtl) {
|
||||
/* Here's what one option object looks like:
|
||||
{text: 'Make It So',
|
||||
enabled: true,
|
||||
callback: Blockly.MakeItSo}
|
||||
*/
|
||||
var menu = new Blockly.Menu();
|
||||
menu.setRole(Blockly.utils.aria.Role.MENU);
|
||||
for (var i = 0, option; (option = options[i]); i++) {
|
||||
var menuItem = new Blockly.MenuItem(option.text);
|
||||
const menu = new Menu();
|
||||
menu.setRole(aria.Role.MENU);
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
const option = options[i];
|
||||
const menuItem = new MenuItem(option.text);
|
||||
menuItem.setRightToLeft(rtl);
|
||||
menuItem.setRole(Blockly.utils.aria.Role.MENUITEM);
|
||||
menuItem.setRole(aria.Role.MENUITEM);
|
||||
menu.addChild(menuItem);
|
||||
menuItem.setEnabled(option.enabled);
|
||||
if (option.enabled) {
|
||||
var actionHandler = function(_menuItem) {
|
||||
var option = this;
|
||||
Blockly.ContextMenu.hide();
|
||||
const actionHandler = function(_menuItem) {
|
||||
const option = this;
|
||||
hide();
|
||||
option.callback(option.scope);
|
||||
};
|
||||
menuItem.onAction(actionHandler, option);
|
||||
@@ -107,26 +136,23 @@ Blockly.ContextMenu.populate_ = function(options, rtl) {
|
||||
|
||||
/**
|
||||
* Add the menu to the page and position it correctly.
|
||||
* @param {!Blockly.Menu} menu The menu to add and position.
|
||||
* @param {!Menu} menu The menu to add and position.
|
||||
* @param {!Event} e Mouse event for the right click that is making the context
|
||||
* menu appear.
|
||||
* @param {boolean} rtl True if RTL, false if LTR.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ContextMenu.position_ = function(menu, e, rtl) {
|
||||
const position_ = function(menu, e, rtl) {
|
||||
// Record windowSize and scrollOffset before adding menu.
|
||||
var viewportBBox = Blockly.utils.getViewportBBox();
|
||||
const viewportBBox = utils.getViewportBBox();
|
||||
// This one is just a point, but we'll pretend that it's a rect so we can use
|
||||
// some helper functions.
|
||||
var anchorBBox = new Blockly.utils.Rect(
|
||||
e.clientY + viewportBBox.top,
|
||||
e.clientY + viewportBBox.top,
|
||||
e.clientX + viewportBBox.left,
|
||||
e.clientX + viewportBBox.left
|
||||
);
|
||||
const anchorBBox = new Rect(
|
||||
e.clientY + viewportBBox.top, e.clientY + viewportBBox.top,
|
||||
e.clientX + viewportBBox.left, e.clientX + viewportBBox.left);
|
||||
|
||||
Blockly.ContextMenu.createWidget_(menu);
|
||||
var menuSize = menu.getSize();
|
||||
createWidget_(menu);
|
||||
const menuSize = menu.getSize();
|
||||
|
||||
if (rtl) {
|
||||
anchorBBox.left += menuSize.width;
|
||||
@@ -135,7 +161,7 @@ Blockly.ContextMenu.position_ = function(menu, e, rtl) {
|
||||
viewportBBox.right += menuSize.width;
|
||||
}
|
||||
|
||||
Blockly.WidgetDiv.positionWithAnchor(viewportBBox, anchorBBox, menuSize, rtl);
|
||||
WidgetDiv.positionWithAnchor(viewportBBox, anchorBBox, menuSize, rtl);
|
||||
// Calling menuDom.focus() has to wait until after the menu has been placed
|
||||
// correctly. Otherwise it will cause a page scroll to get the misplaced menu
|
||||
// in view. See issue #1329.
|
||||
@@ -144,19 +170,19 @@ Blockly.ContextMenu.position_ = function(menu, e, rtl) {
|
||||
|
||||
/**
|
||||
* Create and render the menu widget inside Blockly's widget div.
|
||||
* @param {!Blockly.Menu} menu The menu to add to the widget div.
|
||||
* @param {!Menu} menu The menu to add to the widget div.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ContextMenu.createWidget_ = function(menu) {
|
||||
var div = Blockly.WidgetDiv.DIV;
|
||||
const createWidget_ = function(menu) {
|
||||
const div = WidgetDiv.DIV;
|
||||
menu.render(div);
|
||||
var menuDom = menu.getElement();
|
||||
Blockly.utils.dom.addClass(
|
||||
const menuDom = menu.getElement();
|
||||
dom.addClass(
|
||||
/** @type {!Element} */ (menuDom), 'blocklyContextMenu');
|
||||
// Prevent system context menu when right-clicking a Blockly context menu.
|
||||
Blockly.browserEvents.conditionalBind(
|
||||
browserEvents.conditionalBind(
|
||||
/** @type {!EventTarget} */ (menuDom), 'contextmenu', null,
|
||||
Blockly.utils.noEvent);
|
||||
utils.noEvent);
|
||||
// Focus only after the initial render to avoid issue #1329.
|
||||
menu.focus();
|
||||
};
|
||||
@@ -164,85 +190,88 @@ Blockly.ContextMenu.createWidget_ = function(menu) {
|
||||
/**
|
||||
* Hide the context menu.
|
||||
*/
|
||||
Blockly.ContextMenu.hide = function() {
|
||||
Blockly.WidgetDiv.hideIfOwner(Blockly.ContextMenu);
|
||||
Blockly.ContextMenu.currentBlock = null;
|
||||
const hide = function() {
|
||||
WidgetDiv.hideIfOwner(exports);
|
||||
currentBlock = null;
|
||||
};
|
||||
exports.hide = hide;
|
||||
|
||||
/**
|
||||
* Dispose of the menu.
|
||||
*/
|
||||
Blockly.ContextMenu.dispose = function() {
|
||||
if (Blockly.ContextMenu.menu_) {
|
||||
Blockly.ContextMenu.menu_.dispose();
|
||||
Blockly.ContextMenu.menu_ = null;
|
||||
const dispose = function() {
|
||||
if (menu_) {
|
||||
menu_.dispose();
|
||||
menu_ = null;
|
||||
}
|
||||
};
|
||||
exports.dispose = dispose;
|
||||
|
||||
/**
|
||||
* Create a callback function that creates and configures a block,
|
||||
* then places the new block next to the original.
|
||||
* @param {!Blockly.Block} block Original block.
|
||||
* @param {!Block} block Original block.
|
||||
* @param {!Element} xml XML representation of new block.
|
||||
* @return {!Function} Function that creates a block.
|
||||
*/
|
||||
Blockly.ContextMenu.callbackFactory = function(block, xml) {
|
||||
const callbackFactory = function(block, xml) {
|
||||
return function() {
|
||||
Blockly.Events.disable();
|
||||
Events.disable();
|
||||
let newBlock;
|
||||
try {
|
||||
var newBlock = Blockly.Xml.domToBlock(xml, block.workspace);
|
||||
newBlock = Xml.domToBlock(xml, block.workspace);
|
||||
// Move the new block next to the old block.
|
||||
var xy = block.getRelativeToSurfaceXY();
|
||||
const xy = block.getRelativeToSurfaceXY();
|
||||
if (block.RTL) {
|
||||
xy.x -= Blockly.internalConstants.SNAP_RADIUS;
|
||||
xy.x -= internalConstants.SNAP_RADIUS;
|
||||
} else {
|
||||
xy.x += Blockly.internalConstants.SNAP_RADIUS;
|
||||
xy.x += internalConstants.SNAP_RADIUS;
|
||||
}
|
||||
xy.y += Blockly.internalConstants.SNAP_RADIUS * 2;
|
||||
xy.y += internalConstants.SNAP_RADIUS * 2;
|
||||
newBlock.moveBy(xy.x, xy.y);
|
||||
} finally {
|
||||
Blockly.Events.enable();
|
||||
Events.enable();
|
||||
}
|
||||
if (Blockly.Events.isEnabled() && !newBlock.isShadow()) {
|
||||
Blockly.Events.fire(
|
||||
new (Blockly.Events.get(Blockly.Events.BLOCK_CREATE))(newBlock));
|
||||
if (Events.isEnabled() && !newBlock.isShadow()) {
|
||||
Events.fire(new (Events.get(Events.BLOCK_CREATE))(newBlock));
|
||||
}
|
||||
newBlock.select();
|
||||
};
|
||||
};
|
||||
exports.callbackFactory = callbackFactory;
|
||||
|
||||
// Helper functions for creating context menu options.
|
||||
|
||||
/**
|
||||
* Make a context menu option for deleting the current workspace comment.
|
||||
* @param {!Blockly.WorkspaceCommentSvg} comment The workspace comment where the
|
||||
* @param {!WorkspaceCommentSvg} comment The workspace comment where the
|
||||
* right-click originated.
|
||||
* @return {!Object} A menu option, containing text, enabled, and a callback.
|
||||
* @package
|
||||
*/
|
||||
Blockly.ContextMenu.commentDeleteOption = function(comment) {
|
||||
var deleteOption = {
|
||||
text: Blockly.Msg['REMOVE_COMMENT'],
|
||||
const commentDeleteOption = function(comment) {
|
||||
const deleteOption = {
|
||||
text: Msg['REMOVE_COMMENT'],
|
||||
enabled: true,
|
||||
callback: function() {
|
||||
Blockly.Events.setGroup(true);
|
||||
comment.dispose(true, true);
|
||||
Blockly.Events.setGroup(false);
|
||||
Events.setGroup(true);
|
||||
comment.dispose();
|
||||
Events.setGroup(false);
|
||||
}
|
||||
};
|
||||
return deleteOption;
|
||||
};
|
||||
/** @package */
|
||||
exports.commentDeleteOption = commentDeleteOption;
|
||||
|
||||
/**
|
||||
* Make a context menu option for duplicating the current workspace comment.
|
||||
* @param {!Blockly.WorkspaceCommentSvg} comment The workspace comment where the
|
||||
* @param {!WorkspaceCommentSvg} comment The workspace comment where the
|
||||
* right-click originated.
|
||||
* @return {!Object} A menu option, containing text, enabled, and a callback.
|
||||
* @package
|
||||
*/
|
||||
Blockly.ContextMenu.commentDuplicateOption = function(comment) {
|
||||
var duplicateOption = {
|
||||
text: Blockly.Msg['DUPLICATE_COMMENT'],
|
||||
const commentDuplicateOption = function(comment) {
|
||||
const duplicateOption = {
|
||||
text: Msg['DUPLICATE_COMMENT'],
|
||||
enabled: true,
|
||||
callback: function() {
|
||||
Blockly.duplicate(comment);
|
||||
@@ -250,10 +279,12 @@ Blockly.ContextMenu.commentDuplicateOption = function(comment) {
|
||||
};
|
||||
return duplicateOption;
|
||||
};
|
||||
/** @package */
|
||||
exports.commentDuplicateOption = commentDuplicateOption;
|
||||
|
||||
/**
|
||||
* Make a context menu option for adding a comment on the workspace.
|
||||
* @param {!Blockly.WorkspaceSvg} ws The workspace where the right-click
|
||||
* @param {!WorkspaceSvg} ws The workspace where the right-click
|
||||
* originated.
|
||||
* @param {!Event} e The right-click mouse event.
|
||||
* @return {!Object} A menu option, containing text, enabled, and a callback.
|
||||
@@ -261,41 +292,42 @@ Blockly.ContextMenu.commentDuplicateOption = function(comment) {
|
||||
* @suppress {strictModuleDepCheck,checkTypes} Suppress checks while workspace
|
||||
* comments are not bundled in.
|
||||
*/
|
||||
Blockly.ContextMenu.workspaceCommentOption = function(ws, e) {
|
||||
if (!Blockly.WorkspaceCommentSvg) {
|
||||
const workspaceCommentOption = function(ws, e) {
|
||||
const WorkspaceCommentSvg = goog.module.get('Blockly.WorkspaceCommentSvg');
|
||||
if (!WorkspaceCommentSvg) {
|
||||
throw Error('Missing require for Blockly.WorkspaceCommentSvg');
|
||||
}
|
||||
// Helper function to create and position a comment correctly based on the
|
||||
// location of the mouse event.
|
||||
var addWsComment = function() {
|
||||
var comment = new Blockly.WorkspaceCommentSvg(
|
||||
ws, Blockly.Msg['WORKSPACE_COMMENT_DEFAULT_TEXT'],
|
||||
Blockly.WorkspaceCommentSvg.DEFAULT_SIZE,
|
||||
Blockly.WorkspaceCommentSvg.DEFAULT_SIZE);
|
||||
const addWsComment = function() {
|
||||
const comment = new WorkspaceCommentSvg(
|
||||
ws, Msg['WORKSPACE_COMMENT_DEFAULT_TEXT'],
|
||||
WorkspaceCommentSvg.DEFAULT_SIZE,
|
||||
WorkspaceCommentSvg.DEFAULT_SIZE);
|
||||
|
||||
var injectionDiv = ws.getInjectionDiv();
|
||||
const injectionDiv = ws.getInjectionDiv();
|
||||
// Bounding rect coordinates are in client coordinates, meaning that they
|
||||
// are in pixels relative to the upper left corner of the visible browser
|
||||
// window. These coordinates change when you scroll the browser window.
|
||||
var boundingRect = injectionDiv.getBoundingClientRect();
|
||||
const boundingRect = injectionDiv.getBoundingClientRect();
|
||||
|
||||
// The client coordinates offset by the injection div's upper left corner.
|
||||
var clientOffsetPixels = new Blockly.utils.Coordinate(
|
||||
const clientOffsetPixels = new Coordinate(
|
||||
e.clientX - boundingRect.left, e.clientY - boundingRect.top);
|
||||
|
||||
// The offset in pixels between the main workspace's origin and the upper
|
||||
// left corner of the injection div.
|
||||
var mainOffsetPixels = ws.getOriginOffsetInPixels();
|
||||
const mainOffsetPixels = ws.getOriginOffsetInPixels();
|
||||
|
||||
// The position of the new comment in pixels relative to the origin of the
|
||||
// main workspace.
|
||||
var finalOffset = Blockly.utils.Coordinate.difference(clientOffsetPixels,
|
||||
mainOffsetPixels);
|
||||
const finalOffset =
|
||||
Coordinate.difference(clientOffsetPixels, mainOffsetPixels);
|
||||
// The position of the new comment in main workspace coordinates.
|
||||
finalOffset.scale(1 / ws.scale);
|
||||
|
||||
var commentX = finalOffset.x;
|
||||
var commentY = finalOffset.y;
|
||||
const commentX = finalOffset.x;
|
||||
const commentY = finalOffset.y;
|
||||
comment.moveBy(commentX, commentY);
|
||||
if (ws.rendered) {
|
||||
comment.initSvg();
|
||||
@@ -304,14 +336,16 @@ Blockly.ContextMenu.workspaceCommentOption = function(ws, e) {
|
||||
}
|
||||
};
|
||||
|
||||
var wsCommentOption = {
|
||||
const wsCommentOption = {
|
||||
// Foreign objects don't work in IE. Don't let the user create comments
|
||||
// that they won't be able to edit.
|
||||
enabled: !Blockly.utils.userAgent.IE
|
||||
enabled: !userAgent.IE
|
||||
};
|
||||
wsCommentOption.text = Blockly.Msg['ADD_COMMENT'];
|
||||
wsCommentOption.text = Msg['ADD_COMMENT'];
|
||||
wsCommentOption.callback = function() {
|
||||
addWsComment();
|
||||
};
|
||||
return wsCommentOption;
|
||||
};
|
||||
/** @package */
|
||||
exports.workspaceCommentOption = workspaceCommentOption;
|
||||
|
||||
@@ -10,73 +10,84 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @name Blockly.ContextMenuItems
|
||||
* @namespace
|
||||
*/
|
||||
goog.provide('Blockly.ContextMenuItems');
|
||||
goog.module('Blockly.ContextMenuItems');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.ContextMenuRegistry');
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.inputTypes');
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
const Blockly = goog.require('Blockly');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
const ContextMenuRegistry = goog.require('Blockly.ContextMenuRegistry');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const Msg = goog.require('Blockly.Msg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const clipboard = goog.require('Blockly.clipboard');
|
||||
const inputTypes = goog.require('Blockly.inputTypes');
|
||||
const userAgent = goog.require('Blockly.utils.userAgent');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/** Option to undo previous action. */
|
||||
Blockly.ContextMenuItems.registerUndo = function() {
|
||||
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
|
||||
var undoOption = {
|
||||
const registerUndo = function() {
|
||||
/** @type {!ContextMenuRegistry.RegistryItem} */
|
||||
const undoOption = {
|
||||
displayText: function() {
|
||||
return Blockly.Msg['UNDO'];
|
||||
return Msg['UNDO'];
|
||||
},
|
||||
preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
if (scope.workspace.getUndoStack().length > 0) {
|
||||
return 'enabled';
|
||||
}
|
||||
return 'disabled';
|
||||
},
|
||||
callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
callback: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
scope.workspace.undo(false);
|
||||
},
|
||||
scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE,
|
||||
scopeType: ContextMenuRegistry.ScopeType.WORKSPACE,
|
||||
id: 'undoWorkspace',
|
||||
weight: 1,
|
||||
};
|
||||
Blockly.ContextMenuRegistry.registry.register(undoOption);
|
||||
ContextMenuRegistry.registry.register(undoOption);
|
||||
};
|
||||
exports.registerUndo = registerUndo;
|
||||
|
||||
/** Option to redo previous action. */
|
||||
Blockly.ContextMenuItems.registerRedo = function() {
|
||||
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
|
||||
var redoOption = {
|
||||
displayText: function() { return Blockly.Msg['REDO']; },
|
||||
preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
const registerRedo = function() {
|
||||
/** @type {!ContextMenuRegistry.RegistryItem} */
|
||||
const redoOption = {
|
||||
displayText: function() {
|
||||
return Msg['REDO'];
|
||||
},
|
||||
preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
if (scope.workspace.getRedoStack().length > 0) {
|
||||
return 'enabled';
|
||||
}
|
||||
return 'disabled';
|
||||
},
|
||||
callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
callback: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
scope.workspace.undo(true);
|
||||
},
|
||||
scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE,
|
||||
scopeType: ContextMenuRegistry.ScopeType.WORKSPACE,
|
||||
id: 'redoWorkspace',
|
||||
weight: 2,
|
||||
};
|
||||
Blockly.ContextMenuRegistry.registry.register(redoOption);
|
||||
ContextMenuRegistry.registry.register(redoOption);
|
||||
};
|
||||
exports.registerRedo = registerRedo;
|
||||
|
||||
/** Option to clean up blocks. */
|
||||
Blockly.ContextMenuItems.registerCleanup = function() {
|
||||
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
|
||||
var cleanOption = {
|
||||
const registerCleanup = function() {
|
||||
/** @type {!ContextMenuRegistry.RegistryItem} */
|
||||
const cleanOption = {
|
||||
displayText: function() {
|
||||
return Blockly.Msg['CLEAN_UP'];
|
||||
return Msg['CLEAN_UP'];
|
||||
},
|
||||
preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
if (scope.workspace.isMovable()) {
|
||||
if (scope.workspace.getTopBlocks(false).length > 1) {
|
||||
return 'enabled';
|
||||
@@ -85,27 +96,29 @@ Blockly.ContextMenuItems.registerCleanup = function() {
|
||||
}
|
||||
return 'hidden';
|
||||
},
|
||||
callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
callback: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
scope.workspace.cleanUp();
|
||||
},
|
||||
scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE,
|
||||
scopeType: ContextMenuRegistry.ScopeType.WORKSPACE,
|
||||
id: 'cleanWorkspace',
|
||||
weight: 3,
|
||||
};
|
||||
Blockly.ContextMenuRegistry.registry.register(cleanOption);
|
||||
ContextMenuRegistry.registry.register(cleanOption);
|
||||
};
|
||||
exports.registerCleanup = registerCleanup;
|
||||
|
||||
/**
|
||||
* Creates a callback to collapse or expand top blocks.
|
||||
* @param {boolean} shouldCollapse Whether a block should collapse.
|
||||
* @param {!Array<Blockly.BlockSvg>} topBlocks Top blocks in the workspace.
|
||||
* @param {!Array<BlockSvg>} topBlocks Top blocks in the workspace.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ContextMenuItems.toggleOption_ = function(shouldCollapse, topBlocks) {
|
||||
var DELAY = 10;
|
||||
var ms = 0;
|
||||
for (var i = 0; i < topBlocks.length; i++) {
|
||||
var block = topBlocks[i];
|
||||
const toggleOption_ = function(shouldCollapse, topBlocks) {
|
||||
const DELAY = 10;
|
||||
let ms = 0;
|
||||
for (let i = 0; i < topBlocks.length; i++) {
|
||||
let block = topBlocks[i];
|
||||
while (block) {
|
||||
setTimeout(block.setCollapsed.bind(block, shouldCollapse), ms);
|
||||
block = block.getNextBlock();
|
||||
@@ -115,17 +128,18 @@ Blockly.ContextMenuItems.toggleOption_ = function(shouldCollapse, topBlocks) {
|
||||
};
|
||||
|
||||
/** Option to collapse all blocks. */
|
||||
Blockly.ContextMenuItems.registerCollapse = function() {
|
||||
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
|
||||
var collapseOption = {
|
||||
displayText: function() {
|
||||
return Blockly.Msg['COLLAPSE_ALL'];
|
||||
const registerCollapse = function() {
|
||||
/** @type {!ContextMenuRegistry.RegistryItem} */
|
||||
const collapseOption = {
|
||||
displayText: function() {
|
||||
return Msg['COLLAPSE_ALL'];
|
||||
},
|
||||
preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
if (scope.workspace.options.collapse) {
|
||||
var topBlocks = scope.workspace.getTopBlocks(false);
|
||||
for (var i = 0; i < topBlocks.length; i++) {
|
||||
var block = topBlocks[i];
|
||||
const topBlocks = scope.workspace.getTopBlocks(false);
|
||||
for (let i = 0; i < topBlocks.length; i++) {
|
||||
let block = topBlocks[i];
|
||||
while (block) {
|
||||
if (!block.isCollapsed()) {
|
||||
return 'enabled';
|
||||
@@ -137,28 +151,31 @@ Blockly.ContextMenuItems.registerCollapse = function() {
|
||||
}
|
||||
return 'hidden';
|
||||
},
|
||||
callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
Blockly.ContextMenuItems.toggleOption_(true, scope.workspace.getTopBlocks(true));
|
||||
callback: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
toggleOption_(true, scope.workspace.getTopBlocks(true));
|
||||
},
|
||||
scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE,
|
||||
id: 'collapseWorkspace',
|
||||
weight: 4,
|
||||
scopeType: ContextMenuRegistry.ScopeType.WORKSPACE,
|
||||
id: 'collapseWorkspace',
|
||||
weight: 4,
|
||||
};
|
||||
Blockly.ContextMenuRegistry.registry.register(collapseOption);
|
||||
ContextMenuRegistry.registry.register(collapseOption);
|
||||
};
|
||||
exports.registerCollapse = registerCollapse;
|
||||
|
||||
/** Option to expand all blocks. */
|
||||
Blockly.ContextMenuItems.registerExpand = function() {
|
||||
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
|
||||
var expandOption = {
|
||||
const registerExpand = function() {
|
||||
/** @type {!ContextMenuRegistry.RegistryItem} */
|
||||
const expandOption = {
|
||||
displayText: function() {
|
||||
return Blockly.Msg['EXPAND_ALL'];
|
||||
return Msg['EXPAND_ALL'];
|
||||
},
|
||||
preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
if (scope.workspace.options.collapse) {
|
||||
var topBlocks = scope.workspace.getTopBlocks(false);
|
||||
for (var i = 0; i < topBlocks.length; i++) {
|
||||
var block = topBlocks[i];
|
||||
const topBlocks = scope.workspace.getTopBlocks(false);
|
||||
for (let i = 0; i < topBlocks.length; i++) {
|
||||
let block = topBlocks[i];
|
||||
while (block) {
|
||||
if (block.isCollapsed()) {
|
||||
return 'enabled';
|
||||
@@ -170,142 +187,151 @@ Blockly.ContextMenuItems.registerExpand = function() {
|
||||
}
|
||||
return 'hidden';
|
||||
},
|
||||
callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
Blockly.ContextMenuItems.toggleOption_(false, scope.workspace.getTopBlocks(true));
|
||||
callback: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
toggleOption_(false, scope.workspace.getTopBlocks(true));
|
||||
},
|
||||
scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE,
|
||||
scopeType: ContextMenuRegistry.ScopeType.WORKSPACE,
|
||||
id: 'expandWorkspace',
|
||||
weight: 5,
|
||||
};
|
||||
Blockly.ContextMenuRegistry.registry.register(expandOption);
|
||||
ContextMenuRegistry.registry.register(expandOption);
|
||||
};
|
||||
exports.registerExpand = registerExpand;
|
||||
|
||||
/**
|
||||
* Adds a block and its children to a list of deletable blocks.
|
||||
* @param {!Blockly.BlockSvg} block to delete.
|
||||
* @param {!Array<!Blockly.BlockSvg>} deleteList list of blocks that can be deleted. This will be
|
||||
* @param {!BlockSvg} block to delete.
|
||||
* @param {!Array<!BlockSvg>} deleteList list of blocks that can be deleted.
|
||||
* This will be
|
||||
* modifed in place with the given block and its descendants.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ContextMenuItems.addDeletableBlocks_ = function(block, deleteList) {
|
||||
const addDeletableBlocks_ = function(block, deleteList) {
|
||||
if (block.isDeletable()) {
|
||||
Array.prototype.push.apply(deleteList, block.getDescendants(false));
|
||||
} else {
|
||||
var children = /* eslint-disable-next-line indent */
|
||||
/** @type {!Array<!Blockly.BlockSvg>} */ (block.getChildren(false));
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
Blockly.ContextMenuItems.addDeletableBlocks_(children[i], deleteList);
|
||||
const children = /* eslint-disable-next-line indent */
|
||||
/** @type {!Array<!BlockSvg>} */ (block.getChildren(false));
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
addDeletableBlocks_(children[i], deleteList);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a list of blocks that can be deleted in the given workspace.
|
||||
* @param {!Blockly.WorkspaceSvg} workspace to delete all blocks from.
|
||||
* @return {!Array<!Blockly.BlockSvg>} list of blocks to delete.
|
||||
* @param {!WorkspaceSvg} workspace to delete all blocks from.
|
||||
* @return {!Array<!BlockSvg>} list of blocks to delete.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ContextMenuItems.getDeletableBlocks_ = function(workspace) {
|
||||
var deleteList = [];
|
||||
var topBlocks = workspace.getTopBlocks(true);
|
||||
for (var i = 0; i < topBlocks.length; i++) {
|
||||
Blockly.ContextMenuItems.addDeletableBlocks_(topBlocks[i], deleteList);
|
||||
const getDeletableBlocks_ = function(workspace) {
|
||||
const deleteList = [];
|
||||
const topBlocks = workspace.getTopBlocks(true);
|
||||
for (let i = 0; i < topBlocks.length; i++) {
|
||||
addDeletableBlocks_(topBlocks[i], deleteList);
|
||||
}
|
||||
return deleteList;
|
||||
};
|
||||
|
||||
/** Deletes the given blocks. Used to delete all blocks in the workspace.
|
||||
* @param {!Array<!Blockly.BlockSvg>} deleteList list of blocks to delete.
|
||||
* @param {string} eventGroup event group ID with which all delete events should be associated.
|
||||
/**
|
||||
* Deletes the given blocks. Used to delete all blocks in the workspace.
|
||||
* @param {!Array<!BlockSvg>} deleteList list of blocks to delete.
|
||||
* @param {string} eventGroup event group ID with which all delete events should
|
||||
* be associated.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ContextMenuItems.deleteNext_ = function(deleteList, eventGroup) {
|
||||
var DELAY = 10;
|
||||
Blockly.Events.setGroup(eventGroup);
|
||||
var block = deleteList.shift();
|
||||
const deleteNext_ = function(deleteList, eventGroup) {
|
||||
const DELAY = 10;
|
||||
Events.setGroup(eventGroup);
|
||||
const block = deleteList.shift();
|
||||
if (block) {
|
||||
if (block.workspace) {
|
||||
block.dispose(false, true);
|
||||
setTimeout(Blockly.ContextMenuItems.deleteNext_, DELAY, deleteList, eventGroup);
|
||||
setTimeout(deleteNext_, DELAY, deleteList, eventGroup);
|
||||
} else {
|
||||
Blockly.ContextMenuItems.deleteNext_(deleteList, eventGroup);
|
||||
deleteNext_(deleteList, eventGroup);
|
||||
}
|
||||
}
|
||||
Blockly.Events.setGroup(false);
|
||||
Events.setGroup(false);
|
||||
};
|
||||
|
||||
/** Option to delete all blocks. */
|
||||
Blockly.ContextMenuItems.registerDeleteAll = function() {
|
||||
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
|
||||
var deleteOption = {
|
||||
displayText: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
const registerDeleteAll = function() {
|
||||
/** @type {!ContextMenuRegistry.RegistryItem} */
|
||||
const deleteOption = {
|
||||
displayText: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
if (!scope.workspace) {
|
||||
return;
|
||||
}
|
||||
var deletableBlocksLength =
|
||||
Blockly.ContextMenuItems.getDeletableBlocks_(scope.workspace).length;
|
||||
const deletableBlocksLength = getDeletableBlocks_(scope.workspace).length;
|
||||
if (deletableBlocksLength == 1) {
|
||||
return Blockly.Msg['DELETE_BLOCK'];
|
||||
return Msg['DELETE_BLOCK'];
|
||||
} else {
|
||||
return Blockly.Msg['DELETE_X_BLOCKS'].replace('%1', String(deletableBlocksLength));
|
||||
return Msg['DELETE_X_BLOCKS'].replace(
|
||||
'%1', String(deletableBlocksLength));
|
||||
}
|
||||
},
|
||||
preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
if (!scope.workspace) {
|
||||
return;
|
||||
}
|
||||
var deletableBlocksLength =
|
||||
Blockly.ContextMenuItems.getDeletableBlocks_(scope.workspace).length;
|
||||
const deletableBlocksLength = getDeletableBlocks_(scope.workspace).length;
|
||||
return deletableBlocksLength > 0 ? 'enabled' : 'disabled';
|
||||
},
|
||||
callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
callback: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
if (!scope.workspace) {
|
||||
return;
|
||||
}
|
||||
scope.workspace.cancelCurrentGesture();
|
||||
var deletableBlocks = Blockly.ContextMenuItems.getDeletableBlocks_(scope.workspace);
|
||||
var eventGroup = Blockly.utils.genUid();
|
||||
const deletableBlocks = getDeletableBlocks_(scope.workspace);
|
||||
const eventGroup = utils.genUid();
|
||||
if (deletableBlocks.length < 2) {
|
||||
Blockly.ContextMenuItems.deleteNext_(deletableBlocks, eventGroup);
|
||||
deleteNext_(deletableBlocks, eventGroup);
|
||||
} else {
|
||||
Blockly.confirm(
|
||||
Blockly.Msg['DELETE_ALL_BLOCKS'].replace('%1', deletableBlocks.length),
|
||||
Msg['DELETE_ALL_BLOCKS'].replace('%1', deletableBlocks.length),
|
||||
function(ok) {
|
||||
if (ok) {
|
||||
Blockly.ContextMenuItems.deleteNext_(deletableBlocks, eventGroup);
|
||||
deleteNext_(deletableBlocks, eventGroup);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE,
|
||||
scopeType: ContextMenuRegistry.ScopeType.WORKSPACE,
|
||||
id: 'workspaceDelete',
|
||||
weight: 6,
|
||||
};
|
||||
Blockly.ContextMenuRegistry.registry.register(deleteOption);
|
||||
ContextMenuRegistry.registry.register(deleteOption);
|
||||
};
|
||||
exports.registerDeleteAll = registerDeleteAll;
|
||||
|
||||
/**
|
||||
* Registers all workspace-scoped context menu items.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ContextMenuItems.registerWorkspaceOptions_ = function() {
|
||||
Blockly.ContextMenuItems.registerUndo();
|
||||
Blockly.ContextMenuItems.registerRedo();
|
||||
Blockly.ContextMenuItems.registerCleanup();
|
||||
Blockly.ContextMenuItems.registerCollapse();
|
||||
Blockly.ContextMenuItems.registerExpand();
|
||||
Blockly.ContextMenuItems.registerDeleteAll();
|
||||
const registerWorkspaceOptions_ = function() {
|
||||
registerUndo();
|
||||
registerRedo();
|
||||
registerCleanup();
|
||||
registerCollapse();
|
||||
registerExpand();
|
||||
registerDeleteAll();
|
||||
};
|
||||
|
||||
/** Option to duplicate a block. */
|
||||
Blockly.ContextMenuItems.registerDuplicate = function() {
|
||||
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
|
||||
var duplicateOption = {
|
||||
const registerDuplicate = function() {
|
||||
/** @type {!ContextMenuRegistry.RegistryItem} */
|
||||
const duplicateOption = {
|
||||
displayText: function() {
|
||||
return Blockly.Msg['DUPLICATE_BLOCK'];
|
||||
return Msg['DUPLICATE_BLOCK'];
|
||||
},
|
||||
preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
var block = scope.block;
|
||||
preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
const block = scope.block;
|
||||
if (!block.isInFlyout && block.isDeletable() && block.isMovable()) {
|
||||
if (block.isDuplicatable()) {
|
||||
return 'enabled';
|
||||
@@ -314,121 +340,141 @@ Blockly.ContextMenuItems.registerDuplicate = function() {
|
||||
}
|
||||
return 'hidden';
|
||||
},
|
||||
callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
callback: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
if (scope.block) {
|
||||
Blockly.duplicate(scope.block);
|
||||
clipboard.duplicate(scope.block);
|
||||
}
|
||||
},
|
||||
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
|
||||
scopeType: ContextMenuRegistry.ScopeType.BLOCK,
|
||||
id: 'blockDuplicate',
|
||||
weight: 1,
|
||||
};
|
||||
Blockly.ContextMenuRegistry.registry.register(duplicateOption);
|
||||
ContextMenuRegistry.registry.register(duplicateOption);
|
||||
};
|
||||
exports.registerDuplicate = registerDuplicate;
|
||||
|
||||
/** Option to add or remove block-level comment. */
|
||||
Blockly.ContextMenuItems.registerComment = function() {
|
||||
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
|
||||
var commentOption = {
|
||||
displayText: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
const registerComment = function() {
|
||||
/** @type {!ContextMenuRegistry.RegistryItem} */
|
||||
const commentOption = {
|
||||
displayText: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
if (scope.block.getCommentIcon()) {
|
||||
// If there's already a comment, option is to remove.
|
||||
return Blockly.Msg['REMOVE_COMMENT'];
|
||||
return Msg['REMOVE_COMMENT'];
|
||||
}
|
||||
// If there's no comment yet, option is to add.
|
||||
return Blockly.Msg['ADD_COMMENT'];
|
||||
return Msg['ADD_COMMENT'];
|
||||
},
|
||||
preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
var block = scope.block;
|
||||
preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
const block = scope.block;
|
||||
// IE doesn't support necessary features for comment editing.
|
||||
if (!Blockly.utils.userAgent.IE && !block.isInFlyout && block.workspace.options.comments &&
|
||||
!block.isCollapsed() && block.isEditable()) {
|
||||
if (!userAgent.IE && !block.isInFlyout &&
|
||||
block.workspace.options.comments && !block.isCollapsed() &&
|
||||
block.isEditable()) {
|
||||
return 'enabled';
|
||||
}
|
||||
return 'hidden';
|
||||
},
|
||||
callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
var block = scope.block;
|
||||
callback: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
const block = scope.block;
|
||||
if (block.getCommentIcon()) {
|
||||
block.setCommentText(null);
|
||||
} else {
|
||||
block.setCommentText('');
|
||||
}
|
||||
},
|
||||
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
|
||||
scopeType: ContextMenuRegistry.ScopeType.BLOCK,
|
||||
id: 'blockComment',
|
||||
weight: 2,
|
||||
};
|
||||
Blockly.ContextMenuRegistry.registry.register(commentOption);
|
||||
ContextMenuRegistry.registry.register(commentOption);
|
||||
};
|
||||
exports.registerComment = registerComment;
|
||||
|
||||
/** Option to inline variables. */
|
||||
Blockly.ContextMenuItems.registerInline = function() {
|
||||
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
|
||||
var inlineOption = {
|
||||
displayText: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
return (scope.block.getInputsInline()) ?
|
||||
Blockly.Msg['EXTERNAL_INPUTS'] : Blockly.Msg['INLINE_INPUTS'];
|
||||
const registerInline = function() {
|
||||
/** @type {!ContextMenuRegistry.RegistryItem} */
|
||||
const inlineOption = {
|
||||
displayText: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
return (scope.block.getInputsInline()) ? Msg['EXTERNAL_INPUTS'] :
|
||||
Msg['INLINE_INPUTS'];
|
||||
},
|
||||
preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
var block = scope.block;
|
||||
preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
const block = scope.block;
|
||||
if (!block.isInFlyout && block.isMovable() && !block.isCollapsed()) {
|
||||
for (var i = 1; i < block.inputList.length; i++) {
|
||||
// Only display this option if there are two value or dummy inputs next to each other.
|
||||
if (block.inputList[i - 1].type != Blockly.inputTypes.STATEMENT &&
|
||||
block.inputList[i].type != Blockly.inputTypes.STATEMENT) {
|
||||
for (let i = 1; i < block.inputList.length; i++) {
|
||||
// Only display this option if there are two value or dummy inputs
|
||||
// next to each other.
|
||||
if (block.inputList[i - 1].type != inputTypes.STATEMENT &&
|
||||
block.inputList[i].type != inputTypes.STATEMENT) {
|
||||
return 'enabled';
|
||||
}
|
||||
}
|
||||
}
|
||||
return 'hidden';
|
||||
},
|
||||
callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
callback: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
scope.block.setInputsInline(!scope.block.getInputsInline());
|
||||
},
|
||||
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
|
||||
scopeType: ContextMenuRegistry.ScopeType.BLOCK,
|
||||
id: 'blockInline',
|
||||
weight: 3,
|
||||
};
|
||||
Blockly.ContextMenuRegistry.registry.register(inlineOption);
|
||||
ContextMenuRegistry.registry.register(inlineOption);
|
||||
};
|
||||
exports.registerInline = registerInline;
|
||||
|
||||
/** Option to collapse or expand a block. */
|
||||
Blockly.ContextMenuItems.registerCollapseExpandBlock = function() {
|
||||
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
|
||||
var collapseExpandOption = {
|
||||
displayText: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
return scope.block.isCollapsed() ?
|
||||
Blockly.Msg['EXPAND_BLOCK'] : Blockly.Msg['COLLAPSE_BLOCK'];
|
||||
const registerCollapseExpandBlock = function() {
|
||||
/** @type {!ContextMenuRegistry.RegistryItem} */
|
||||
const collapseExpandOption = {
|
||||
displayText: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
return scope.block.isCollapsed() ? Msg['EXPAND_BLOCK'] :
|
||||
Msg['COLLAPSE_BLOCK'];
|
||||
},
|
||||
preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
var block = scope.block;
|
||||
if (!block.isInFlyout && block.isMovable() && block.workspace.options.collapse) {
|
||||
preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
const block = scope.block;
|
||||
if (!block.isInFlyout && block.isMovable() &&
|
||||
block.workspace.options.collapse) {
|
||||
return 'enabled';
|
||||
}
|
||||
return 'hidden';
|
||||
},
|
||||
callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
callback: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
scope.block.setCollapsed(!scope.block.isCollapsed());
|
||||
},
|
||||
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
|
||||
scopeType: ContextMenuRegistry.ScopeType.BLOCK,
|
||||
id: 'blockCollapseExpand',
|
||||
weight: 4,
|
||||
};
|
||||
Blockly.ContextMenuRegistry.registry.register(collapseExpandOption);
|
||||
ContextMenuRegistry.registry.register(collapseExpandOption);
|
||||
};
|
||||
exports.registerCollapseExpandBlock = registerCollapseExpandBlock;
|
||||
|
||||
/** Option to disable or enable a block. */
|
||||
Blockly.ContextMenuItems.registerDisable = function() {
|
||||
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
|
||||
var disableOption = {
|
||||
displayText: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
return (scope.block.isEnabled()) ?
|
||||
Blockly.Msg['DISABLE_BLOCK'] : Blockly.Msg['ENABLE_BLOCK'];
|
||||
const registerDisable = function() {
|
||||
/** @type {!ContextMenuRegistry.RegistryItem} */
|
||||
const disableOption = {
|
||||
displayText: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
return (scope.block.isEnabled()) ? Msg['DISABLE_BLOCK'] :
|
||||
Msg['ENABLE_BLOCK'];
|
||||
},
|
||||
preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
var block = scope.block;
|
||||
if (!block.isInFlyout && block.workspace.options.disable && block.isEditable()) {
|
||||
preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
const block = scope.block;
|
||||
if (!block.isInFlyout && block.workspace.options.disable &&
|
||||
block.isEditable()) {
|
||||
if (block.getInheritedDisabled()) {
|
||||
return 'disabled';
|
||||
}
|
||||
@@ -436,108 +482,119 @@ Blockly.ContextMenuItems.registerDisable = function() {
|
||||
}
|
||||
return 'hidden';
|
||||
},
|
||||
callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
var block = scope.block;
|
||||
var group = Blockly.Events.getGroup();
|
||||
callback: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
const block = scope.block;
|
||||
const group = Events.getGroup();
|
||||
if (!group) {
|
||||
Blockly.Events.setGroup(true);
|
||||
Events.setGroup(true);
|
||||
}
|
||||
block.setEnabled(!block.isEnabled());
|
||||
if (!group) {
|
||||
Blockly.Events.setGroup(false);
|
||||
Events.setGroup(false);
|
||||
}
|
||||
},
|
||||
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
|
||||
scopeType: ContextMenuRegistry.ScopeType.BLOCK,
|
||||
id: 'blockDisable',
|
||||
weight: 5,
|
||||
};
|
||||
Blockly.ContextMenuRegistry.registry.register(disableOption);
|
||||
ContextMenuRegistry.registry.register(disableOption);
|
||||
};
|
||||
exports.registerDisable = registerDisable;
|
||||
|
||||
/** Option to delete a block. */
|
||||
Blockly.ContextMenuItems.registerDelete = function() {
|
||||
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
|
||||
var deleteOption = {
|
||||
displayText: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
var block = scope.block;
|
||||
const registerDelete = function() {
|
||||
/** @type {!ContextMenuRegistry.RegistryItem} */
|
||||
const deleteOption = {
|
||||
displayText: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
const block = scope.block;
|
||||
// Count the number of blocks that are nested in this block.
|
||||
var descendantCount = block.getDescendants(false).length;
|
||||
var nextBlock = block.getNextBlock();
|
||||
let descendantCount = block.getDescendants(false).length;
|
||||
const nextBlock = block.getNextBlock();
|
||||
if (nextBlock) {
|
||||
// Blocks in the current stack would survive this block's deletion.
|
||||
descendantCount -= nextBlock.getDescendants(false).length;
|
||||
}
|
||||
return (descendantCount == 1) ? Blockly.Msg['DELETE_BLOCK'] :
|
||||
Blockly.Msg['DELETE_X_BLOCKS'].replace('%1', String(descendantCount));
|
||||
return (descendantCount == 1) ?
|
||||
Msg['DELETE_BLOCK'] :
|
||||
Msg['DELETE_X_BLOCKS'].replace('%1', String(descendantCount));
|
||||
},
|
||||
preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
if (!scope.block.isInFlyout && scope.block.isDeletable()) {
|
||||
return 'enabled';
|
||||
}
|
||||
return 'hidden';
|
||||
},
|
||||
callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
Blockly.Events.setGroup(true);
|
||||
callback: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
Events.setGroup(true);
|
||||
if (scope.block) {
|
||||
Blockly.deleteBlock(scope.block);
|
||||
}
|
||||
Blockly.Events.setGroup(false);
|
||||
Events.setGroup(false);
|
||||
},
|
||||
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
|
||||
scopeType: ContextMenuRegistry.ScopeType.BLOCK,
|
||||
id: 'blockDelete',
|
||||
weight: 6,
|
||||
};
|
||||
Blockly.ContextMenuRegistry.registry.register(deleteOption);
|
||||
ContextMenuRegistry.registry.register(deleteOption);
|
||||
};
|
||||
exports.registerDelete = registerDelete;
|
||||
|
||||
/** Option to open help for a block. */
|
||||
Blockly.ContextMenuItems.registerHelp = function() {
|
||||
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
|
||||
var helpOption = {
|
||||
const registerHelp = function() {
|
||||
/** @type {!ContextMenuRegistry.RegistryItem} */
|
||||
const helpOption = {
|
||||
displayText: function() {
|
||||
return Blockly.Msg['HELP'];
|
||||
return Msg['HELP'];
|
||||
},
|
||||
preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
var block = scope.block;
|
||||
var url = (typeof block.helpUrl == 'function') ?
|
||||
block.helpUrl() : block.helpUrl;
|
||||
preconditionFn: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
const block = scope.block;
|
||||
const url = (typeof block.helpUrl == 'function') ? block.helpUrl() :
|
||||
block.helpUrl;
|
||||
if (url) {
|
||||
return 'enabled';
|
||||
}
|
||||
return 'hidden';
|
||||
},
|
||||
callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
|
||||
callback: function(/** @type {!ContextMenuRegistry.Scope} */
|
||||
scope) {
|
||||
scope.block.showHelp();
|
||||
},
|
||||
scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
|
||||
scopeType: ContextMenuRegistry.ScopeType.BLOCK,
|
||||
id: 'blockHelp',
|
||||
weight: 7,
|
||||
};
|
||||
Blockly.ContextMenuRegistry.registry.register(helpOption);
|
||||
ContextMenuRegistry.registry.register(helpOption);
|
||||
};
|
||||
exports.registerHelp = registerHelp;
|
||||
|
||||
/**
|
||||
* Registers all block-scoped context menu items.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ContextMenuItems.registerBlockOptions_ = function() {
|
||||
Blockly.ContextMenuItems.registerDuplicate();
|
||||
Blockly.ContextMenuItems.registerComment();
|
||||
Blockly.ContextMenuItems.registerInline();
|
||||
Blockly.ContextMenuItems.registerCollapseExpandBlock();
|
||||
Blockly.ContextMenuItems.registerDisable();
|
||||
Blockly.ContextMenuItems.registerDelete();
|
||||
Blockly.ContextMenuItems.registerHelp();
|
||||
const registerBlockOptions_ = function() {
|
||||
registerDuplicate();
|
||||
registerComment();
|
||||
registerInline();
|
||||
registerCollapseExpandBlock();
|
||||
registerDisable();
|
||||
registerDelete();
|
||||
registerHelp();
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers all default context menu items. This should be called once per instance of
|
||||
* ContextMenuRegistry.
|
||||
* Registers all default context menu items. This should be called once per
|
||||
* instance of ContextMenuRegistry.
|
||||
* @package
|
||||
*/
|
||||
Blockly.ContextMenuItems.registerDefaultOptions = function() {
|
||||
Blockly.ContextMenuItems.registerWorkspaceOptions_();
|
||||
Blockly.ContextMenuItems.registerBlockOptions_();
|
||||
const registerDefaultOptions = function() {
|
||||
registerWorkspaceOptions_();
|
||||
registerBlockOptions_();
|
||||
};
|
||||
exports.registerDefaultOptions = registerDefaultOptions;
|
||||
|
||||
Blockly.ContextMenuItems.registerDefaultOptions();
|
||||
registerDefaultOptions();
|
||||
|
||||
@@ -11,91 +11,97 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @name Blockly.ContextMenuRegistry
|
||||
* @name ContextMenuRegistry
|
||||
* @namespace
|
||||
*/
|
||||
goog.provide('Blockly.ContextMenuRegistry');
|
||||
goog.module('Blockly.ContextMenuRegistry');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
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 WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
|
||||
|
||||
/**
|
||||
* Class for the registry of context menu items. This is intended to be a
|
||||
* singleton. You should not create a new instance, and only access this class
|
||||
* from Blockly.ContextMenuRegistry.registry.
|
||||
* from ContextMenuRegistry.registry.
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
Blockly.ContextMenuRegistry = function() {
|
||||
const ContextMenuRegistry = function() {
|
||||
// Singleton instance should be registered once.
|
||||
Blockly.ContextMenuRegistry.registry = this;
|
||||
ContextMenuRegistry.registry = this;
|
||||
|
||||
/**
|
||||
* Registry of all registered RegistryItems, keyed by ID.
|
||||
* @type {!Object<string, !Blockly.ContextMenuRegistry.RegistryItem>}
|
||||
* @type {!Object<string, !ContextMenuRegistry.RegistryItem>}
|
||||
* @private
|
||||
*/
|
||||
this.registry_ = Object.create(null);
|
||||
};
|
||||
|
||||
/**
|
||||
* Where this menu item should be rendered. If the menu item should be rendered in multiple
|
||||
* scopes, e.g. on both a block and a workspace, it should be registered for each scope.
|
||||
* Where this menu item should be rendered. If the menu item should be rendered
|
||||
* in multiple scopes, e.g. on both a block and a workspace, it should be
|
||||
* registered for each scope.
|
||||
* @enum {string}
|
||||
*/
|
||||
Blockly.ContextMenuRegistry.ScopeType = {
|
||||
ContextMenuRegistry.ScopeType = {
|
||||
BLOCK: 'block',
|
||||
WORKSPACE: 'workspace',
|
||||
};
|
||||
|
||||
/**
|
||||
* The actual workspace/block where the menu is being rendered. This is passed to callback and
|
||||
* displayText functions that depend on this information.
|
||||
* The actual workspace/block where the menu is being rendered. This is passed
|
||||
* to callback and displayText functions that depend on this information.
|
||||
* @typedef {{
|
||||
* block: (Blockly.BlockSvg|undefined),
|
||||
* workspace: (Blockly.WorkspaceSvg|undefined)
|
||||
* block: (BlockSvg|undefined),
|
||||
* workspace: (WorkspaceSvg|undefined)
|
||||
* }}
|
||||
*/
|
||||
Blockly.ContextMenuRegistry.Scope;
|
||||
ContextMenuRegistry.Scope;
|
||||
|
||||
/**
|
||||
* A menu item as entered in the registry.
|
||||
* @typedef {{
|
||||
* callback: function(!Blockly.ContextMenuRegistry.Scope),
|
||||
* scopeType: !Blockly.ContextMenuRegistry.ScopeType,
|
||||
* displayText: ((function(!Blockly.ContextMenuRegistry.Scope):string)|string),
|
||||
* preconditionFn: function(!Blockly.ContextMenuRegistry.Scope):string,
|
||||
* callback: function(!ContextMenuRegistry.Scope),
|
||||
* scopeType: !ContextMenuRegistry.ScopeType,
|
||||
* displayText: ((function(!ContextMenuRegistry.Scope):string)|string),
|
||||
* preconditionFn: function(!ContextMenuRegistry.Scope):string,
|
||||
* weight: number,
|
||||
* id: string
|
||||
* }}
|
||||
*/
|
||||
Blockly.ContextMenuRegistry.RegistryItem;
|
||||
*/
|
||||
ContextMenuRegistry.RegistryItem;
|
||||
|
||||
/**
|
||||
* A menu item as presented to contextmenu.js.
|
||||
* @typedef {{
|
||||
* text: string,
|
||||
* enabled: boolean,
|
||||
* callback: function(!Blockly.ContextMenuRegistry.Scope),
|
||||
* scope: !Blockly.ContextMenuRegistry.Scope,
|
||||
* callback: function(!ContextMenuRegistry.Scope),
|
||||
* scope: !ContextMenuRegistry.Scope,
|
||||
* weight: number
|
||||
* }}
|
||||
*/
|
||||
Blockly.ContextMenuRegistry.ContextMenuOption;
|
||||
ContextMenuRegistry.ContextMenuOption;
|
||||
|
||||
/**
|
||||
* Singleton instance of this class. All interactions with this class should be
|
||||
* done on this object.
|
||||
* @type {?Blockly.ContextMenuRegistry}
|
||||
* @type {?ContextMenuRegistry}
|
||||
*/
|
||||
Blockly.ContextMenuRegistry.registry = null;
|
||||
ContextMenuRegistry.registry = null;
|
||||
|
||||
/**
|
||||
* Registers a RegistryItem.
|
||||
* @param {!Blockly.ContextMenuRegistry.RegistryItem} item Context menu item to register.
|
||||
* @param {!ContextMenuRegistry.RegistryItem} item Context menu item to
|
||||
* register.
|
||||
* @throws {Error} if an item with the given ID already exists.
|
||||
*/
|
||||
Blockly.ContextMenuRegistry.prototype.register = function(item) {
|
||||
ContextMenuRegistry.prototype.register = function(item) {
|
||||
if (this.registry_[item.id]) {
|
||||
throw Error('Menu item with ID "' + item.id + '" is already registered.');
|
||||
}
|
||||
@@ -107,7 +113,7 @@ Blockly.ContextMenuRegistry.prototype.register = function(item) {
|
||||
* @param {string} id The ID of the RegistryItem to remove.
|
||||
* @throws {Error} if an item with the given ID does not exist.
|
||||
*/
|
||||
Blockly.ContextMenuRegistry.prototype.unregister = function(id) {
|
||||
ContextMenuRegistry.prototype.unregister = function(id) {
|
||||
if (!this.registry_[id]) {
|
||||
throw new Error('Menu item with ID "' + id + '" not found.');
|
||||
}
|
||||
@@ -116,33 +122,37 @@ Blockly.ContextMenuRegistry.prototype.unregister = function(id) {
|
||||
|
||||
/**
|
||||
* @param {string} id The ID of the RegistryItem to get.
|
||||
* @return {?Blockly.ContextMenuRegistry.RegistryItem} RegistryItem or null if not found
|
||||
* @return {?ContextMenuRegistry.RegistryItem} RegistryItem or null if not found
|
||||
*/
|
||||
Blockly.ContextMenuRegistry.prototype.getItem = function(id) {
|
||||
ContextMenuRegistry.prototype.getItem = function(id) {
|
||||
return this.registry_[id] || null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the valid context menu options for the given scope type (e.g. block or workspace) and scope.
|
||||
* Blocks are only shown if the preconditionFn shows they should not be hidden.
|
||||
* @param {!Blockly.ContextMenuRegistry.ScopeType} scopeType Type of scope where menu should be
|
||||
* shown (e.g. on a block or on a workspace)
|
||||
* @param {!Blockly.ContextMenuRegistry.Scope} scope Current scope of context menu
|
||||
* Gets the valid context menu options for the given scope type (e.g. block or
|
||||
* workspace) and scope. Blocks are only shown if the preconditionFn shows they
|
||||
* should not be hidden.
|
||||
* @param {!ContextMenuRegistry.ScopeType} scopeType Type of scope where menu
|
||||
* should be shown (e.g. on a block or on a workspace)
|
||||
* @param {!ContextMenuRegistry.Scope} scope Current scope of context menu
|
||||
* (i.e., the exact workspace or block being clicked on)
|
||||
* @return {!Array<!Blockly.ContextMenuRegistry.ContextMenuOption>} the list of ContextMenuOptions
|
||||
* @return {!Array<!ContextMenuRegistry.ContextMenuOption>} the list of
|
||||
* ContextMenuOptions
|
||||
*/
|
||||
Blockly.ContextMenuRegistry.prototype.getContextMenuOptions = function(scopeType, scope) {
|
||||
var menuOptions = [];
|
||||
var registry = this.registry_;
|
||||
ContextMenuRegistry.prototype.getContextMenuOptions = function(
|
||||
scopeType, scope) {
|
||||
const menuOptions = [];
|
||||
const registry = this.registry_;
|
||||
Object.keys(registry).forEach(function(id) {
|
||||
var item = registry[id];
|
||||
const item = registry[id];
|
||||
if (scopeType == item.scopeType) {
|
||||
var precondition = item.preconditionFn(scope);
|
||||
const precondition = item.preconditionFn(scope);
|
||||
if (precondition != 'hidden') {
|
||||
var displayText = typeof item.displayText == 'function' ?
|
||||
item.displayText(scope) : item.displayText;
|
||||
/** @type {!Blockly.ContextMenuRegistry.ContextMenuOption} */
|
||||
var menuOption = {
|
||||
const displayText = typeof item.displayText == 'function' ?
|
||||
item.displayText(scope) :
|
||||
item.displayText;
|
||||
/** @type {!ContextMenuRegistry.ContextMenuOption} */
|
||||
const menuOption = {
|
||||
text: displayText,
|
||||
enabled: (precondition == 'enabled'),
|
||||
callback: item.callback,
|
||||
@@ -160,4 +170,6 @@ Blockly.ContextMenuRegistry.prototype.getContextMenuOptions = function(scopeType
|
||||
};
|
||||
|
||||
// Creates and assigns the singleton instance.
|
||||
new Blockly.ContextMenuRegistry();
|
||||
new ContextMenuRegistry();
|
||||
|
||||
exports = ContextMenuRegistry;
|
||||
|
||||
@@ -18,10 +18,10 @@ goog.module.declareLegacyNamespace();
|
||||
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');
|
||||
const IDeleteArea = goog.requireType('Blockly.IDeleteArea');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDraggable = goog.requireType('Blockly.IDraggable');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
|
||||
/**
|
||||
* Abstract class for a component that can delete a block or bubble that is
|
||||
@@ -42,7 +42,7 @@ const DeleteArea = function() {
|
||||
*/
|
||||
this.wouldDelete_ = false;
|
||||
};
|
||||
inherits(DeleteArea, DragTarget);
|
||||
object.inherits(DeleteArea, DragTarget);
|
||||
|
||||
/**
|
||||
* Returns whether the provided block or bubble would be deleted if dropped on
|
||||
|
||||
@@ -16,7 +16,7 @@ goog.module('Blockly.DragTarget');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDragTarget = goog.require('Blockly.IDragTarget');
|
||||
const IDragTarget = goog.requireType('Blockly.IDragTarget');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDraggable = goog.requireType('Blockly.IDraggable');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
goog.provide('Blockly.DropDownDiv');
|
||||
|
||||
goog.require('Blockly.common');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.math');
|
||||
goog.require('Blockly.utils.Rect');
|
||||
@@ -162,7 +163,7 @@ Blockly.DropDownDiv.createDom = function() {
|
||||
}
|
||||
var div = document.createElement('div');
|
||||
div.className = 'blocklyDropDownDiv';
|
||||
var container = Blockly.parentContainer || document.body;
|
||||
var container = Blockly.common.getParentContainer() || document.body;
|
||||
container.appendChild(div);
|
||||
/**
|
||||
* The div element.
|
||||
@@ -381,7 +382,7 @@ Blockly.DropDownDiv.show = function(owner, rtl, primaryX, primaryY,
|
||||
div.style.direction = rtl ? 'rtl' : 'ltr';
|
||||
|
||||
var mainWorkspace =
|
||||
/** @type {!Blockly.WorkspaceSvg} */ (Blockly.getMainWorkspace());
|
||||
/** @type {!Blockly.WorkspaceSvg} */ (Blockly.common.getMainWorkspace());
|
||||
Blockly.DropDownDiv.rendererClassName_ =
|
||||
mainWorkspace.getRenderer().getClassName();
|
||||
Blockly.DropDownDiv.themeClassName_ = mainWorkspace.getTheme().getClassName();
|
||||
@@ -694,7 +695,7 @@ Blockly.DropDownDiv.hideWithoutAnimation = function() {
|
||||
Blockly.DropDownDiv.themeClassName_ = '';
|
||||
}
|
||||
(/** @type {!Blockly.WorkspaceSvg} */ (
|
||||
Blockly.getMainWorkspace())).markFocused();
|
||||
Blockly.common.getMainWorkspace())).markFocused();
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,573 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2018 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Classes for all types of block events.
|
||||
* @author fenichel@google.com (Rachel Fenichel)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Events.BlockBase');
|
||||
goog.provide('Blockly.Events.BlockChange');
|
||||
goog.provide('Blockly.Events.BlockCreate');
|
||||
goog.provide('Blockly.Events.BlockDelete');
|
||||
goog.provide('Blockly.Events.BlockMove');
|
||||
goog.provide('Blockly.Events.Change'); // Deprecated.
|
||||
goog.provide('Blockly.Events.Create'); // Deprecated.
|
||||
goog.provide('Blockly.Events.Delete'); // Deprecated.
|
||||
goog.provide('Blockly.Events.Move'); // Deprecated.
|
||||
|
||||
goog.require('Blockly.connectionTypes');
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.Events.Abstract');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.utils.xml');
|
||||
goog.require('Blockly.Xml');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
|
||||
|
||||
/**
|
||||
* Abstract class for a block event.
|
||||
* @param {!Blockly.Block=} opt_block The block this event corresponds to.
|
||||
* Undefined for a blank event.
|
||||
* @extends {Blockly.Events.Abstract}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.BlockBase = function(opt_block) {
|
||||
Blockly.Events.BlockBase.superClass_.constructor.call(this);
|
||||
this.isBlank = typeof opt_block == 'undefined';
|
||||
|
||||
/**
|
||||
* The block ID for the block this event pertains to
|
||||
* @type {string}
|
||||
*/
|
||||
this.blockId = this.isBlank ? '' : opt_block.id;
|
||||
|
||||
/**
|
||||
* The workspace identifier for this event.
|
||||
* @type {string}
|
||||
*/
|
||||
this.workspaceId = this.isBlank ? '' : opt_block.workspace.id;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.BlockBase,
|
||||
Blockly.Events.Abstract);
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.BlockBase.prototype.toJson = function() {
|
||||
var json = Blockly.Events.BlockBase.superClass_.toJson.call(this);
|
||||
json['blockId'] = this.blockId;
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.BlockBase.prototype.fromJson = function(json) {
|
||||
Blockly.Events.BlockBase.superClass_.fromJson.call(this, json);
|
||||
this.blockId = json['blockId'];
|
||||
};
|
||||
|
||||
/**
|
||||
* Class for a block change event.
|
||||
* @param {!Blockly.Block=} opt_block The changed block. Undefined for a blank
|
||||
* event.
|
||||
* @param {string=} opt_element One of 'field', 'comment', 'disabled', etc.
|
||||
* @param {?string=} opt_name Name of input or field affected, or null.
|
||||
* @param {*=} opt_oldValue Previous value of element.
|
||||
* @param {*=} opt_newValue New value of element.
|
||||
* @extends {Blockly.Events.BlockBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.BlockChange = function(opt_block, opt_element, opt_name, opt_oldValue,
|
||||
opt_newValue) {
|
||||
Blockly.Events.Change.superClass_.constructor.call(this, opt_block);
|
||||
if (!opt_block) {
|
||||
return; // Blank event to be populated by fromJson.
|
||||
}
|
||||
this.element = typeof opt_element == 'undefined' ? '' : opt_element;
|
||||
this.name = typeof opt_name == 'undefined' ? '' : opt_name;
|
||||
this.oldValue = typeof opt_oldValue == 'undefined' ? '' : opt_oldValue;
|
||||
this.newValue = typeof opt_newValue == 'undefined' ? '' : opt_newValue;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.BlockChange, Blockly.Events.BlockBase);
|
||||
|
||||
/**
|
||||
* Class for a block change event.
|
||||
* @param {!Blockly.Block=} opt_block The changed block. Undefined for a blank
|
||||
* event.
|
||||
* @param {string=} opt_element One of 'field', 'comment', 'disabled', etc.
|
||||
* @param {?string=} opt_name Name of input or field affected, or null.
|
||||
* @param {*=} opt_oldValue Previous value of element.
|
||||
* @param {*=} opt_newValue New value of element.
|
||||
* @extends {Blockly.Events.BlockBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.Change = Blockly.Events.BlockChange;
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.BlockChange.prototype.type = Blockly.Events.CHANGE;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.BlockChange.prototype.toJson = function() {
|
||||
var json = Blockly.Events.BlockChange.superClass_.toJson.call(this);
|
||||
json['element'] = this.element;
|
||||
if (this.name) {
|
||||
json['name'] = this.name;
|
||||
}
|
||||
json['oldValue'] = this.oldValue;
|
||||
json['newValue'] = this.newValue;
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.BlockChange.prototype.fromJson = function(json) {
|
||||
Blockly.Events.BlockChange.superClass_.fromJson.call(this, json);
|
||||
this.element = json['element'];
|
||||
this.name = json['name'];
|
||||
this.oldValue = json['oldValue'];
|
||||
this.newValue = json['newValue'];
|
||||
};
|
||||
|
||||
/**
|
||||
* Does this event record any change of state?
|
||||
* @return {boolean} False if something changed.
|
||||
*/
|
||||
Blockly.Events.BlockChange.prototype.isNull = function() {
|
||||
return this.oldValue == this.newValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Run a change event.
|
||||
* @param {boolean} forward True if run forward, false if run backward (undo).
|
||||
*/
|
||||
Blockly.Events.BlockChange.prototype.run = function(forward) {
|
||||
var workspace = this.getEventWorkspace_();
|
||||
var block = workspace.getBlockById(this.blockId);
|
||||
if (!block) {
|
||||
console.warn("Can't change non-existent block: " + this.blockId);
|
||||
return;
|
||||
}
|
||||
if (block.mutator) {
|
||||
// Close the mutator (if open) since we don't want to update it.
|
||||
block.mutator.setVisible(false);
|
||||
}
|
||||
var value = forward ? this.newValue : this.oldValue;
|
||||
switch (this.element) {
|
||||
case 'field':
|
||||
var field = block.getField(this.name);
|
||||
if (field) {
|
||||
field.setValue(value);
|
||||
} else {
|
||||
console.warn("Can't set non-existent field: " + this.name);
|
||||
}
|
||||
break;
|
||||
case 'comment':
|
||||
block.setCommentText(/** @type {string} */ (value) || null);
|
||||
break;
|
||||
case 'collapsed':
|
||||
block.setCollapsed(!!value);
|
||||
break;
|
||||
case 'disabled':
|
||||
block.setEnabled(!value);
|
||||
break;
|
||||
case 'inline':
|
||||
block.setInputsInline(!!value);
|
||||
break;
|
||||
case 'mutation':
|
||||
var oldMutation = '';
|
||||
if (block.mutationToDom) {
|
||||
var oldMutationDom = block.mutationToDom();
|
||||
oldMutation = oldMutationDom && Blockly.Xml.domToText(oldMutationDom);
|
||||
}
|
||||
if (block.domToMutation) {
|
||||
var dom = Blockly.Xml.textToDom(/** @type {string} */ (value) || '<mutation/>');
|
||||
block.domToMutation(dom);
|
||||
}
|
||||
Blockly.Events.fire(new Blockly.Events.BlockChange(
|
||||
block, 'mutation', null, oldMutation, value));
|
||||
break;
|
||||
default:
|
||||
console.warn('Unknown change type: ' + this.element);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Class for a block creation event.
|
||||
* @param {!Blockly.Block=} opt_block The created block. Undefined for a blank
|
||||
* event.
|
||||
* @extends {Blockly.Events.BlockBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.Create = function(opt_block) {
|
||||
Blockly.Events.Create.superClass_.constructor.call(this, opt_block);
|
||||
if (!opt_block) {
|
||||
return; // Blank event to be populated by fromJson.
|
||||
}
|
||||
if (opt_block.isShadow()) {
|
||||
// Moving shadow blocks is handled via disconnection.
|
||||
this.recordUndo = false;
|
||||
}
|
||||
|
||||
if (opt_block.workspace.rendered) {
|
||||
this.xml = Blockly.Xml.blockToDomWithXY(opt_block);
|
||||
} else {
|
||||
this.xml = Blockly.Xml.blockToDom(opt_block);
|
||||
}
|
||||
this.ids = Blockly.Events.getDescendantIds(opt_block);
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.Create, Blockly.Events.BlockBase);
|
||||
|
||||
/**
|
||||
* Class for a block creation event.
|
||||
* @param {!Blockly.Block=} block The created block. Undefined for a blank
|
||||
* event.
|
||||
* @extends {Blockly.Events.BlockBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.BlockCreate = Blockly.Events.Create;
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.Create.prototype.type = Blockly.Events.CREATE;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.Create.prototype.toJson = function() {
|
||||
var json = Blockly.Events.Create.superClass_.toJson.call(this);
|
||||
json['xml'] = Blockly.Xml.domToText(this.xml);
|
||||
json['ids'] = this.ids;
|
||||
if (!this.recordUndo) {
|
||||
json['recordUndo'] = this.recordUndo;
|
||||
}
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.Create.prototype.fromJson = function(json) {
|
||||
Blockly.Events.Create.superClass_.fromJson.call(this, json);
|
||||
this.xml = Blockly.Xml.textToDom(json['xml']);
|
||||
this.ids = json['ids'];
|
||||
if (json['recordUndo'] !== undefined) {
|
||||
this.recordUndo = json['recordUndo'];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Run a creation event.
|
||||
* @param {boolean} forward True if run forward, false if run backward (undo).
|
||||
*/
|
||||
Blockly.Events.Create.prototype.run = function(forward) {
|
||||
var workspace = this.getEventWorkspace_();
|
||||
if (forward) {
|
||||
var xml = Blockly.utils.xml.createElement('xml');
|
||||
xml.appendChild(this.xml);
|
||||
Blockly.Xml.domToWorkspace(xml, workspace);
|
||||
} else {
|
||||
for (var i = 0, id; (id = this.ids[i]); i++) {
|
||||
var block = workspace.getBlockById(id);
|
||||
if (block) {
|
||||
block.dispose(false);
|
||||
} else if (id == this.blockId) {
|
||||
// Only complain about root-level block.
|
||||
console.warn("Can't uncreate non-existent block: " + id);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Class for a block deletion event.
|
||||
* @param {!Blockly.Block=} opt_block The deleted block. Undefined for a blank
|
||||
* event.
|
||||
* @extends {Blockly.Events.BlockBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.Delete = function(opt_block) {
|
||||
Blockly.Events.Delete.superClass_.constructor.call(this, opt_block);
|
||||
if (!opt_block) {
|
||||
return; // Blank event to be populated by fromJson.
|
||||
}
|
||||
if (opt_block.getParent()) {
|
||||
throw Error('Connected blocks cannot be deleted.');
|
||||
}
|
||||
if (opt_block.isShadow()) {
|
||||
// Respawning shadow blocks is handled via disconnection.
|
||||
this.recordUndo = false;
|
||||
}
|
||||
|
||||
if (opt_block.workspace.rendered) {
|
||||
this.oldXml = Blockly.Xml.blockToDomWithXY(opt_block);
|
||||
} else {
|
||||
this.oldXml = Blockly.Xml.blockToDom(opt_block);
|
||||
}
|
||||
this.ids = Blockly.Events.getDescendantIds(opt_block);
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.Delete, Blockly.Events.BlockBase);
|
||||
|
||||
/**
|
||||
* Class for a block deletion event.
|
||||
* @param {?Blockly.Block} block The deleted block. Null for a blank event.
|
||||
* @extends {Blockly.Events.BlockBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.BlockDelete = Blockly.Events.Delete;
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.Delete.prototype.type = Blockly.Events.DELETE;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.Delete.prototype.toJson = function() {
|
||||
var json = Blockly.Events.Delete.superClass_.toJson.call(this);
|
||||
json['oldXml'] = Blockly.Xml.domToText(this.oldXml);
|
||||
json['ids'] = this.ids;
|
||||
if (!this.recordUndo) {
|
||||
json['recordUndo'] = this.recordUndo;
|
||||
}
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.Delete.prototype.fromJson = function(json) {
|
||||
Blockly.Events.Delete.superClass_.fromJson.call(this, json);
|
||||
this.oldXml = Blockly.Xml.textToDom(json['oldXml']);
|
||||
this.ids = json['ids'];
|
||||
if (json['recordUndo'] !== undefined) {
|
||||
this.recordUndo = json['recordUndo'];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Run a deletion event.
|
||||
* @param {boolean} forward True if run forward, false if run backward (undo).
|
||||
*/
|
||||
Blockly.Events.Delete.prototype.run = function(forward) {
|
||||
var workspace = this.getEventWorkspace_();
|
||||
if (forward) {
|
||||
for (var i = 0, id; (id = this.ids[i]); i++) {
|
||||
var block = workspace.getBlockById(id);
|
||||
if (block) {
|
||||
block.dispose(false);
|
||||
} else if (id == this.blockId) {
|
||||
// Only complain about root-level block.
|
||||
console.warn("Can't delete non-existent block: " + id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var xml = Blockly.utils.xml.createElement('xml');
|
||||
xml.appendChild(this.oldXml);
|
||||
Blockly.Xml.domToWorkspace(xml, workspace);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Class for a block move event. Created before the move.
|
||||
* @param {!Blockly.Block=} opt_block The moved block. Undefined for a blank
|
||||
* event.
|
||||
* @extends {Blockly.Events.BlockBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.Move = function(opt_block) {
|
||||
Blockly.Events.Move.superClass_.constructor.call(this, opt_block);
|
||||
if (!opt_block) {
|
||||
return; // Blank event to be populated by fromJson.
|
||||
}
|
||||
if (opt_block.isShadow()) {
|
||||
// Moving shadow blocks is handled via disconnection.
|
||||
this.recordUndo = false;
|
||||
}
|
||||
|
||||
var location = this.currentLocation_();
|
||||
this.oldParentId = location.parentId;
|
||||
this.oldInputName = location.inputName;
|
||||
this.oldCoordinate = location.coordinate;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.Move, Blockly.Events.BlockBase);
|
||||
|
||||
/**
|
||||
* Class for a block move event. Created before the move.
|
||||
* @param {?Blockly.Block} block The moved block. Null for a blank event.
|
||||
* @extends {Blockly.Events.BlockBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.BlockMove = Blockly.Events.Move;
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.Move.prototype.type = Blockly.Events.MOVE;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.Move.prototype.toJson = function() {
|
||||
var json = Blockly.Events.Move.superClass_.toJson.call(this);
|
||||
if (this.newParentId) {
|
||||
json['newParentId'] = this.newParentId;
|
||||
}
|
||||
if (this.newInputName) {
|
||||
json['newInputName'] = this.newInputName;
|
||||
}
|
||||
if (this.newCoordinate) {
|
||||
json['newCoordinate'] = Math.round(this.newCoordinate.x) + ',' +
|
||||
Math.round(this.newCoordinate.y);
|
||||
}
|
||||
if (!this.recordUndo) {
|
||||
json['recordUndo'] = this.recordUndo;
|
||||
}
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.Move.prototype.fromJson = function(json) {
|
||||
Blockly.Events.Move.superClass_.fromJson.call(this, json);
|
||||
this.newParentId = json['newParentId'];
|
||||
this.newInputName = json['newInputName'];
|
||||
if (json['newCoordinate']) {
|
||||
var xy = json['newCoordinate'].split(',');
|
||||
this.newCoordinate =
|
||||
new Blockly.utils.Coordinate(Number(xy[0]), Number(xy[1]));
|
||||
}
|
||||
if (json['recordUndo'] !== undefined) {
|
||||
this.recordUndo = json['recordUndo'];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Record the block's new location. Called after the move.
|
||||
*/
|
||||
Blockly.Events.Move.prototype.recordNew = function() {
|
||||
var location = this.currentLocation_();
|
||||
this.newParentId = location.parentId;
|
||||
this.newInputName = location.inputName;
|
||||
this.newCoordinate = location.coordinate;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the parentId and input if the block is connected,
|
||||
* or the XY location if disconnected.
|
||||
* @return {!Object} Collection of location info.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Events.Move.prototype.currentLocation_ = function() {
|
||||
var workspace = this.getEventWorkspace_();
|
||||
var block = workspace.getBlockById(this.blockId);
|
||||
var location = {};
|
||||
var parent = block.getParent();
|
||||
if (parent) {
|
||||
location.parentId = parent.id;
|
||||
var input = parent.getInputWithBlock(block);
|
||||
if (input) {
|
||||
location.inputName = input.name;
|
||||
}
|
||||
} else {
|
||||
location.coordinate = block.getRelativeToSurfaceXY();
|
||||
}
|
||||
return location;
|
||||
};
|
||||
|
||||
/**
|
||||
* Does this event record any change of state?
|
||||
* @return {boolean} False if something changed.
|
||||
*/
|
||||
Blockly.Events.Move.prototype.isNull = function() {
|
||||
return this.oldParentId == this.newParentId &&
|
||||
this.oldInputName == this.newInputName &&
|
||||
Blockly.utils.Coordinate.equals(this.oldCoordinate, this.newCoordinate);
|
||||
};
|
||||
|
||||
/**
|
||||
* Run a move event.
|
||||
* @param {boolean} forward True if run forward, false if run backward (undo).
|
||||
*/
|
||||
Blockly.Events.Move.prototype.run = function(forward) {
|
||||
var workspace = this.getEventWorkspace_();
|
||||
var block = workspace.getBlockById(this.blockId);
|
||||
if (!block) {
|
||||
console.warn("Can't move non-existent block: " + this.blockId);
|
||||
return;
|
||||
}
|
||||
var parentId = forward ? this.newParentId : this.oldParentId;
|
||||
var inputName = forward ? this.newInputName : this.oldInputName;
|
||||
var coordinate = forward ? this.newCoordinate : this.oldCoordinate;
|
||||
var parentBlock = null;
|
||||
if (parentId) {
|
||||
parentBlock = workspace.getBlockById(parentId);
|
||||
if (!parentBlock) {
|
||||
console.warn("Can't connect to non-existent block: " + parentId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (block.getParent()) {
|
||||
block.unplug();
|
||||
}
|
||||
if (coordinate) {
|
||||
var xy = block.getRelativeToSurfaceXY();
|
||||
block.moveBy(coordinate.x - xy.x, coordinate.y - xy.y);
|
||||
} else {
|
||||
var blockConnection = block.outputConnection || block.previousConnection;
|
||||
var parentConnection;
|
||||
var connectionType = blockConnection.type;
|
||||
if (inputName) {
|
||||
var input = parentBlock.getInput(inputName);
|
||||
if (input) {
|
||||
parentConnection = input.connection;
|
||||
}
|
||||
} else if (connectionType == Blockly.connectionTypes.PREVIOUS_STATEMENT) {
|
||||
parentConnection = parentBlock.nextConnection;
|
||||
}
|
||||
if (parentConnection) {
|
||||
blockConnection.connect(parentConnection);
|
||||
} else {
|
||||
console.warn("Can't connect to non-existent input: " + inputName);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.CREATE,
|
||||
Blockly.Events.Create);
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.DELETE,
|
||||
Blockly.Events.Delete);
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.CHANGE,
|
||||
Blockly.Events.BlockChange);
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.MOVE,
|
||||
Blockly.Events.Move);
|
||||
@@ -11,19 +11,19 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Events.Abstract');
|
||||
goog.module('Blockly.Events.Abstract');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Events');
|
||||
|
||||
goog.requireType('Blockly.Workspace');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Workspace = goog.requireType('Blockly.Workspace');
|
||||
|
||||
|
||||
/**
|
||||
* Abstract class for an event.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.Abstract = function() {
|
||||
|
||||
const Abstract = function() {
|
||||
/**
|
||||
* Whether or not the event is blank (to be populated by fromJson).
|
||||
* @type {?boolean}
|
||||
@@ -42,29 +42,27 @@ Blockly.Events.Abstract = function() {
|
||||
* perspective, and should be undone together.
|
||||
* @type {string}
|
||||
*/
|
||||
this.group = Blockly.Events.getGroup();
|
||||
this.group = Events.getGroup();
|
||||
|
||||
/**
|
||||
* Sets whether the event should be added to the undo stack.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.recordUndo = Blockly.Events.recordUndo;
|
||||
this.recordUndo = Events.recordUndo;
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether or not the event is a UI event.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.Events.Abstract.prototype.isUiEvent = false;
|
||||
Abstract.prototype.isUiEvent = false;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.Abstract.prototype.toJson = function() {
|
||||
var json = {
|
||||
'type': this.type
|
||||
};
|
||||
Abstract.prototype.toJson = function() {
|
||||
const json = {'type': this.type};
|
||||
if (this.group) {
|
||||
json['group'] = this.group;
|
||||
}
|
||||
@@ -75,7 +73,7 @@ Blockly.Events.Abstract.prototype.toJson = function() {
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.Abstract.prototype.fromJson = function(json) {
|
||||
Abstract.prototype.fromJson = function(json) {
|
||||
this.isBlank = false;
|
||||
this.group = json['group'];
|
||||
};
|
||||
@@ -84,7 +82,7 @@ Blockly.Events.Abstract.prototype.fromJson = function(json) {
|
||||
* Does this event record any change of state?
|
||||
* @return {boolean} True if null, false if something changed.
|
||||
*/
|
||||
Blockly.Events.Abstract.prototype.isNull = function() {
|
||||
Abstract.prototype.isNull = function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -92,23 +90,27 @@ Blockly.Events.Abstract.prototype.isNull = function() {
|
||||
* Run an event.
|
||||
* @param {boolean} _forward True if run forward, false if run backward (undo).
|
||||
*/
|
||||
Blockly.Events.Abstract.prototype.run = function(_forward) {
|
||||
Abstract.prototype.run = function(_forward) {
|
||||
// Defined by subclasses.
|
||||
};
|
||||
|
||||
/**
|
||||
* Get workspace the event belongs to.
|
||||
* @return {!Blockly.Workspace} The workspace the event belongs to.
|
||||
* @return {!Workspace} The workspace the event belongs to.
|
||||
* @throws {Error} if workspace is null.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Events.Abstract.prototype.getEventWorkspace_ = function() {
|
||||
Abstract.prototype.getEventWorkspace_ = function() {
|
||||
let workspace;
|
||||
if (this.workspaceId) {
|
||||
var workspace = Blockly.Workspace.getById(this.workspaceId);
|
||||
workspace = goog.module.get('Blockly.Workspace').getById(this.workspaceId);
|
||||
}
|
||||
if (!workspace) {
|
||||
throw Error('Workspace is null. Event must have been generated from real' +
|
||||
throw Error(
|
||||
'Workspace is null. Event must have been generated from real' +
|
||||
' Blockly events.');
|
||||
}
|
||||
return workspace;
|
||||
};
|
||||
|
||||
exports = Abstract;
|
||||
|
||||
66
core/events/events_block_base.js
Normal file
66
core/events/events_block_base.js
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2018 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Base class for all types of block events.
|
||||
* @author fenichel@google.com (Rachel Fenichel)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.Events.BlockBase');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
const Abstract = goog.require('Blockly.Events.Abstract');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
|
||||
|
||||
/**
|
||||
* Abstract class for a block event.
|
||||
* @param {!Block=} opt_block The block this event corresponds to.
|
||||
* Undefined for a blank event.
|
||||
* @extends {Abstract}
|
||||
* @constructor
|
||||
*/
|
||||
const BlockBase = function(opt_block) {
|
||||
BlockBase.superClass_.constructor.call(this);
|
||||
this.isBlank = typeof opt_block == 'undefined';
|
||||
|
||||
/**
|
||||
* The block ID for the block this event pertains to
|
||||
* @type {string}
|
||||
*/
|
||||
this.blockId = this.isBlank ? '' : opt_block.id;
|
||||
|
||||
/**
|
||||
* The workspace identifier for this event.
|
||||
* @type {string}
|
||||
*/
|
||||
this.workspaceId = this.isBlank ? '' : opt_block.workspace.id;
|
||||
};
|
||||
object.inherits(BlockBase, Abstract);
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
BlockBase.prototype.toJson = function() {
|
||||
const json = BlockBase.superClass_.toJson.call(this);
|
||||
json['blockId'] = this.blockId;
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
BlockBase.prototype.fromJson = function(json) {
|
||||
BlockBase.superClass_.fromJson.call(this, json);
|
||||
this.blockId = json['blockId'];
|
||||
};
|
||||
|
||||
exports = BlockBase;
|
||||
148
core/events/events_block_change.js
Normal file
148
core/events/events_block_change.js
Normal file
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2018 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Class for a block change event.
|
||||
* @author fenichel@google.com (Rachel Fenichel)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.Events.BlockChange');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const Xml = goog.require('Blockly.Xml');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a block change event.
|
||||
* @param {!Block=} opt_block The changed block. Undefined for a blank
|
||||
* event.
|
||||
* @param {string=} opt_element One of 'field', 'comment', 'disabled', etc.
|
||||
* @param {?string=} opt_name Name of input or field affected, or null.
|
||||
* @param {*=} opt_oldValue Previous value of element.
|
||||
* @param {*=} opt_newValue New value of element.
|
||||
* @extends {Events.BlockBase}
|
||||
* @constructor
|
||||
*/
|
||||
const BlockChange = function(
|
||||
opt_block, opt_element, opt_name, opt_oldValue, opt_newValue) {
|
||||
BlockChange.superClass_.constructor.call(this, opt_block);
|
||||
if (!opt_block) {
|
||||
return; // Blank event to be populated by fromJson.
|
||||
}
|
||||
this.element = typeof opt_element == 'undefined' ? '' : opt_element;
|
||||
this.name = typeof opt_name == 'undefined' ? '' : opt_name;
|
||||
this.oldValue = typeof opt_oldValue == 'undefined' ? '' : opt_oldValue;
|
||||
this.newValue = typeof opt_newValue == 'undefined' ? '' : opt_newValue;
|
||||
};
|
||||
object.inherits(BlockChange, Events.BlockBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
BlockChange.prototype.type = Events.BLOCK_CHANGE;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
BlockChange.prototype.toJson = function() {
|
||||
const json = BlockChange.superClass_.toJson.call(this);
|
||||
json['element'] = this.element;
|
||||
if (this.name) {
|
||||
json['name'] = this.name;
|
||||
}
|
||||
json['oldValue'] = this.oldValue;
|
||||
json['newValue'] = this.newValue;
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
BlockChange.prototype.fromJson = function(json) {
|
||||
BlockChange.superClass_.fromJson.call(this, json);
|
||||
this.element = json['element'];
|
||||
this.name = json['name'];
|
||||
this.oldValue = json['oldValue'];
|
||||
this.newValue = json['newValue'];
|
||||
};
|
||||
|
||||
/**
|
||||
* Does this event record any change of state?
|
||||
* @return {boolean} False if something changed.
|
||||
*/
|
||||
BlockChange.prototype.isNull = function() {
|
||||
return this.oldValue == this.newValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Run a change event.
|
||||
* @param {boolean} forward True if run forward, false if run backward (undo).
|
||||
*/
|
||||
BlockChange.prototype.run = function(forward) {
|
||||
const workspace = this.getEventWorkspace_();
|
||||
const block = workspace.getBlockById(this.blockId);
|
||||
if (!block) {
|
||||
console.warn('Can\'t change non-existent block: ' + this.blockId);
|
||||
return;
|
||||
}
|
||||
if (block.mutator) {
|
||||
// Close the mutator (if open) since we don't want to update it.
|
||||
block.mutator.setVisible(false);
|
||||
}
|
||||
const value = forward ? this.newValue : this.oldValue;
|
||||
switch (this.element) {
|
||||
case 'field': {
|
||||
const field = block.getField(this.name);
|
||||
if (field) {
|
||||
field.setValue(value);
|
||||
} else {
|
||||
console.warn('Can\'t set non-existent field: ' + this.name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'comment':
|
||||
block.setCommentText(/** @type {string} */ (value) || null);
|
||||
break;
|
||||
case 'collapsed':
|
||||
block.setCollapsed(!!value);
|
||||
break;
|
||||
case 'disabled':
|
||||
block.setEnabled(!value);
|
||||
break;
|
||||
case 'inline':
|
||||
block.setInputsInline(!!value);
|
||||
break;
|
||||
case 'mutation': {
|
||||
let oldMutation = '';
|
||||
if (block.mutationToDom) {
|
||||
const oldMutationDom = block.mutationToDom();
|
||||
oldMutation = oldMutationDom && Xml.domToText(oldMutationDom);
|
||||
}
|
||||
if (block.domToMutation) {
|
||||
const dom = Xml.textToDom(/** @type {string} */
|
||||
(value) || '<mutation/>');
|
||||
block.domToMutation(dom);
|
||||
}
|
||||
Events.fire(new BlockChange(block, 'mutation', null, oldMutation, value));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console.warn('Unknown change type: ' + this.element);
|
||||
}
|
||||
};
|
||||
|
||||
registry.register(registry.Type.EVENT, Events.CHANGE, BlockChange);
|
||||
|
||||
exports = BlockChange;
|
||||
111
core/events/events_block_create.js
Normal file
111
core/events/events_block_create.js
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2018 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Class for a block creation event.
|
||||
* @author fenichel@google.com (Rachel Fenichel)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.Events.BlockCreate');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
const BlockBase = goog.require('Blockly.Events.BlockBase');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const Xml = goog.require('Blockly.Xml');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
const xml = goog.require('Blockly.utils.xml');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a block creation event.
|
||||
* @param {!Block=} opt_block The created block. Undefined for a blank
|
||||
* event.
|
||||
* @extends {BlockBase}
|
||||
* @constructor
|
||||
*/
|
||||
const BlockCreate = function(opt_block) {
|
||||
BlockCreate.superClass_.constructor.call(this, opt_block);
|
||||
if (!opt_block) {
|
||||
return; // Blank event to be populated by fromJson.
|
||||
}
|
||||
if (opt_block.isShadow()) {
|
||||
// Moving shadow blocks is handled via disconnection.
|
||||
this.recordUndo = false;
|
||||
}
|
||||
|
||||
if (opt_block.workspace.rendered) {
|
||||
this.xml = Xml.blockToDomWithXY(opt_block);
|
||||
} else {
|
||||
this.xml = Xml.blockToDom(opt_block);
|
||||
}
|
||||
this.ids = Events.getDescendantIds(opt_block);
|
||||
};
|
||||
object.inherits(BlockCreate, BlockBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
BlockCreate.prototype.type = Events.BLOCK_CREATE;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
BlockCreate.prototype.toJson = function() {
|
||||
const json = BlockCreate.superClass_.toJson.call(this);
|
||||
json['xml'] = Xml.domToText(this.xml);
|
||||
json['ids'] = this.ids;
|
||||
if (!this.recordUndo) {
|
||||
json['recordUndo'] = this.recordUndo;
|
||||
}
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
BlockCreate.prototype.fromJson = function(json) {
|
||||
BlockCreate.superClass_.fromJson.call(this, json);
|
||||
this.xml = Xml.textToDom(json['xml']);
|
||||
this.ids = json['ids'];
|
||||
if (json['recordUndo'] !== undefined) {
|
||||
this.recordUndo = json['recordUndo'];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Run a creation event.
|
||||
* @param {boolean} forward True if run forward, false if run backward (undo).
|
||||
*/
|
||||
BlockCreate.prototype.run = function(forward) {
|
||||
const workspace = this.getEventWorkspace_();
|
||||
if (forward) {
|
||||
const xmlEl = xml.createElement('xml');
|
||||
xmlEl.appendChild(this.xml);
|
||||
Xml.domToWorkspace(xmlEl, workspace);
|
||||
} else {
|
||||
for (let i = 0; i < this.ids.length; i++) {
|
||||
const id = this.ids[i];
|
||||
const block = workspace.getBlockById(id);
|
||||
if (block) {
|
||||
block.dispose(false);
|
||||
} else if (id == this.blockId) {
|
||||
// Only complain about root-level block.
|
||||
console.warn('Can\'t uncreate non-existent block: ' + id);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
registry.register(registry.Type.EVENT, Events.CREATE, BlockCreate);
|
||||
|
||||
exports = BlockCreate;
|
||||
114
core/events/events_block_delete.js
Normal file
114
core/events/events_block_delete.js
Normal file
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2018 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Class for a block delete event.
|
||||
* @author fenichel@google.com (Rachel Fenichel)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.Events.BlockDelete');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
const BlockBase = goog.require('Blockly.Events.BlockBase');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const Xml = goog.require('Blockly.Xml');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
const xml = goog.require('Blockly.utils.xml');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a block deletion event.
|
||||
* @param {!Block=} opt_block The deleted block. Undefined for a blank
|
||||
* event.
|
||||
* @extends {BlockBase}
|
||||
* @constructor
|
||||
*/
|
||||
const BlockDelete = function(opt_block) {
|
||||
BlockDelete.superClass_.constructor.call(this, opt_block);
|
||||
if (!opt_block) {
|
||||
return; // Blank event to be populated by fromJson.
|
||||
}
|
||||
if (opt_block.getParent()) {
|
||||
throw Error('Connected blocks cannot be deleted.');
|
||||
}
|
||||
if (opt_block.isShadow()) {
|
||||
// Respawning shadow blocks is handled via disconnection.
|
||||
this.recordUndo = false;
|
||||
}
|
||||
|
||||
if (opt_block.workspace.rendered) {
|
||||
this.oldXml = Xml.blockToDomWithXY(opt_block);
|
||||
} else {
|
||||
this.oldXml = Xml.blockToDom(opt_block);
|
||||
}
|
||||
this.ids = Events.getDescendantIds(opt_block);
|
||||
};
|
||||
object.inherits(BlockDelete, BlockBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
BlockDelete.prototype.type = Events.BLOCK_DELETE;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
BlockDelete.prototype.toJson = function() {
|
||||
const json = BlockDelete.superClass_.toJson.call(this);
|
||||
json['oldXml'] = Xml.domToText(this.oldXml);
|
||||
json['ids'] = this.ids;
|
||||
if (!this.recordUndo) {
|
||||
json['recordUndo'] = this.recordUndo;
|
||||
}
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
BlockDelete.prototype.fromJson = function(json) {
|
||||
BlockDelete.superClass_.fromJson.call(this, json);
|
||||
this.oldXml = Xml.textToDom(json['oldXml']);
|
||||
this.ids = json['ids'];
|
||||
if (json['recordUndo'] !== undefined) {
|
||||
this.recordUndo = json['recordUndo'];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Run a deletion event.
|
||||
* @param {boolean} forward True if run forward, false if run backward (undo).
|
||||
*/
|
||||
BlockDelete.prototype.run = function(forward) {
|
||||
const workspace = this.getEventWorkspace_();
|
||||
if (forward) {
|
||||
for (let i = 0; i < this.ids.length; i++) {
|
||||
const id = this.ids[i];
|
||||
const block = workspace.getBlockById(id);
|
||||
if (block) {
|
||||
block.dispose(false);
|
||||
} else if (id == this.blockId) {
|
||||
// Only complain about root-level block.
|
||||
console.warn('Can\'t delete non-existent block: ' + id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const xmlEl = xml.createElement('xml');
|
||||
xmlEl.appendChild(this.oldXml);
|
||||
Xml.domToWorkspace(xmlEl, workspace);
|
||||
}
|
||||
};
|
||||
|
||||
registry.register(registry.Type.EVENT, Events.DELETE, BlockDelete);
|
||||
|
||||
exports = BlockDelete;
|
||||
@@ -10,30 +10,31 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Events.BlockDrag');
|
||||
goog.module('Blockly.Events.BlockDrag');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.Events.UiBase');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.utils.object');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const UiBase = goog.require('Blockly.Events.UiBase');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a block drag event.
|
||||
* @param {!Blockly.Block=} opt_block The top block in the stack that is being
|
||||
* @param {!Block=} opt_block The top block in the stack that is being
|
||||
* dragged. Undefined for a blank event.
|
||||
* @param {boolean=} opt_isStart Whether this is the start of a block drag.
|
||||
* Undefined for a blank event.
|
||||
* @param {!Array<!Blockly.Block>=} opt_blocks The blocks affected by this
|
||||
* @param {!Array<!Block>=} opt_blocks The blocks affected by this
|
||||
* drag. Undefined for a blank event.
|
||||
* @extends {Blockly.Events.UiBase}
|
||||
* @extends {UiBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.BlockDrag = function(opt_block, opt_isStart, opt_blocks) {
|
||||
var workspaceId = opt_block ? opt_block.workspace.id : undefined;
|
||||
Blockly.Events.BlockDrag.superClass_.constructor.call(this, workspaceId);
|
||||
const BlockDrag = function(opt_block, opt_isStart, opt_blocks) {
|
||||
const workspaceId = opt_block ? opt_block.workspace.id : undefined;
|
||||
BlockDrag.superClass_.constructor.call(this, workspaceId);
|
||||
this.blockId = opt_block ? opt_block.id : null;
|
||||
|
||||
/**
|
||||
@@ -44,24 +45,24 @@ Blockly.Events.BlockDrag = function(opt_block, opt_isStart, opt_blocks) {
|
||||
|
||||
/**
|
||||
* The blocks affected by this drag event.
|
||||
* @type {!Array<!Blockly.Block>|undefined}
|
||||
* @type {!Array<!Block>|undefined}
|
||||
*/
|
||||
this.blocks = opt_blocks;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.BlockDrag, Blockly.Events.UiBase);
|
||||
object.inherits(BlockDrag, UiBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.BlockDrag.prototype.type = Blockly.Events.BLOCK_DRAG;
|
||||
BlockDrag.prototype.type = Events.BLOCK_DRAG;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.BlockDrag.prototype.toJson = function() {
|
||||
var json = Blockly.Events.BlockDrag.superClass_.toJson.call(this);
|
||||
BlockDrag.prototype.toJson = function() {
|
||||
const json = BlockDrag.superClass_.toJson.call(this);
|
||||
json['isStart'] = this.isStart;
|
||||
json['blockId'] = this.blockId;
|
||||
json['blocks'] = this.blocks;
|
||||
@@ -72,12 +73,13 @@ Blockly.Events.BlockDrag.prototype.toJson = function() {
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.BlockDrag.prototype.fromJson = function(json) {
|
||||
Blockly.Events.BlockDrag.superClass_.fromJson.call(this, json);
|
||||
BlockDrag.prototype.fromJson = function(json) {
|
||||
BlockDrag.superClass_.fromJson.call(this, json);
|
||||
this.isStart = json['isStart'];
|
||||
this.blockId = json['blockId'];
|
||||
this.blocks = json['blocks'];
|
||||
};
|
||||
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT,
|
||||
Blockly.Events.BLOCK_DRAG, Blockly.Events.BlockDrag);
|
||||
registry.register(registry.Type.EVENT, Events.BLOCK_DRAG, BlockDrag);
|
||||
|
||||
exports = BlockDrag;
|
||||
|
||||
188
core/events/events_block_move.js
Normal file
188
core/events/events_block_move.js
Normal file
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2018 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Class for a block move event.
|
||||
* @author fenichel@google.com (Rachel Fenichel)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.Events.BlockMove');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
const BlockBase = goog.require('Blockly.Events.BlockBase');
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const connectionTypes = goog.require('Blockly.connectionTypes');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a block move event. Created before the move.
|
||||
* @param {!Block=} opt_block The moved block. Undefined for a blank
|
||||
* event.
|
||||
* @extends {BlockBase}
|
||||
* @constructor
|
||||
*/
|
||||
const BlockMove = function(opt_block) {
|
||||
BlockMove.superClass_.constructor.call(this, opt_block);
|
||||
if (!opt_block) {
|
||||
return; // Blank event to be populated by fromJson.
|
||||
}
|
||||
if (opt_block.isShadow()) {
|
||||
// Moving shadow blocks is handled via disconnection.
|
||||
this.recordUndo = false;
|
||||
}
|
||||
|
||||
const location = this.currentLocation_();
|
||||
this.oldParentId = location.parentId;
|
||||
this.oldInputName = location.inputName;
|
||||
this.oldCoordinate = location.coordinate;
|
||||
};
|
||||
object.inherits(BlockMove, BlockBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
BlockMove.prototype.type = Events.BLOCK_MOVE;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
BlockMove.prototype.toJson = function() {
|
||||
const json = BlockMove.superClass_.toJson.call(this);
|
||||
if (this.newParentId) {
|
||||
json['newParentId'] = this.newParentId;
|
||||
}
|
||||
if (this.newInputName) {
|
||||
json['newInputName'] = this.newInputName;
|
||||
}
|
||||
if (this.newCoordinate) {
|
||||
json['newCoordinate'] = Math.round(this.newCoordinate.x) + ',' +
|
||||
Math.round(this.newCoordinate.y);
|
||||
}
|
||||
if (!this.recordUndo) {
|
||||
json['recordUndo'] = this.recordUndo;
|
||||
}
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
BlockMove.prototype.fromJson = function(json) {
|
||||
BlockMove.superClass_.fromJson.call(this, json);
|
||||
this.newParentId = json['newParentId'];
|
||||
this.newInputName = json['newInputName'];
|
||||
if (json['newCoordinate']) {
|
||||
const xy = json['newCoordinate'].split(',');
|
||||
this.newCoordinate = new Coordinate(Number(xy[0]), Number(xy[1]));
|
||||
}
|
||||
if (json['recordUndo'] !== undefined) {
|
||||
this.recordUndo = json['recordUndo'];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Record the block's new location. Called after the move.
|
||||
*/
|
||||
BlockMove.prototype.recordNew = function() {
|
||||
const location = this.currentLocation_();
|
||||
this.newParentId = location.parentId;
|
||||
this.newInputName = location.inputName;
|
||||
this.newCoordinate = location.coordinate;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the parentId and input if the block is connected,
|
||||
* or the XY location if disconnected.
|
||||
* @return {!Object} Collection of location info.
|
||||
* @private
|
||||
*/
|
||||
BlockMove.prototype.currentLocation_ = function() {
|
||||
const workspace = this.getEventWorkspace_();
|
||||
const block = workspace.getBlockById(this.blockId);
|
||||
const location = {};
|
||||
const parent = block.getParent();
|
||||
if (parent) {
|
||||
location.parentId = parent.id;
|
||||
const input = parent.getInputWithBlock(block);
|
||||
if (input) {
|
||||
location.inputName = input.name;
|
||||
}
|
||||
} else {
|
||||
location.coordinate = block.getRelativeToSurfaceXY();
|
||||
}
|
||||
return location;
|
||||
};
|
||||
|
||||
/**
|
||||
* Does this event record any change of state?
|
||||
* @return {boolean} False if something changed.
|
||||
*/
|
||||
BlockMove.prototype.isNull = function() {
|
||||
return this.oldParentId == this.newParentId &&
|
||||
this.oldInputName == this.newInputName &&
|
||||
Coordinate.equals(this.oldCoordinate, this.newCoordinate);
|
||||
};
|
||||
|
||||
/**
|
||||
* Run a move event.
|
||||
* @param {boolean} forward True if run forward, false if run backward (undo).
|
||||
*/
|
||||
BlockMove.prototype.run = function(forward) {
|
||||
const workspace = this.getEventWorkspace_();
|
||||
const block = workspace.getBlockById(this.blockId);
|
||||
if (!block) {
|
||||
console.warn('Can\'t move non-existent block: ' + this.blockId);
|
||||
return;
|
||||
}
|
||||
const parentId = forward ? this.newParentId : this.oldParentId;
|
||||
const inputName = forward ? this.newInputName : this.oldInputName;
|
||||
const coordinate = forward ? this.newCoordinate : this.oldCoordinate;
|
||||
let parentBlock;
|
||||
if (parentId) {
|
||||
parentBlock = workspace.getBlockById(parentId);
|
||||
if (!parentBlock) {
|
||||
console.warn('Can\'t connect to non-existent block: ' + parentId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (block.getParent()) {
|
||||
block.unplug();
|
||||
}
|
||||
if (coordinate) {
|
||||
const xy = block.getRelativeToSurfaceXY();
|
||||
block.moveBy(coordinate.x - xy.x, coordinate.y - xy.y);
|
||||
} else {
|
||||
const blockConnection = block.outputConnection || block.previousConnection;
|
||||
let parentConnection;
|
||||
const connectionType = blockConnection.type;
|
||||
if (inputName) {
|
||||
const input = parentBlock.getInput(inputName);
|
||||
if (input) {
|
||||
parentConnection = input.connection;
|
||||
}
|
||||
} else if (connectionType == connectionTypes.PREVIOUS_STATEMENT) {
|
||||
parentConnection = parentBlock.nextConnection;
|
||||
}
|
||||
if (parentConnection) {
|
||||
blockConnection.connect(parentConnection);
|
||||
} else {
|
||||
console.warn('Can\'t connect to non-existent input: ' + inputName);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
registry.register(registry.Type.EVENT, Events.MOVE, BlockMove);
|
||||
|
||||
exports = BlockMove;
|
||||
@@ -10,30 +10,32 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Events.BubbleOpen');
|
||||
goog.module('Blockly.Events.BubbleOpen');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.Events.UiBase');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.utils.object');
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const UiBase = goog.require('Blockly.Events.UiBase');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a bubble open event.
|
||||
* @param {Blockly.BlockSvg} opt_block The associated block. Undefined for a
|
||||
* @param {BlockSvg} opt_block The associated block. Undefined for a
|
||||
* blank event.
|
||||
* @param {boolean=} opt_isOpen Whether the bubble is opening (false if
|
||||
* closing). Undefined for a blank event.
|
||||
* @param {string=} opt_bubbleType The type of bubble. One of 'mutator', 'comment'
|
||||
* @param {string=} opt_bubbleType The type of bubble. One of 'mutator',
|
||||
* 'comment'
|
||||
* or 'warning'. Undefined for a blank event.
|
||||
* @extends {Blockly.Events.UiBase}
|
||||
* @extends {UiBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.BubbleOpen = function(opt_block, opt_isOpen, opt_bubbleType) {
|
||||
var workspaceId = opt_block ? opt_block.workspace.id : undefined;
|
||||
Blockly.Events.BubbleOpen.superClass_.constructor.call(this, workspaceId);
|
||||
const BubbleOpen = function(opt_block, opt_isOpen, opt_bubbleType) {
|
||||
const workspaceId = opt_block ? opt_block.workspace.id : undefined;
|
||||
BubbleOpen.superClass_.constructor.call(this, workspaceId);
|
||||
this.blockId = opt_block ? opt_block.id : null;
|
||||
|
||||
/**
|
||||
@@ -48,20 +50,20 @@ Blockly.Events.BubbleOpen = function(opt_block, opt_isOpen, opt_bubbleType) {
|
||||
*/
|
||||
this.bubbleType = opt_bubbleType;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.BubbleOpen, Blockly.Events.UiBase);
|
||||
object.inherits(BubbleOpen, UiBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.BubbleOpen.prototype.type = Blockly.Events.BUBBLE_OPEN;
|
||||
BubbleOpen.prototype.type = Events.BUBBLE_OPEN;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.BubbleOpen.prototype.toJson = function() {
|
||||
var json = Blockly.Events.BubbleOpen.superClass_.toJson.call(this);
|
||||
BubbleOpen.prototype.toJson = function() {
|
||||
const json = BubbleOpen.superClass_.toJson.call(this);
|
||||
json['isOpen'] = this.isOpen;
|
||||
json['bubbleType'] = this.bubbleType;
|
||||
json['blockId'] = this.blockId;
|
||||
@@ -72,12 +74,13 @@ Blockly.Events.BubbleOpen.prototype.toJson = function() {
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.BubbleOpen.prototype.fromJson = function(json) {
|
||||
Blockly.Events.BubbleOpen.superClass_.fromJson.call(this, json);
|
||||
BubbleOpen.prototype.fromJson = function(json) {
|
||||
BubbleOpen.superClass_.fromJson.call(this, json);
|
||||
this.isOpen = json['isOpen'];
|
||||
this.bubbleType = json['bubbleType'];
|
||||
this.blockId = json['blockId'];
|
||||
};
|
||||
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT,
|
||||
Blockly.Events.BUBBLE_OPEN, Blockly.Events.BubbleOpen);
|
||||
registry.register(registry.Type.EVENT, Events.BUBBLE_OPEN, BubbleOpen);
|
||||
|
||||
exports = BubbleOpen;
|
||||
|
||||
@@ -10,31 +10,31 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Events.Click');
|
||||
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.Events.UiBase');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.utils.object');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
goog.module('Blockly.Events.Click');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const UiBase = goog.require('Blockly.Events.UiBase');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
/**
|
||||
* Class for a click event.
|
||||
* @param {?Blockly.Block=} opt_block The affected block. Null for click events
|
||||
* @param {?Block=} opt_block The affected block. Null for click events
|
||||
* that do not have an associated block (i.e. workspace click). Undefined
|
||||
* for a blank event.
|
||||
* @param {?string=} opt_workspaceId The workspace identifier for this event.
|
||||
* Not used if block is passed. Undefined for a blank event.
|
||||
* @param {string=} opt_targetType The type of element targeted by this click
|
||||
* event. Undefined for a blank event.
|
||||
* @extends {Blockly.Events.UiBase}
|
||||
* @extends {UiBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.Click = function(opt_block, opt_workspaceId, opt_targetType) {
|
||||
var workspaceId = opt_block ? opt_block.workspace.id : opt_workspaceId;
|
||||
Blockly.Events.Click.superClass_.constructor.call(this, workspaceId);
|
||||
const Click = function(opt_block, opt_workspaceId, opt_targetType) {
|
||||
const workspaceId = opt_block ? opt_block.workspace.id : opt_workspaceId;
|
||||
Click.superClass_.constructor.call(this, workspaceId);
|
||||
this.blockId = opt_block ? opt_block.id : null;
|
||||
|
||||
/**
|
||||
@@ -43,20 +43,20 @@ Blockly.Events.Click = function(opt_block, opt_workspaceId, opt_targetType) {
|
||||
*/
|
||||
this.targetType = opt_targetType;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.Click, Blockly.Events.UiBase);
|
||||
object.inherits(Click, UiBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.Click.prototype.type = Blockly.Events.CLICK;
|
||||
Click.prototype.type = Events.CLICK;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.Click.prototype.toJson = function() {
|
||||
var json = Blockly.Events.Click.superClass_.toJson.call(this);
|
||||
Click.prototype.toJson = function() {
|
||||
const json = Click.superClass_.toJson.call(this);
|
||||
json['targetType'] = this.targetType;
|
||||
if (this.blockId) {
|
||||
json['blockId'] = this.blockId;
|
||||
@@ -68,11 +68,12 @@ Blockly.Events.Click.prototype.toJson = function() {
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.Click.prototype.fromJson = function(json) {
|
||||
Blockly.Events.Click.superClass_.fromJson.call(this, json);
|
||||
Click.prototype.fromJson = function(json) {
|
||||
Click.superClass_.fromJson.call(this, json);
|
||||
this.targetType = json['targetType'];
|
||||
this.blockId = json['blockId'];
|
||||
};
|
||||
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.CLICK,
|
||||
Blockly.Events.Click);
|
||||
registry.register(registry.Type.EVENT, Events.CLICK, Click);
|
||||
|
||||
exports = Click;
|
||||
|
||||
@@ -10,39 +10,39 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Events.MarkerMove');
|
||||
goog.module('Blockly.Events.MarkerMove');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.Events.UiBase');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.utils.object');
|
||||
|
||||
goog.requireType('Blockly.ASTNode');
|
||||
goog.requireType('Blockly.Block');
|
||||
goog.requireType('Blockly.Workspace');
|
||||
const ASTNode = goog.require('Blockly.ASTNode');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const UiBase = goog.require('Blockly.Events.UiBase');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Workspace = goog.requireType('Blockly.Workspace');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a marker move event.
|
||||
* @param {?Blockly.Block=} opt_block The affected block. Null if current node
|
||||
* @param {?Block=} opt_block The affected block. Null if current node
|
||||
* is of type workspace. Undefined for a blank event.
|
||||
* @param {boolean=} isCursor Whether this is a cursor event. Undefined for a
|
||||
* blank event.
|
||||
* @param {?Blockly.ASTNode=} opt_oldNode The old node the marker used to be on.
|
||||
* @param {?ASTNode=} opt_oldNode The old node the marker used to be on.
|
||||
* Undefined for a blank event.
|
||||
* @param {!Blockly.ASTNode=} opt_newNode The new node the marker is now on.
|
||||
* @param {!ASTNode=} opt_newNode The new node the marker is now on.
|
||||
* Undefined for a blank event.
|
||||
* @extends {Blockly.Events.UiBase}
|
||||
* @extends {UiBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.MarkerMove = function(opt_block, isCursor, opt_oldNode,
|
||||
opt_newNode) {
|
||||
var workspaceId = opt_block ? opt_block.workspace.id : undefined;
|
||||
if (opt_newNode && opt_newNode.getType() == Blockly.ASTNode.types.WORKSPACE) {
|
||||
workspaceId =
|
||||
(/** @type {!Blockly.Workspace} */ (opt_newNode.getLocation())).id;
|
||||
const MarkerMove = function(opt_block, isCursor, opt_oldNode, opt_newNode) {
|
||||
let workspaceId = opt_block ? opt_block.workspace.id : undefined;
|
||||
if (opt_newNode && opt_newNode.getType() == ASTNode.types.WORKSPACE) {
|
||||
workspaceId = (/** @type {!Workspace} */ (opt_newNode.getLocation())).id;
|
||||
}
|
||||
Blockly.Events.MarkerMove.superClass_.constructor.call(this, workspaceId);
|
||||
MarkerMove.superClass_.constructor.call(this, workspaceId);
|
||||
|
||||
/**
|
||||
* The workspace identifier for this event.
|
||||
@@ -52,13 +52,13 @@ Blockly.Events.MarkerMove = function(opt_block, isCursor, opt_oldNode,
|
||||
|
||||
/**
|
||||
* The old node the marker used to be on.
|
||||
* @type {?Blockly.ASTNode|undefined}
|
||||
* @type {?ASTNode|undefined}
|
||||
*/
|
||||
this.oldNode = opt_oldNode;
|
||||
|
||||
/**
|
||||
* The new node the marker is now on.
|
||||
* @type {Blockly.ASTNode|undefined}
|
||||
* @type {ASTNode|undefined}
|
||||
*/
|
||||
this.newNode = opt_newNode;
|
||||
|
||||
@@ -68,20 +68,20 @@ Blockly.Events.MarkerMove = function(opt_block, isCursor, opt_oldNode,
|
||||
*/
|
||||
this.isCursor = isCursor;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.MarkerMove, Blockly.Events.UiBase);
|
||||
object.inherits(MarkerMove, UiBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.MarkerMove.prototype.type = Blockly.Events.MARKER_MOVE;
|
||||
MarkerMove.prototype.type = Events.MARKER_MOVE;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.MarkerMove.prototype.toJson = function() {
|
||||
var json = Blockly.Events.MarkerMove.superClass_.toJson.call(this);
|
||||
MarkerMove.prototype.toJson = function() {
|
||||
const json = MarkerMove.superClass_.toJson.call(this);
|
||||
json['isCursor'] = this.isCursor;
|
||||
json['blockId'] = this.blockId;
|
||||
json['oldNode'] = this.oldNode;
|
||||
@@ -93,13 +93,14 @@ Blockly.Events.MarkerMove.prototype.toJson = function() {
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.MarkerMove.prototype.fromJson = function(json) {
|
||||
Blockly.Events.MarkerMove.superClass_.fromJson.call(this, json);
|
||||
MarkerMove.prototype.fromJson = function(json) {
|
||||
MarkerMove.superClass_.fromJson.call(this, json);
|
||||
this.isCursor = json['isCursor'];
|
||||
this.blockId = json['blockId'];
|
||||
this.oldNode = json['oldNode'];
|
||||
this.newNode = json['newNode'];
|
||||
};
|
||||
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT,
|
||||
Blockly.Events.MARKER_MOVE, Blockly.Events.MarkerMove);
|
||||
registry.register(registry.Type.EVENT, Events.MARKER_MOVE, MarkerMove);
|
||||
|
||||
exports = MarkerMove;
|
||||
|
||||
@@ -10,12 +10,13 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Events.Selected');
|
||||
goog.module('Blockly.Events.Selected');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.Events.UiBase');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.utils.object');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const UiBase = goog.require('Blockly.Events.UiBase');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
@@ -26,12 +27,11 @@ goog.require('Blockly.utils.object');
|
||||
* element currently selected (deselect). Undefined for a blank event.
|
||||
* @param {string=} opt_workspaceId The workspace identifier for this event.
|
||||
* Null if no element previously selected. Undefined for a blank event.
|
||||
* @extends {Blockly.Events.UiBase}
|
||||
* @extends {UiBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.Selected = function(opt_oldElementId, opt_newElementId,
|
||||
opt_workspaceId) {
|
||||
Blockly.Events.Selected.superClass_.constructor.call(this, opt_workspaceId);
|
||||
const Selected = function(opt_oldElementId, opt_newElementId, opt_workspaceId) {
|
||||
Selected.superClass_.constructor.call(this, opt_workspaceId);
|
||||
|
||||
/**
|
||||
* The id of the last selected element.
|
||||
@@ -45,20 +45,20 @@ Blockly.Events.Selected = function(opt_oldElementId, opt_newElementId,
|
||||
*/
|
||||
this.newElementId = opt_newElementId;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.Selected, Blockly.Events.UiBase);
|
||||
object.inherits(Selected, UiBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.Selected.prototype.type = Blockly.Events.SELECTED;
|
||||
Selected.prototype.type = Events.SELECTED;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.Selected.prototype.toJson = function() {
|
||||
var json = Blockly.Events.Selected.superClass_.toJson.call(this);
|
||||
Selected.prototype.toJson = function() {
|
||||
const json = Selected.superClass_.toJson.call(this);
|
||||
json['oldElementId'] = this.oldElementId;
|
||||
json['newElementId'] = this.newElementId;
|
||||
return json;
|
||||
@@ -68,11 +68,12 @@ Blockly.Events.Selected.prototype.toJson = function() {
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.Selected.prototype.fromJson = function(json) {
|
||||
Blockly.Events.Selected.superClass_.fromJson.call(this, json);
|
||||
Selected.prototype.fromJson = function(json) {
|
||||
Selected.superClass_.fromJson.call(this, json);
|
||||
this.oldElementId = json['oldElementId'];
|
||||
this.newElementId = json['newElementId'];
|
||||
};
|
||||
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.SELECTED,
|
||||
Blockly.Events.Selected);
|
||||
registry.register(registry.Type.EVENT, Events.SELECTED, Selected);
|
||||
|
||||
exports = Selected;
|
||||
|
||||
@@ -10,12 +10,13 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Events.ThemeChange');
|
||||
goog.module('Blockly.Events.ThemeChange');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.Events.UiBase');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.utils.object');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const UiBase = goog.require('Blockly.Events.UiBase');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
@@ -23,11 +24,11 @@ goog.require('Blockly.utils.object');
|
||||
* @param {string=} opt_themeName The theme name. Undefined for a blank event.
|
||||
* @param {string=} opt_workspaceId The workspace identifier for this event.
|
||||
* event. Undefined for a blank event.
|
||||
* @extends {Blockly.Events.UiBase}
|
||||
* @extends {UiBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.ThemeChange = function(opt_themeName, opt_workspaceId) {
|
||||
Blockly.Events.ThemeChange.superClass_.constructor.call(this, opt_workspaceId);
|
||||
const ThemeChange = function(opt_themeName, opt_workspaceId) {
|
||||
ThemeChange.superClass_.constructor.call(this, opt_workspaceId);
|
||||
|
||||
/**
|
||||
* The theme name.
|
||||
@@ -35,20 +36,20 @@ Blockly.Events.ThemeChange = function(opt_themeName, opt_workspaceId) {
|
||||
*/
|
||||
this.themeName = opt_themeName;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.ThemeChange, Blockly.Events.UiBase);
|
||||
object.inherits(ThemeChange, UiBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.ThemeChange.prototype.type = Blockly.Events.THEME_CHANGE;
|
||||
ThemeChange.prototype.type = Events.THEME_CHANGE;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.ThemeChange.prototype.toJson = function() {
|
||||
var json = Blockly.Events.ThemeChange.superClass_.toJson.call(this);
|
||||
ThemeChange.prototype.toJson = function() {
|
||||
const json = ThemeChange.superClass_.toJson.call(this);
|
||||
json['themeName'] = this.themeName;
|
||||
return json;
|
||||
};
|
||||
@@ -57,10 +58,11 @@ Blockly.Events.ThemeChange.prototype.toJson = function() {
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.ThemeChange.prototype.fromJson = function(json) {
|
||||
Blockly.Events.ThemeChange.superClass_.fromJson.call(this, json);
|
||||
ThemeChange.prototype.fromJson = function(json) {
|
||||
ThemeChange.superClass_.fromJson.call(this, json);
|
||||
this.themeName = json['themeName'];
|
||||
};
|
||||
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT,
|
||||
Blockly.Events.THEME_CHANGE, Blockly.Events.ThemeChange);
|
||||
registry.register(registry.Type.EVENT, Events.THEME_CHANGE, ThemeChange);
|
||||
|
||||
exports = ThemeChange;
|
||||
|
||||
@@ -10,12 +10,13 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Events.ToolboxItemSelect');
|
||||
goog.module('Blockly.Events.ToolboxItemSelect');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.Events.UiBase');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.utils.object');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const UiBase = goog.require('Blockly.Events.UiBase');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
@@ -26,13 +27,11 @@ goog.require('Blockly.utils.object');
|
||||
* a blank event.
|
||||
* @param {string=} opt_workspaceId The workspace identifier for this event.
|
||||
* Undefined for a blank event.
|
||||
* @extends {Blockly.Events.UiBase}
|
||||
* @extends {UiBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.ToolboxItemSelect = function(opt_oldItem, opt_newItem,
|
||||
opt_workspaceId) {
|
||||
Blockly.Events.ToolboxItemSelect.superClass_.constructor.call(
|
||||
this, opt_workspaceId);
|
||||
const ToolboxItemSelect = function(opt_oldItem, opt_newItem, opt_workspaceId) {
|
||||
ToolboxItemSelect.superClass_.constructor.call(this, opt_workspaceId);
|
||||
|
||||
/**
|
||||
* The previously selected toolbox item.
|
||||
@@ -46,20 +45,20 @@ Blockly.Events.ToolboxItemSelect = function(opt_oldItem, opt_newItem,
|
||||
*/
|
||||
this.newItem = opt_newItem;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.ToolboxItemSelect, Blockly.Events.UiBase);
|
||||
object.inherits(ToolboxItemSelect, UiBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.ToolboxItemSelect.prototype.type = Blockly.Events.TOOLBOX_ITEM_SELECT;
|
||||
ToolboxItemSelect.prototype.type = Events.TOOLBOX_ITEM_SELECT;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.ToolboxItemSelect.prototype.toJson = function() {
|
||||
var json = Blockly.Events.ToolboxItemSelect.superClass_.toJson.call(this);
|
||||
ToolboxItemSelect.prototype.toJson = function() {
|
||||
const json = ToolboxItemSelect.superClass_.toJson.call(this);
|
||||
json['oldItem'] = this.oldItem;
|
||||
json['newItem'] = this.newItem;
|
||||
return json;
|
||||
@@ -69,11 +68,13 @@ Blockly.Events.ToolboxItemSelect.prototype.toJson = function() {
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.ToolboxItemSelect.prototype.fromJson = function(json) {
|
||||
Blockly.Events.ToolboxItemSelect.superClass_.fromJson.call(this, json);
|
||||
ToolboxItemSelect.prototype.fromJson = function(json) {
|
||||
ToolboxItemSelect.superClass_.fromJson.call(this, json);
|
||||
this.oldItem = json['oldItem'];
|
||||
this.newItem = json['newItem'];
|
||||
};
|
||||
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT,
|
||||
Blockly.Events.TOOLBOX_ITEM_SELECT, Blockly.Events.ToolboxItemSelect);
|
||||
registry.register(
|
||||
registry.Type.EVENT, Events.TOOLBOX_ITEM_SELECT, ToolboxItemSelect);
|
||||
|
||||
exports = ToolboxItemSelect;
|
||||
|
||||
@@ -10,12 +10,13 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Events.TrashcanOpen');
|
||||
goog.module('Blockly.Events.TrashcanOpen');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.Events.UiBase');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.utils.object');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const UiBase = goog.require('Blockly.Events.UiBase');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
@@ -24,11 +25,11 @@ goog.require('Blockly.utils.object');
|
||||
* opening). Undefined for a blank event.
|
||||
* @param {string=} opt_workspaceId The workspace identifier for this event.
|
||||
* Undefined for a blank event.
|
||||
* @extends {Blockly.Events.UiBase}
|
||||
* @extends {UiBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.TrashcanOpen = function(opt_isOpen, opt_workspaceId) {
|
||||
Blockly.Events.TrashcanOpen.superClass_.constructor.call(this, opt_workspaceId);
|
||||
const TrashcanOpen = function(opt_isOpen, opt_workspaceId) {
|
||||
TrashcanOpen.superClass_.constructor.call(this, opt_workspaceId);
|
||||
|
||||
/**
|
||||
* Whether the trashcan flyout is opening (false if closing).
|
||||
@@ -36,20 +37,20 @@ Blockly.Events.TrashcanOpen = function(opt_isOpen, opt_workspaceId) {
|
||||
*/
|
||||
this.isOpen = opt_isOpen;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.TrashcanOpen, Blockly.Events.UiBase);
|
||||
object.inherits(TrashcanOpen, UiBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.TrashcanOpen.prototype.type = Blockly.Events.TRASHCAN_OPEN;
|
||||
TrashcanOpen.prototype.type = Events.TRASHCAN_OPEN;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.TrashcanOpen.prototype.toJson = function() {
|
||||
var json = Blockly.Events.TrashcanOpen.superClass_.toJson.call(this);
|
||||
TrashcanOpen.prototype.toJson = function() {
|
||||
const json = TrashcanOpen.superClass_.toJson.call(this);
|
||||
json['isOpen'] = this.isOpen;
|
||||
return json;
|
||||
};
|
||||
@@ -58,10 +59,11 @@ Blockly.Events.TrashcanOpen.prototype.toJson = function() {
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.TrashcanOpen.prototype.fromJson = function(json) {
|
||||
Blockly.Events.TrashcanOpen.superClass_.fromJson.call(this, json);
|
||||
TrashcanOpen.prototype.fromJson = function(json) {
|
||||
TrashcanOpen.superClass_.fromJson.call(this, json);
|
||||
this.isOpen = json['isOpen'];
|
||||
};
|
||||
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT,
|
||||
Blockly.Events.TRASHCAN_OPEN, Blockly.Events.TrashcanOpen);
|
||||
registry.register(registry.Type.EVENT, Events.TRASHCAN_OPEN, TrashcanOpen);
|
||||
|
||||
exports = TrashcanOpen;
|
||||
|
||||
83
core/events/events_ui.js
Normal file
83
core/events/events_ui.js
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2018 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview (Deprecated) Events fired as a result of UI actions in
|
||||
* Blockly's editor.
|
||||
* @author fraser@google.com (Neil Fraser)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.Events.Ui');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const UiBase = goog.require('Blockly.Events.UiBase');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a UI event.
|
||||
* @param {?Block=} opt_block The affected block. Null for UI events
|
||||
* that do not have an associated block. Undefined for a blank event.
|
||||
* @param {string=} opt_element One of 'selected', 'comment', 'mutatorOpen',
|
||||
* etc.
|
||||
* @param {*=} opt_oldValue Previous value of element.
|
||||
* @param {*=} opt_newValue New value of element.
|
||||
* @extends {UiBase}
|
||||
* @deprecated December 2020. Instead use a more specific UI event.
|
||||
* @constructor
|
||||
*/
|
||||
const Ui = function(opt_block, opt_element, opt_oldValue, opt_newValue) {
|
||||
const workspaceId = opt_block ? opt_block.workspace.id : undefined;
|
||||
Ui.superClass_.constructor.call(this, workspaceId);
|
||||
|
||||
this.blockId = opt_block ? opt_block.id : null;
|
||||
this.element = typeof opt_element == 'undefined' ? '' : opt_element;
|
||||
this.oldValue = typeof opt_oldValue == 'undefined' ? '' : opt_oldValue;
|
||||
this.newValue = typeof opt_newValue == 'undefined' ? '' : opt_newValue;
|
||||
};
|
||||
object.inherits(Ui, UiBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Ui.prototype.type = Events.UI;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Ui.prototype.toJson = function() {
|
||||
const json = Ui.superClass_.toJson.call(this);
|
||||
json['element'] = this.element;
|
||||
if (this.newValue !== undefined) {
|
||||
json['newValue'] = this.newValue;
|
||||
}
|
||||
if (this.blockId) {
|
||||
json['blockId'] = this.blockId;
|
||||
}
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Ui.prototype.fromJson = function(json) {
|
||||
Ui.superClass_.fromJson.call(this, json);
|
||||
this.element = json['element'];
|
||||
this.newValue = json['newValue'];
|
||||
this.blockId = json['blockId'];
|
||||
};
|
||||
|
||||
registry.register(registry.Type.EVENT, Events.UI, Ui);
|
||||
|
||||
exports = Ui;
|
||||
58
core/events/events_ui_base.js
Normal file
58
core/events/events_ui_base.js
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Base class for events fired as a result of UI actions in
|
||||
* Blockly's editor.
|
||||
* @author fraser@google.com (Neil Fraser)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.Events.UiBase');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
const Abstract = goog.require('Blockly.Events.Abstract');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
|
||||
|
||||
/**
|
||||
* Base class for a UI event.
|
||||
* UI events are events that don't need to be sent over the wire for multi-user
|
||||
* editing to work (e.g. scrolling the workspace, zooming, opening toolbox
|
||||
* categories).
|
||||
* UI events do not undo or redo.
|
||||
* @param {string=} opt_workspaceId The workspace identifier for this event.
|
||||
* Undefined for a blank event.
|
||||
* @extends {Abstract}
|
||||
* @constructor
|
||||
*/
|
||||
const UiBase = function(opt_workspaceId) {
|
||||
UiBase.superClass_.constructor.call(this);
|
||||
|
||||
/**
|
||||
* Whether or not the event is blank (to be populated by fromJson).
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isBlank = typeof opt_workspaceId == 'undefined';
|
||||
|
||||
/**
|
||||
* The workspace identifier for this event.
|
||||
* @type {string}
|
||||
*/
|
||||
this.workspaceId = opt_workspaceId ? opt_workspaceId : '';
|
||||
|
||||
// UI events do not undo or redo.
|
||||
this.recordUndo = false;
|
||||
};
|
||||
object.inherits(UiBase, Abstract);
|
||||
|
||||
/**
|
||||
* Whether or not the event is a UI event.
|
||||
* @type {boolean}
|
||||
*/
|
||||
UiBase.prototype.isUiEvent = true;
|
||||
|
||||
exports = UiBase;
|
||||
66
core/events/events_var_base.js
Normal file
66
core/events/events_var_base.js
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2018 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Abstract class for a variable event.
|
||||
* @author fenichel@google.com (Rachel Fenichel)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.Events.VarBase');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
const Abstract = goog.require('Blockly.Events.Abstract');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const VariableModel = goog.requireType('Blockly.VariableModel');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
|
||||
|
||||
/**
|
||||
* Abstract class for a variable event.
|
||||
* @param {!VariableModel=} opt_variable The variable this event
|
||||
* corresponds to. Undefined for a blank event.
|
||||
* @extends {Abstract}
|
||||
* @constructor
|
||||
*/
|
||||
const VarBase = function(opt_variable) {
|
||||
VarBase.superClass_.constructor.call(this);
|
||||
this.isBlank = typeof opt_variable == 'undefined';
|
||||
|
||||
/**
|
||||
* The variable id for the variable this event pertains to.
|
||||
* @type {string}
|
||||
*/
|
||||
this.varId = this.isBlank ? '' : opt_variable.getId();
|
||||
|
||||
/**
|
||||
* The workspace identifier for this event.
|
||||
* @type {string}
|
||||
*/
|
||||
this.workspaceId = this.isBlank ? '' : opt_variable.workspace.id;
|
||||
};
|
||||
object.inherits(VarBase, Abstract);
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
VarBase.prototype.toJson = function() {
|
||||
const json = VarBase.superClass_.toJson.call(this);
|
||||
json['varId'] = this.varId;
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
VarBase.prototype.fromJson = function(json) {
|
||||
VarBase.superClass_.toJson.call(this);
|
||||
this.varId = json['varId'];
|
||||
};
|
||||
|
||||
exports = VarBase;
|
||||
84
core/events/events_var_create.js
Normal file
84
core/events/events_var_create.js
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2018 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Class for a variable creation event.
|
||||
* @author fenichel@google.com (Rachel Fenichel)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.Events.VarCreate');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const VarBase = goog.require('Blockly.Events.VarBase');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const VariableModel = goog.requireType('Blockly.VariableModel');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a variable creation event.
|
||||
* @param {!VariableModel=} opt_variable The created variable. Undefined
|
||||
* for a blank event.
|
||||
* @extends {VarBase}
|
||||
* @constructor
|
||||
*/
|
||||
const VarCreate = function(opt_variable) {
|
||||
VarCreate.superClass_.constructor.call(this, opt_variable);
|
||||
if (!opt_variable) {
|
||||
return; // Blank event to be populated by fromJson.
|
||||
}
|
||||
|
||||
this.varType = opt_variable.type;
|
||||
this.varName = opt_variable.name;
|
||||
};
|
||||
object.inherits(VarCreate, VarBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
VarCreate.prototype.type = Events.VAR_CREATE;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
VarCreate.prototype.toJson = function() {
|
||||
const json = VarCreate.superClass_.toJson.call(this);
|
||||
json['varType'] = this.varType;
|
||||
json['varName'] = this.varName;
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
VarCreate.prototype.fromJson = function(json) {
|
||||
VarCreate.superClass_.fromJson.call(this, json);
|
||||
this.varType = json['varType'];
|
||||
this.varName = json['varName'];
|
||||
};
|
||||
|
||||
/**
|
||||
* Run a variable creation event.
|
||||
* @param {boolean} forward True if run forward, false if run backward (undo).
|
||||
*/
|
||||
VarCreate.prototype.run = function(forward) {
|
||||
const workspace = this.getEventWorkspace_();
|
||||
if (forward) {
|
||||
workspace.createVariable(this.varName, this.varType, this.varId);
|
||||
} else {
|
||||
workspace.deleteVariableById(this.varId);
|
||||
}
|
||||
};
|
||||
|
||||
registry.register(registry.Type.EVENT, Events.VAR_CREATE, VarCreate);
|
||||
|
||||
exports = VarCreate;
|
||||
84
core/events/events_var_delete.js
Normal file
84
core/events/events_var_delete.js
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2018 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Classes for all types of variable events.
|
||||
* @author fenichel@google.com (Rachel Fenichel)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.Events.VarDelete');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const VarBase = goog.require('Blockly.Events.VarBase');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const VariableModel = goog.requireType('Blockly.VariableModel');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a variable deletion event.
|
||||
* @param {!VariableModel=} opt_variable The deleted variable. Undefined
|
||||
* for a blank event.
|
||||
* @extends {VarBase}
|
||||
* @constructor
|
||||
*/
|
||||
const VarDelete = function(opt_variable) {
|
||||
VarDelete.superClass_.constructor.call(this, opt_variable);
|
||||
if (!opt_variable) {
|
||||
return; // Blank event to be populated by fromJson.
|
||||
}
|
||||
|
||||
this.varType = opt_variable.type;
|
||||
this.varName = opt_variable.name;
|
||||
};
|
||||
object.inherits(VarDelete, VarBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
VarDelete.prototype.type = Events.VAR_DELETE;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
VarDelete.prototype.toJson = function() {
|
||||
const json = VarDelete.superClass_.toJson.call(this);
|
||||
json['varType'] = this.varType;
|
||||
json['varName'] = this.varName;
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
VarDelete.prototype.fromJson = function(json) {
|
||||
VarDelete.superClass_.fromJson.call(this, json);
|
||||
this.varType = json['varType'];
|
||||
this.varName = json['varName'];
|
||||
};
|
||||
|
||||
/**
|
||||
* Run a variable deletion event.
|
||||
* @param {boolean} forward True if run forward, false if run backward (undo).
|
||||
*/
|
||||
VarDelete.prototype.run = function(forward) {
|
||||
const workspace = this.getEventWorkspace_();
|
||||
if (forward) {
|
||||
workspace.deleteVariableById(this.varId);
|
||||
} else {
|
||||
workspace.createVariable(this.varName, this.varType, this.varId);
|
||||
}
|
||||
};
|
||||
|
||||
registry.register(registry.Type.EVENT, Events.VAR_DELETE, VarDelete);
|
||||
|
||||
exports = VarDelete;
|
||||
85
core/events/events_var_rename.js
Normal file
85
core/events/events_var_rename.js
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2018 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Class for a variable rename event.
|
||||
* @author fenichel@google.com (Rachel Fenichel)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.module('Blockly.Events.VarRename');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const VarBase = goog.require('Blockly.Events.VarBase');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const VariableModel = goog.requireType('Blockly.VariableModel');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a variable rename event.
|
||||
* @param {!VariableModel=} opt_variable The renamed variable. Undefined
|
||||
* for a blank event.
|
||||
* @param {string=} newName The new name the variable will be changed to.
|
||||
* @extends {VarBase}
|
||||
* @constructor
|
||||
*/
|
||||
const VarRename = function(opt_variable, newName) {
|
||||
VarRename.superClass_.constructor.call(this, opt_variable);
|
||||
if (!opt_variable) {
|
||||
return; // Blank event to be populated by fromJson.
|
||||
}
|
||||
|
||||
this.oldName = opt_variable.name;
|
||||
this.newName = typeof newName == 'undefined' ? '' : newName;
|
||||
};
|
||||
object.inherits(VarRename, VarBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
VarRename.prototype.type = Events.VAR_RENAME;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
VarRename.prototype.toJson = function() {
|
||||
const json = VarRename.superClass_.toJson.call(this);
|
||||
json['oldName'] = this.oldName;
|
||||
json['newName'] = this.newName;
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
VarRename.prototype.fromJson = function(json) {
|
||||
VarRename.superClass_.fromJson.call(this, json);
|
||||
this.oldName = json['oldName'];
|
||||
this.newName = json['newName'];
|
||||
};
|
||||
|
||||
/**
|
||||
* Run a variable rename event.
|
||||
* @param {boolean} forward True if run forward, false if run backward (undo).
|
||||
*/
|
||||
VarRename.prototype.run = function(forward) {
|
||||
const workspace = this.getEventWorkspace_();
|
||||
if (forward) {
|
||||
workspace.renameVariableById(this.varId, this.newName);
|
||||
} else {
|
||||
workspace.renameVariableById(this.varId, this.oldName);
|
||||
}
|
||||
};
|
||||
|
||||
registry.register(registry.Type.EVENT, Events.VAR_RENAME, VarRename);
|
||||
|
||||
exports = VarRename;
|
||||
@@ -10,12 +10,13 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Events.ViewportChange');
|
||||
goog.module('Blockly.Events.ViewportChange');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.Events.UiBase');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.utils.object');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const UiBase = goog.require('Blockly.Events.UiBase');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
@@ -30,12 +31,12 @@ goog.require('Blockly.utils.object');
|
||||
* Undefined for a blank event.
|
||||
* @param {number=} opt_oldScale The old scale of the workspace. Undefined for a
|
||||
* blank event.
|
||||
* @extends {Blockly.Events.UiBase}
|
||||
* @extends {UiBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.ViewportChange = function(opt_top, opt_left, opt_scale,
|
||||
opt_workspaceId, opt_oldScale) {
|
||||
Blockly.Events.ViewportChange.superClass_.constructor.call(this, opt_workspaceId);
|
||||
const ViewportChange = function(
|
||||
opt_top, opt_left, opt_scale, opt_workspaceId, opt_oldScale) {
|
||||
ViewportChange.superClass_.constructor.call(this, opt_workspaceId);
|
||||
|
||||
/**
|
||||
* Top-edge of the visible portion of the workspace, relative to the workspace
|
||||
@@ -63,21 +64,20 @@ Blockly.Events.ViewportChange = function(opt_top, opt_left, opt_scale,
|
||||
*/
|
||||
this.oldScale = opt_oldScale;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.ViewportChange,
|
||||
Blockly.Events.UiBase);
|
||||
object.inherits(ViewportChange, UiBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.ViewportChange.prototype.type = Blockly.Events.VIEWPORT_CHANGE;
|
||||
ViewportChange.prototype.type = Events.VIEWPORT_CHANGE;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.ViewportChange.prototype.toJson = function() {
|
||||
var json = Blockly.Events.ViewportChange.superClass_.toJson.call(this);
|
||||
ViewportChange.prototype.toJson = function() {
|
||||
const json = ViewportChange.superClass_.toJson.call(this);
|
||||
json['viewTop'] = this.viewTop;
|
||||
json['viewLeft'] = this.viewLeft;
|
||||
json['scale'] = this.scale;
|
||||
@@ -89,13 +89,14 @@ Blockly.Events.ViewportChange.prototype.toJson = function() {
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.ViewportChange.prototype.fromJson = function(json) {
|
||||
Blockly.Events.ViewportChange.superClass_.fromJson.call(this, json);
|
||||
ViewportChange.prototype.fromJson = function(json) {
|
||||
ViewportChange.superClass_.fromJson.call(this, json);
|
||||
this.viewTop = json['viewTop'];
|
||||
this.viewLeft = json['viewLeft'];
|
||||
this.scale = json['scale'];
|
||||
this.oldScale = json['oldScale'];
|
||||
};
|
||||
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT,
|
||||
Blockly.Events.VIEWPORT_CHANGE, Blockly.Events.ViewportChange);
|
||||
registry.register(registry.Type.EVENT, Events.VIEWPORT_CHANGE, ViewportChange);
|
||||
|
||||
exports = ViewportChange;
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2018 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Events fired as a result of UI actions in Blockly's editor.
|
||||
* @author fraser@google.com (Neil Fraser)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Events.Ui');
|
||||
goog.provide('Blockly.Events.UiBase');
|
||||
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.Events.Abstract');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.utils.object');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
|
||||
|
||||
/**
|
||||
* Base class for a UI event.
|
||||
* UI events are events that don't need to be sent over the wire for multi-user
|
||||
* editing to work (e.g. scrolling the workspace, zooming, opening toolbox
|
||||
* categories).
|
||||
* UI events do not undo or redo.
|
||||
* @param {string=} opt_workspaceId The workspace identifier for this event.
|
||||
* Undefined for a blank event.
|
||||
* @extends {Blockly.Events.Abstract}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.UiBase = function(opt_workspaceId) {
|
||||
Blockly.Events.UiBase.superClass_.constructor.call(this);
|
||||
|
||||
/**
|
||||
* Whether or not the event is blank (to be populated by fromJson).
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isBlank = typeof opt_workspaceId == 'undefined';
|
||||
|
||||
/**
|
||||
* The workspace identifier for this event.
|
||||
* @type {string}
|
||||
*/
|
||||
this.workspaceId = opt_workspaceId ? opt_workspaceId : '';
|
||||
|
||||
// UI events do not undo or redo.
|
||||
this.recordUndo = false;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.UiBase, Blockly.Events.Abstract);
|
||||
|
||||
/**
|
||||
* Whether or not the event is a UI event.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.Events.UiBase.prototype.isUiEvent = true;
|
||||
|
||||
/**
|
||||
* Class for a UI event.
|
||||
* @param {?Blockly.Block=} opt_block The affected block. Null for UI events
|
||||
* that do not have an associated block. Undefined for a blank event.
|
||||
* @param {string=} opt_element One of 'selected', 'comment', 'mutatorOpen',
|
||||
* etc.
|
||||
* @param {*=} opt_oldValue Previous value of element.
|
||||
* @param {*=} opt_newValue New value of element.
|
||||
* @extends {Blockly.Events.UiBase}
|
||||
* @deprecated December 2020. Instead use a more specific UI event.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.Ui = function(opt_block, opt_element, opt_oldValue,
|
||||
opt_newValue) {
|
||||
var workspaceId = opt_block ? opt_block.workspace.id : undefined;
|
||||
Blockly.Events.Ui.superClass_.constructor.call(this, workspaceId);
|
||||
|
||||
this.blockId = opt_block ? opt_block.id : null;
|
||||
this.element = typeof opt_element == 'undefined' ? '' : opt_element;
|
||||
this.oldValue = typeof opt_oldValue == 'undefined' ? '' : opt_oldValue;
|
||||
this.newValue = typeof opt_newValue == 'undefined' ? '' : opt_newValue;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.Ui, Blockly.Events.UiBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.Ui.prototype.type = Blockly.Events.UI;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.Ui.prototype.toJson = function() {
|
||||
var json = Blockly.Events.Ui.superClass_.toJson.call(this);
|
||||
json['element'] = this.element;
|
||||
if (this.newValue !== undefined) {
|
||||
json['newValue'] = this.newValue;
|
||||
}
|
||||
if (this.blockId) {
|
||||
json['blockId'] = this.blockId;
|
||||
}
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.Ui.prototype.fromJson = function(json) {
|
||||
Blockly.Events.Ui.superClass_.fromJson.call(this, json);
|
||||
this.element = json['element'];
|
||||
this.newValue = json['newValue'];
|
||||
this.blockId = json['blockId'];
|
||||
};
|
||||
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.UI,
|
||||
Blockly.Events.Ui);
|
||||
@@ -1,250 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2018 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Classes for all types of variable events.
|
||||
* @author fenichel@google.com (Rachel Fenichel)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Events.VarBase');
|
||||
goog.provide('Blockly.Events.VarCreate');
|
||||
goog.provide('Blockly.Events.VarDelete');
|
||||
goog.provide('Blockly.Events.VarRename');
|
||||
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.Events.Abstract');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.utils.object');
|
||||
|
||||
goog.requireType('Blockly.VariableModel');
|
||||
|
||||
|
||||
/**
|
||||
* Abstract class for a variable event.
|
||||
* @param {!Blockly.VariableModel=} opt_variable The variable this event
|
||||
* corresponds to. Undefined for a blank event.
|
||||
* @extends {Blockly.Events.Abstract}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.VarBase = function(opt_variable) {
|
||||
Blockly.Events.VarBase.superClass_.constructor.call(this);
|
||||
this.isBlank = typeof opt_variable == 'undefined';
|
||||
|
||||
/**
|
||||
* The variable id for the variable this event pertains to.
|
||||
* @type {string}
|
||||
*/
|
||||
this.varId = this.isBlank ? '' : opt_variable.getId();
|
||||
|
||||
/**
|
||||
* The workspace identifier for this event.
|
||||
* @type {string}
|
||||
*/
|
||||
this.workspaceId = this.isBlank ? '' : opt_variable.workspace.id;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.VarBase, Blockly.Events.Abstract);
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.VarBase.prototype.toJson = function() {
|
||||
var json = Blockly.Events.VarBase.superClass_.toJson.call(this);
|
||||
json['varId'] = this.varId;
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.VarBase.prototype.fromJson = function(json) {
|
||||
Blockly.Events.VarBase.superClass_.toJson.call(this);
|
||||
this.varId = json['varId'];
|
||||
};
|
||||
|
||||
/**
|
||||
* Class for a variable creation event.
|
||||
* @param {!Blockly.VariableModel=} opt_variable The created variable. Undefined
|
||||
* for a blank event.
|
||||
* @extends {Blockly.Events.VarBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.VarCreate = function(opt_variable) {
|
||||
Blockly.Events.VarCreate.superClass_.constructor.call(this, opt_variable);
|
||||
if (!opt_variable) {
|
||||
return; // Blank event to be populated by fromJson.
|
||||
}
|
||||
|
||||
this.varType = opt_variable.type;
|
||||
this.varName = opt_variable.name;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.VarCreate, Blockly.Events.VarBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.VarCreate.prototype.type = Blockly.Events.VAR_CREATE;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.VarCreate.prototype.toJson = function() {
|
||||
var json = Blockly.Events.VarCreate.superClass_.toJson.call(this);
|
||||
json['varType'] = this.varType;
|
||||
json['varName'] = this.varName;
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.VarCreate.prototype.fromJson = function(json) {
|
||||
Blockly.Events.VarCreate.superClass_.fromJson.call(this, json);
|
||||
this.varType = json['varType'];
|
||||
this.varName = json['varName'];
|
||||
};
|
||||
|
||||
/**
|
||||
* Run a variable creation event.
|
||||
* @param {boolean} forward True if run forward, false if run backward (undo).
|
||||
*/
|
||||
Blockly.Events.VarCreate.prototype.run = function(forward) {
|
||||
var workspace = this.getEventWorkspace_();
|
||||
if (forward) {
|
||||
workspace.createVariable(this.varName, this.varType, this.varId);
|
||||
} else {
|
||||
workspace.deleteVariableById(this.varId);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Class for a variable deletion event.
|
||||
* @param {!Blockly.VariableModel=} opt_variable The deleted variable. Undefined
|
||||
* for a blank event.
|
||||
* @extends {Blockly.Events.VarBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.VarDelete = function(opt_variable) {
|
||||
Blockly.Events.VarDelete.superClass_.constructor.call(this, opt_variable);
|
||||
if (!opt_variable) {
|
||||
return; // Blank event to be populated by fromJson.
|
||||
}
|
||||
|
||||
this.varType = opt_variable.type;
|
||||
this.varName = opt_variable.name;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.VarDelete, Blockly.Events.VarBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.VarDelete.prototype.type = Blockly.Events.VAR_DELETE;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.VarDelete.prototype.toJson = function() {
|
||||
var json = Blockly.Events.VarDelete.superClass_.toJson.call(this);
|
||||
json['varType'] = this.varType;
|
||||
json['varName'] = this.varName;
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.VarDelete.prototype.fromJson = function(json) {
|
||||
Blockly.Events.VarDelete.superClass_.fromJson.call(this, json);
|
||||
this.varType = json['varType'];
|
||||
this.varName = json['varName'];
|
||||
};
|
||||
|
||||
/**
|
||||
* Run a variable deletion event.
|
||||
* @param {boolean} forward True if run forward, false if run backward (undo).
|
||||
*/
|
||||
Blockly.Events.VarDelete.prototype.run = function(forward) {
|
||||
var workspace = this.getEventWorkspace_();
|
||||
if (forward) {
|
||||
workspace.deleteVariableById(this.varId);
|
||||
} else {
|
||||
workspace.createVariable(this.varName, this.varType, this.varId);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Class for a variable rename event.
|
||||
* @param {!Blockly.VariableModel=} opt_variable The renamed variable. Undefined
|
||||
* for a blank event.
|
||||
* @param {string=} newName The new name the variable will be changed to.
|
||||
* @extends {Blockly.Events.VarBase}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.VarRename = function(opt_variable, newName) {
|
||||
Blockly.Events.VarRename.superClass_.constructor.call(this, opt_variable);
|
||||
if (!opt_variable) {
|
||||
return; // Blank event to be populated by fromJson.
|
||||
}
|
||||
|
||||
this.oldName = opt_variable.name;
|
||||
this.newName = typeof newName == 'undefined' ? '' : newName;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.VarRename, Blockly.Events.VarBase);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.VarRename.prototype.type = Blockly.Events.VAR_RENAME;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.VarRename.prototype.toJson = function() {
|
||||
var json = Blockly.Events.VarRename.superClass_.toJson.call(this);
|
||||
json['oldName'] = this.oldName;
|
||||
json['newName'] = this.newName;
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.VarRename.prototype.fromJson = function(json) {
|
||||
Blockly.Events.VarRename.superClass_.fromJson.call(this, json);
|
||||
this.oldName = json['oldName'];
|
||||
this.newName = json['newName'];
|
||||
};
|
||||
|
||||
/**
|
||||
* Run a variable rename event.
|
||||
* @param {boolean} forward True if run forward, false if run backward (undo).
|
||||
*/
|
||||
Blockly.Events.VarRename.prototype.run = function(forward) {
|
||||
var workspace = this.getEventWorkspace_();
|
||||
if (forward) {
|
||||
workspace.renameVariableById(this.varId, this.newName);
|
||||
} else {
|
||||
workspace.renameVariableById(this.varId, this.oldName);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT,
|
||||
Blockly.Events.VAR_CREATE, Blockly.Events.VarCreate);
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT,
|
||||
Blockly.Events.VAR_DELETE, Blockly.Events.VarDelete);
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT,
|
||||
Blockly.Events.VAR_RENAME, Blockly.Events.VarRename);
|
||||
@@ -10,14 +10,15 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Events.FinishedLoading');
|
||||
goog.module('Blockly.Events.FinishedLoading');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.Events.Abstract');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.utils.object');
|
||||
|
||||
goog.requireType('Blockly.Workspace');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const EventsAbstract = goog.require('Blockly.Events.Abstract');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Workspace = goog.requireType('Blockly.Workspace');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
@@ -25,13 +26,12 @@ goog.requireType('Blockly.Workspace');
|
||||
* Used to notify the developer when the workspace has finished loading (i.e
|
||||
* domToWorkspace).
|
||||
* Finished loading events do not record undo or redo.
|
||||
* @param {!Blockly.Workspace=} opt_workspace The workspace that has finished
|
||||
* @param {!Workspace=} opt_workspace The workspace that has finished
|
||||
* loading. Undefined for a blank event.
|
||||
* @extends {Blockly.Events.Abstract}
|
||||
* @extends {EventsAbstract}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Events.FinishedLoading = function(opt_workspace) {
|
||||
|
||||
const FinishedLoading = function(opt_workspace) {
|
||||
/**
|
||||
* Whether or not the event is blank (to be populated by fromJson).
|
||||
* @type {boolean}
|
||||
@@ -50,26 +50,25 @@ Blockly.Events.FinishedLoading = function(opt_workspace) {
|
||||
* perspective, and should be undone together.
|
||||
* @type {string}
|
||||
*/
|
||||
this.group = Blockly.Events.getGroup();
|
||||
this.group = Events.getGroup();
|
||||
|
||||
// Workspace events do not undo or redo.
|
||||
this.recordUndo = false;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Events.FinishedLoading,
|
||||
Blockly.Events.Abstract);
|
||||
object.inherits(FinishedLoading, EventsAbstract);
|
||||
|
||||
/**
|
||||
* Type of this event.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Events.FinishedLoading.prototype.type = Blockly.Events.FINISHED_LOADING;
|
||||
FinishedLoading.prototype.type = Events.FINISHED_LOADING;
|
||||
|
||||
/**
|
||||
* Encode the event as JSON.
|
||||
* @return {!Object} JSON representation.
|
||||
*/
|
||||
Blockly.Events.FinishedLoading.prototype.toJson = function() {
|
||||
var json = {
|
||||
FinishedLoading.prototype.toJson = function() {
|
||||
const json = {
|
||||
'type': this.type,
|
||||
};
|
||||
if (this.group) {
|
||||
@@ -85,11 +84,13 @@ Blockly.Events.FinishedLoading.prototype.toJson = function() {
|
||||
* Decode the JSON event.
|
||||
* @param {!Object} json JSON representation.
|
||||
*/
|
||||
Blockly.Events.FinishedLoading.prototype.fromJson = function(json) {
|
||||
FinishedLoading.prototype.fromJson = function(json) {
|
||||
this.isBlank = false;
|
||||
this.workspaceId = json['workspaceId'];
|
||||
this.group = json['group'];
|
||||
};
|
||||
|
||||
Blockly.registry.register(Blockly.registry.Type.EVENT,
|
||||
Blockly.Events.FINISHED_LOADING, Blockly.Events.FinishedLoading);
|
||||
registry.register(
|
||||
registry.Type.EVENT, Events.FINISHED_LOADING, FinishedLoading);
|
||||
|
||||
exports = FinishedLoading;
|
||||
|
||||
@@ -24,6 +24,8 @@ goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.utils.xml');
|
||||
goog.require('Blockly.Xml');
|
||||
|
||||
goog.requireType('Blockly.WorkspaceComment');
|
||||
|
||||
|
||||
/**
|
||||
* Abstract class for a comment event.
|
||||
@@ -232,7 +234,7 @@ Blockly.Events.CommentCreateDeleteHelper = function(event, create) {
|
||||
} else {
|
||||
var comment = workspace.getCommentById(event.commentId);
|
||||
if (comment) {
|
||||
comment.dispose(false, false);
|
||||
comment.dispose();
|
||||
} else {
|
||||
// Only complain about root-level block.
|
||||
console.warn("Can't uncreate non-existent comment: " + event.commentId);
|
||||
|
||||
@@ -22,7 +22,8 @@ goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
const {checkMessageReferences, replaceMessageReferences, runAfterPageLoad} = goog.require('Blockly.utils');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
goog.requireType('Blockly.Mutator');
|
||||
|
||||
|
||||
/**
|
||||
@@ -102,10 +103,11 @@ const registerMutator = function(name, mixinObj, opt_helperFn, opt_blockList) {
|
||||
// Sanity checks passed.
|
||||
register(name, function() {
|
||||
if (hasMutatorDialog) {
|
||||
if (!Blockly.Mutator) {
|
||||
const Mutator = goog.module.get('Blockly.Mutator');
|
||||
if (!Mutator) {
|
||||
throw Error(errorPrefix + 'Missing require for Blockly.Mutator');
|
||||
}
|
||||
this.setMutator(new Blockly.Mutator(opt_blockList || []));
|
||||
this.setMutator(new Mutator(opt_blockList || []));
|
||||
}
|
||||
// Mixin the object.
|
||||
this.mixin(mixinObj);
|
||||
@@ -331,13 +333,13 @@ const buildTooltipForDropdown = function(dropdownName, lookupTable) {
|
||||
|
||||
// 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.
|
||||
// utils.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
|
||||
runAfterPageLoad(function() {
|
||||
utils.runAfterPageLoad(function() {
|
||||
for (let key in lookupTable) {
|
||||
// Will print warnings if reference is missing.
|
||||
checkMessageReferences(lookupTable[key]);
|
||||
utils.checkMessageReferences(lookupTable[key]);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -366,7 +368,7 @@ const buildTooltipForDropdown = function(dropdownName, lookupTable) {
|
||||
console.warn(warning + '.');
|
||||
}
|
||||
} else {
|
||||
tooltip = replaceMessageReferences(tooltip);
|
||||
tooltip = utils.replaceMessageReferences(tooltip);
|
||||
}
|
||||
return tooltip;
|
||||
}.bind(this));
|
||||
@@ -411,12 +413,12 @@ const checkDropdownOptionsInTable = function(block, dropdownName, lookupTable) {
|
||||
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.
|
||||
// utils.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
|
||||
runAfterPageLoad(function() {
|
||||
utils.runAfterPageLoad(function() {
|
||||
// Will print warnings if reference is missing.
|
||||
checkMessageReferences(msgTemplate);
|
||||
utils.checkMessageReferences(msgTemplate);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -427,7 +429,7 @@ const buildTooltipWithFieldText = function(msgTemplate, fieldName) {
|
||||
const extensionFn = function() {
|
||||
this.setTooltip(function() {
|
||||
const field = this.getField(fieldName);
|
||||
return replaceMessageReferences(msgTemplate)
|
||||
return utils.replaceMessageReferences(msgTemplate)
|
||||
.replace('%1', field ? field.getText() : '');
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
@@ -26,15 +26,15 @@ const Coordinate = goog.requireType('Blockly.utils.Coordinate');
|
||||
const DropDownDiv = goog.require('Blockly.DropDownDiv');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IASTNodeLocationSvg = goog.require('Blockly.IASTNodeLocationSvg');
|
||||
const IASTNodeLocationSvg = goog.requireType('Blockly.IASTNodeLocationSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IASTNodeLocationWithBlock = goog.require('Blockly.IASTNodeLocationWithBlock');
|
||||
const IASTNodeLocationWithBlock = goog.requireType('Blockly.IASTNodeLocationWithBlock');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IKeyboardAccessible = goog.require('Blockly.IKeyboardAccessible');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IRegistrable = goog.require('Blockly.IRegistrable');
|
||||
const IKeyboardAccessible = goog.requireType('Blockly.IKeyboardAccessible');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Input = goog.requireType('Blockly.Input');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IRegistrable = goog.requireType('Blockly.IRegistrable');
|
||||
const MarkerManager = goog.require('Blockly.MarkerManager');
|
||||
const Rect = goog.require('Blockly.utils.Rect');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
@@ -45,12 +45,11 @@ const Tooltip = goog.require('Blockly.Tooltip');
|
||||
const WidgetDiv = goog.require('Blockly.WidgetDiv');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const browserEvents = goog.require('Blockly.browserEvents');
|
||||
const style = goog.require('Blockly.utils.style');
|
||||
const userAgent = goog.require('Blockly.utils.userAgent');
|
||||
const {addClass, createSvgElement, getFastTextWidth, removeClass, removeNode} = goog.require('Blockly.utils.dom');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const {conditionalBind, unbind, Data} = goog.require('Blockly.browserEvents');
|
||||
const {getPageOffset} = goog.require('Blockly.utils.style');
|
||||
const {replaceMessageReferences} = goog.require('Blockly.utils');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockChange');
|
||||
/** @suppress {extraRequire} */
|
||||
@@ -150,7 +149,7 @@ const Field = function(value, opt_validator, opt_config) {
|
||||
|
||||
/**
|
||||
* Mouse down event listener data.
|
||||
* @type {?Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.mouseDownWrapper_ = null;
|
||||
@@ -281,7 +280,7 @@ Field.prototype.SERIALIZABLE = false;
|
||||
Field.prototype.configure_ = function(config) {
|
||||
let tooltip = config['tooltip'];
|
||||
if (typeof tooltip == 'string') {
|
||||
tooltip = replaceMessageReferences(config['tooltip']);
|
||||
tooltip = utils.replaceMessageReferences(config['tooltip']);
|
||||
}
|
||||
tooltip && this.setTooltip(tooltip);
|
||||
|
||||
@@ -331,7 +330,7 @@ Field.prototype.init = function() {
|
||||
// Field has already been initialized once.
|
||||
return;
|
||||
}
|
||||
this.fieldGroup_ = createSvgElement(Svg.G, {}, null);
|
||||
this.fieldGroup_ = dom.createSvgElement(Svg.G, {}, null);
|
||||
if (!this.isVisible()) {
|
||||
this.fieldGroup_.style.display = 'none';
|
||||
}
|
||||
@@ -367,7 +366,7 @@ Field.prototype.initModel = function() {};
|
||||
* @protected
|
||||
*/
|
||||
Field.prototype.createBorderRect_ = function() {
|
||||
this.borderRect_ = createSvgElement(
|
||||
this.borderRect_ = dom.createSvgElement(
|
||||
Svg.RECT, {
|
||||
'rx': this.getConstants().FIELD_BORDER_RECT_RADIUS,
|
||||
'ry': this.getConstants().FIELD_BORDER_RECT_RADIUS,
|
||||
@@ -387,7 +386,7 @@ Field.prototype.createBorderRect_ = function() {
|
||||
* @protected
|
||||
*/
|
||||
Field.prototype.createTextElement_ = function() {
|
||||
this.textElement_ = createSvgElement(
|
||||
this.textElement_ = dom.createSvgElement(
|
||||
Svg.TEXT, {
|
||||
'class': 'blocklyText',
|
||||
},
|
||||
@@ -406,7 +405,7 @@ Field.prototype.createTextElement_ = function() {
|
||||
*/
|
||||
Field.prototype.bindEvents_ = function() {
|
||||
Tooltip.bindMouseEvents(this.getClickTarget_());
|
||||
this.mouseDownWrapper_ = conditionalBind(
|
||||
this.mouseDownWrapper_ = browserEvents.conditionalBind(
|
||||
this.getClickTarget_(), 'mousedown', this, this.onMouseDown_);
|
||||
};
|
||||
|
||||
@@ -443,10 +442,10 @@ Field.prototype.dispose = function() {
|
||||
Tooltip.unbindMouseEvents(this.getClickTarget_());
|
||||
|
||||
if (this.mouseDownWrapper_) {
|
||||
unbind(this.mouseDownWrapper_);
|
||||
browserEvents.unbind(this.mouseDownWrapper_);
|
||||
}
|
||||
|
||||
removeNode(this.fieldGroup_);
|
||||
dom.removeNode(this.fieldGroup_);
|
||||
|
||||
this.disposed = true;
|
||||
};
|
||||
@@ -460,12 +459,12 @@ Field.prototype.updateEditable = function() {
|
||||
return;
|
||||
}
|
||||
if (this.enabled_ && this.sourceBlock_.isEditable()) {
|
||||
addClass(group, 'blocklyEditableText');
|
||||
removeClass(group, 'blocklyNonEditableText');
|
||||
dom.addClass(group, 'blocklyEditableText');
|
||||
dom.removeClass(group, 'blocklyNonEditableText');
|
||||
group.style.cursor = this.CURSOR;
|
||||
} else {
|
||||
addClass(group, 'blocklyNonEditableText');
|
||||
removeClass(group, 'blocklyEditableText');
|
||||
dom.addClass(group, 'blocklyNonEditableText');
|
||||
dom.removeClass(group, 'blocklyEditableText');
|
||||
group.style.cursor = '';
|
||||
}
|
||||
};
|
||||
@@ -643,7 +642,7 @@ Field.prototype.updateSize_ = function(opt_margin) {
|
||||
|
||||
let contentWidth = 0;
|
||||
if (this.textElement_) {
|
||||
contentWidth = getFastTextWidth(
|
||||
contentWidth = dom.getFastTextWidth(
|
||||
this.textElement_, constants.FIELD_TEXT_FONTSIZE,
|
||||
constants.FIELD_TEXT_FONTWEIGHT, constants.FIELD_TEXT_FONTFAMILY);
|
||||
totalWidth += contentWidth;
|
||||
@@ -760,7 +759,7 @@ Field.prototype.getScaledBBox = function() {
|
||||
}
|
||||
} else {
|
||||
const bBox = this.borderRect_.getBoundingClientRect();
|
||||
xy = getPageOffset(this.borderRect_);
|
||||
xy = style.getPageOffset(this.borderRect_);
|
||||
scaledWidth = bBox.width;
|
||||
scaledHeight = bBox.height;
|
||||
}
|
||||
@@ -1020,7 +1019,7 @@ Field.prototype.getClickTarget_ = function() {
|
||||
* @protected
|
||||
*/
|
||||
Field.prototype.getAbsoluteXY_ = function() {
|
||||
return getPageOffset(
|
||||
return style.getPageOffset(
|
||||
/** @type {!SVGRectElement} */ (this.getClickTarget_()));
|
||||
};
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ 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');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockChange');
|
||||
|
||||
@@ -48,7 +48,7 @@ const FieldCheckbox = function(opt_value, opt_validator, opt_config) {
|
||||
FieldCheckbox.superClass_.constructor.call(
|
||||
this, opt_value, opt_validator, opt_config);
|
||||
};
|
||||
inherits(FieldCheckbox, Field);
|
||||
object.inherits(FieldCheckbox, Field);
|
||||
|
||||
/**
|
||||
* The default value for this field.
|
||||
|
||||
@@ -20,12 +20,11 @@ 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 browserEvents = goog.require('Blockly.browserEvents');
|
||||
const colour = goog.require('Blockly.utils.colour');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
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');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockChange');
|
||||
|
||||
@@ -65,40 +64,40 @@ const FieldColour = function(opt_value, opt_validator, opt_config) {
|
||||
|
||||
/**
|
||||
* Mouse click event data.
|
||||
* @type {?Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.onClickWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Mouse move event data.
|
||||
* @type {?Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.onMouseMoveWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Mouse enter event data.
|
||||
* @type {?Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.onMouseEnterWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Mouse leave event data.
|
||||
* @type {?Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.onMouseLeaveWrapper_ = null;
|
||||
|
||||
/**
|
||||
* Key down event data.
|
||||
* @type {?Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.onKeyDownWrapper_ = null;
|
||||
};
|
||||
inherits(FieldColour, Field);
|
||||
object.inherits(FieldColour, Field);
|
||||
|
||||
/**
|
||||
* Construct a FieldColour from a JSON arg object.
|
||||
@@ -472,7 +471,7 @@ FieldColour.prototype.onMouseLeave_ = function() {
|
||||
this.picker_.blur();
|
||||
const highlighted = this.getHighlighted_();
|
||||
if (highlighted) {
|
||||
removeClass(highlighted, 'blocklyColourHighlighted');
|
||||
dom.removeClass(highlighted, 'blocklyColourHighlighted');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -503,10 +502,10 @@ FieldColour.prototype.setHighlightedCell_ = function(cell, index) {
|
||||
// Unhighlight the current item.
|
||||
const highlighted = this.getHighlighted_();
|
||||
if (highlighted) {
|
||||
removeClass(highlighted, 'blocklyColourHighlighted');
|
||||
dom.removeClass(highlighted, 'blocklyColourHighlighted');
|
||||
}
|
||||
// Highlight new item.
|
||||
addClass(cell, 'blocklyColourHighlighted');
|
||||
dom.addClass(cell, 'blocklyColourHighlighted');
|
||||
// Set new highlighted index.
|
||||
this.highlightedIndex_ = index;
|
||||
|
||||
@@ -560,15 +559,15 @@ FieldColour.prototype.dropdownCreate_ = function() {
|
||||
|
||||
// Configure event handler on the table to listen for any event in a cell.
|
||||
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);
|
||||
browserEvents.conditionalBind(table, 'click', this, this.onClick_, true);
|
||||
this.onMouseMoveWrapper_ = browserEvents.conditionalBind(
|
||||
table, 'mousemove', this, this.onMouseMove_, true);
|
||||
this.onMouseEnterWrapper_ = browserEvents.conditionalBind(
|
||||
table, 'mouseenter', this, this.onMouseEnter_, true);
|
||||
this.onMouseLeaveWrapper_ = browserEvents.conditionalBind(
|
||||
table, 'mouseleave', this, this.onMouseLeave_, true);
|
||||
this.onKeyDownWrapper_ =
|
||||
conditionalBind(table, 'keydown', this, this.onKeyDown_);
|
||||
browserEvents.conditionalBind(table, 'keydown', this, this.onKeyDown_);
|
||||
|
||||
this.picker_ = table;
|
||||
};
|
||||
@@ -579,23 +578,23 @@ FieldColour.prototype.dropdownCreate_ = function() {
|
||||
*/
|
||||
FieldColour.prototype.dropdownDispose_ = function() {
|
||||
if (this.onClickWrapper_) {
|
||||
unbind(this.onClickWrapper_);
|
||||
browserEvents.unbind(this.onClickWrapper_);
|
||||
this.onClickWrapper_ = null;
|
||||
}
|
||||
if (this.onMouseMoveWrapper_) {
|
||||
unbind(this.onMouseMoveWrapper_);
|
||||
browserEvents.unbind(this.onMouseMoveWrapper_);
|
||||
this.onMouseMoveWrapper_ = null;
|
||||
}
|
||||
if (this.onMouseEnterWrapper_) {
|
||||
unbind(this.onMouseEnterWrapper_);
|
||||
browserEvents.unbind(this.onMouseEnterWrapper_);
|
||||
this.onMouseEnterWrapper_ = null;
|
||||
}
|
||||
if (this.onMouseLeaveWrapper_) {
|
||||
unbind(this.onMouseLeaveWrapper_);
|
||||
browserEvents.unbind(this.onMouseLeaveWrapper_);
|
||||
this.onMouseLeaveWrapper_ = null;
|
||||
}
|
||||
if (this.onKeyDownWrapper_) {
|
||||
unbind(this.onKeyDownWrapper_);
|
||||
browserEvents.unbind(this.onKeyDownWrapper_);
|
||||
this.onKeyDownWrapper_ = null;
|
||||
}
|
||||
this.picker_ = null;
|
||||
|
||||
@@ -24,10 +24,10 @@ 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 object = goog.require('Blockly.utils.object');
|
||||
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');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
const utilsString = goog.require('Blockly.utils.string');
|
||||
|
||||
|
||||
/**
|
||||
@@ -130,7 +130,7 @@ const FieldDropdown = function(menuGenerator, opt_validator, opt_config) {
|
||||
*/
|
||||
this.svgArrow_ = null;
|
||||
};
|
||||
inherits(FieldDropdown, Field);
|
||||
object.inherits(FieldDropdown, Field);
|
||||
|
||||
/**
|
||||
* Dropdown image properties.
|
||||
@@ -405,10 +405,10 @@ FieldDropdown.prototype.trimOptions_ = function() {
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
const label = options[i][0];
|
||||
if (typeof label == 'string') {
|
||||
options[i][0] = replaceMessageReferences(label);
|
||||
options[i][0] = utils.replaceMessageReferences(label);
|
||||
} else {
|
||||
if (label.alt != null) {
|
||||
options[i][0].alt = replaceMessageReferences(label.alt);
|
||||
options[i][0].alt = utils.replaceMessageReferences(label.alt);
|
||||
}
|
||||
hasImages = true;
|
||||
}
|
||||
@@ -420,9 +420,9 @@ FieldDropdown.prototype.trimOptions_ = function() {
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
strings.push(options[i][0]);
|
||||
}
|
||||
const shortest = shortestStringLength(strings);
|
||||
const prefixLength = commonWordPrefix(strings, shortest);
|
||||
const suffixLength = commonWordSuffix(strings, shortest);
|
||||
const shortest = utilsString.shortestStringLength(strings);
|
||||
const prefixLength = utilsString.commonWordPrefix(strings, shortest);
|
||||
const suffixLength = utilsString.commonWordSuffix(strings, shortest);
|
||||
if (!prefixLength && !suffixLength) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -16,10 +16,10 @@ goog.module.declareLegacyNamespace();
|
||||
const Field = goog.require('Blockly.Field');
|
||||
const Size = goog.require('Blockly.utils.Size');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
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');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
@@ -45,9 +45,9 @@ const FieldImage = function(
|
||||
if (!src) {
|
||||
throw Error('Src value of an image field is required');
|
||||
}
|
||||
src = replaceMessageReferences(src);
|
||||
const imageHeight = Number(replaceMessageReferences(height));
|
||||
const imageWidth = Number(replaceMessageReferences(width));
|
||||
src = utils.replaceMessageReferences(src);
|
||||
const imageHeight = Number(utils.replaceMessageReferences(height));
|
||||
const imageWidth = Number(utils.replaceMessageReferences(width));
|
||||
if (isNaN(imageHeight) || isNaN(imageWidth)) {
|
||||
throw Error(
|
||||
'Height and width values of an image field must cast to' +
|
||||
@@ -78,7 +78,7 @@ const FieldImage = function(
|
||||
|
||||
if (!opt_config) { // If the config wasn't passed, do old configuration.
|
||||
this.flipRtl_ = !!opt_flipRtl;
|
||||
this.altText_ = replaceMessageReferences(opt_alt) || '';
|
||||
this.altText_ = utils.replaceMessageReferences(opt_alt) || '';
|
||||
}
|
||||
|
||||
// Initialize other properties.
|
||||
@@ -115,7 +115,7 @@ const FieldImage = function(
|
||||
*/
|
||||
this.imageElement_ = null;
|
||||
};
|
||||
inherits(FieldImage, Field);
|
||||
object.inherits(FieldImage, Field);
|
||||
|
||||
/**
|
||||
* The default value for this field.
|
||||
@@ -174,7 +174,7 @@ FieldImage.prototype.isDirty_ = false;
|
||||
FieldImage.prototype.configure_ = function(config) {
|
||||
FieldImage.superClass_.configure_.call(this, config);
|
||||
this.flipRtl_ = !!config['flipRtl'];
|
||||
this.altText_ = replaceMessageReferences(config['alt']) || '';
|
||||
this.altText_ = utils.replaceMessageReferences(config['alt']) || '';
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -182,7 +182,7 @@ FieldImage.prototype.configure_ = function(config) {
|
||||
* @package
|
||||
*/
|
||||
FieldImage.prototype.initView = function() {
|
||||
this.imageElement_ = createSvgElement(
|
||||
this.imageElement_ = dom.createSvgElement(
|
||||
Svg.IMAGE, {
|
||||
'height': this.imageHeight_ + 'px',
|
||||
'width': this.size_.width + 'px',
|
||||
@@ -190,7 +190,7 @@ FieldImage.prototype.initView = function() {
|
||||
},
|
||||
this.fieldGroup_);
|
||||
this.imageElement_.setAttributeNS(
|
||||
XLINK_NS, 'xlink:href', /** @type {string} */ (this.value_));
|
||||
dom.XLINK_NS, 'xlink:href', /** @type {string} */ (this.value_));
|
||||
|
||||
if (this.clickHandler_) {
|
||||
this.imageElement_.style.cursor = 'pointer';
|
||||
@@ -227,7 +227,7 @@ FieldImage.prototype.doValueUpdate_ = function(newValue) {
|
||||
this.value_ = newValue;
|
||||
if (this.imageElement_) {
|
||||
this.imageElement_.setAttributeNS(
|
||||
XLINK_NS, 'xlink:href', String(this.value_));
|
||||
dom.XLINK_NS, 'xlink:href', String(this.value_));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ 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');
|
||||
const {replaceMessageReferences} = goog.require('Blockly.utils');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
@@ -47,7 +47,7 @@ const FieldLabel = function(opt_value, opt_class, opt_config) {
|
||||
this.class_ = opt_class || null;
|
||||
}
|
||||
};
|
||||
inherits(FieldLabel, Field);
|
||||
object.inherits(FieldLabel, Field);
|
||||
|
||||
/**
|
||||
* The default value for this field.
|
||||
@@ -65,7 +65,7 @@ FieldLabel.prototype.DEFAULT_VALUE = '';
|
||||
* @nocollapse
|
||||
*/
|
||||
FieldLabel.fromJson = function(options) {
|
||||
const text = replaceMessageReferences(options['text']);
|
||||
const text = utils.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);
|
||||
|
||||
@@ -16,8 +16,8 @@ goog.module.declareLegacyNamespace();
|
||||
|
||||
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');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
@@ -37,7 +37,7 @@ const FieldLabelSerializable = function(opt_value, opt_class, opt_config) {
|
||||
FieldLabelSerializable.superClass_.constructor.call(
|
||||
this, opt_value, opt_class, opt_config);
|
||||
};
|
||||
inherits(FieldLabelSerializable, FieldLabel);
|
||||
object.inherits(FieldLabelSerializable, FieldLabel);
|
||||
|
||||
/**
|
||||
* Construct a FieldLabelSerializable from a JSON arg object,
|
||||
@@ -48,7 +48,7 @@ inherits(FieldLabelSerializable, FieldLabel);
|
||||
* @nocollapse
|
||||
*/
|
||||
FieldLabelSerializable.fromJson = function(options) {
|
||||
const text = replaceMessageReferences(options['text']);
|
||||
const text = utils.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);
|
||||
|
||||
@@ -24,9 +24,9 @@ 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 object = goog.require('Blockly.utils.object');
|
||||
const userAgent = goog.require('Blockly.utils.userAgent');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
const {replaceMessageReferences} = goog.require('Blockly.utils');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
@@ -70,7 +70,7 @@ const FieldMultilineInput = function(opt_value, opt_validator, opt_config) {
|
||||
*/
|
||||
this.isOverflowedY_ = false;
|
||||
};
|
||||
inherits(FieldMultilineInput, FieldTextInput);
|
||||
object.inherits(FieldMultilineInput, FieldTextInput);
|
||||
|
||||
/**
|
||||
* @override
|
||||
@@ -89,7 +89,7 @@ FieldMultilineInput.prototype.configure_ = function(config) {
|
||||
* @nocollapse
|
||||
*/
|
||||
FieldMultilineInput.fromJson = function(options) {
|
||||
const text = replaceMessageReferences(options['text']);
|
||||
const text = utils.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);
|
||||
|
||||
@@ -15,8 +15,8 @@ goog.module.declareLegacyNamespace();
|
||||
|
||||
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');
|
||||
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
|
||||
|
||||
/**
|
||||
@@ -74,7 +74,7 @@ const FieldNumber = function(
|
||||
this.setConstraints(opt_min, opt_max, opt_precision);
|
||||
}
|
||||
};
|
||||
inherits(FieldNumber, FieldTextInput);
|
||||
object.inherits(FieldNumber, FieldTextInput);
|
||||
|
||||
/**
|
||||
* The default value for this field.
|
||||
@@ -313,6 +313,6 @@ FieldNumber.prototype.widgetCreate_ = function() {
|
||||
return htmlInput;
|
||||
};
|
||||
|
||||
register('field_number', FieldNumber);
|
||||
fieldRegistry.register('field_number', FieldNumber);
|
||||
|
||||
exports = FieldNumber;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
goog.module('Blockly.FieldTextInput');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
const Blockly = goog.require('Blockly');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
@@ -28,10 +29,9 @@ 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 object = goog.require('Blockly.utils.object');
|
||||
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');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockChange');
|
||||
|
||||
@@ -95,7 +95,7 @@ const FieldTextInput = function(opt_value, opt_validator, opt_config) {
|
||||
*/
|
||||
this.workspace_ = null;
|
||||
};
|
||||
inherits(FieldTextInput, Field);
|
||||
object.inherits(FieldTextInput, Field);
|
||||
|
||||
/**
|
||||
* The default value for this field.
|
||||
@@ -113,7 +113,7 @@ FieldTextInput.prototype.DEFAULT_VALUE = '';
|
||||
* @nocollapse
|
||||
*/
|
||||
FieldTextInput.fromJson = function(options) {
|
||||
const text = replaceMessageReferences(options['text']);
|
||||
const text = utils.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);
|
||||
@@ -312,7 +312,7 @@ FieldTextInput.prototype.showEditor_ = function(_opt_e, opt_quietInput) {
|
||||
* @private
|
||||
*/
|
||||
FieldTextInput.prototype.showPromptEditor_ = function() {
|
||||
blocklyPrompt(Msg['CHANGE_VALUE_TITLE'], this.getText(), function(text) {
|
||||
Blockly.prompt(Msg['CHANGE_VALUE_TITLE'], this.getText(), function(text) {
|
||||
this.setValue(this.getValueFromEditorText_(text));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
@@ -13,9 +13,12 @@
|
||||
goog.module('Blockly.FieldVariable');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
const FieldDropdown = goog.require('Blockly.FieldDropdown');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Menu = goog.requireType('Blockly.Menu');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const MenuItem = goog.requireType('Blockly.MenuItem');
|
||||
const Msg = goog.require('Blockly.Msg');
|
||||
const Size = goog.require('Blockly.utils.Size');
|
||||
@@ -24,8 +27,8 @@ 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');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockChange');
|
||||
|
||||
@@ -86,7 +89,7 @@ const FieldVariable = function(
|
||||
this.setTypes_(opt_variableTypes, opt_defaultType);
|
||||
}
|
||||
};
|
||||
inherits(FieldVariable, FieldDropdown);
|
||||
object.inherits(FieldVariable, FieldDropdown);
|
||||
|
||||
/**
|
||||
* Construct a FieldVariable from a JSON arg object,
|
||||
@@ -98,7 +101,7 @@ inherits(FieldVariable, FieldDropdown);
|
||||
* @nocollapse
|
||||
*/
|
||||
FieldVariable.fromJson = function(options) {
|
||||
const varName = replaceMessageReferences(options['variable']);
|
||||
const varName = utils.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);
|
||||
|
||||
@@ -14,17 +14,19 @@ goog.module('Blockly.Flyout');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.require('Blockly.Block');
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
const Blockly = goog.require('Blockly');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
const ComponentManager = goog.require('Blockly.ComponentManager');
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
const DeleteArea = goog.require('Blockly.DeleteArea');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const FlyoutButton = goog.require('Blockly.FlyoutButton');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const FlyoutButton = goog.requireType('Blockly.FlyoutButton');
|
||||
const FlyoutMetricsManager = goog.require('Blockly.FlyoutMetricsManager');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IFlyout = goog.require('Blockly.IFlyout');
|
||||
const IFlyout = goog.requireType('Blockly.IFlyout');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Options = goog.requireType('Blockly.Options');
|
||||
const ScrollbarPair = goog.require('Blockly.ScrollbarPair');
|
||||
@@ -38,7 +40,6 @@ const dom = goog.require('Blockly.utils.dom');
|
||||
const toolbox = goog.require('Blockly.utils.toolbox');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
const utilsXml = goog.require('Blockly.utils.xml');
|
||||
const {hideChaff} = goog.require('Blockly');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.blockRendering');
|
||||
/** @suppress {extraRequire} */
|
||||
@@ -659,6 +660,7 @@ Flyout.prototype.getDynamicCategoryContents_ = function(categoryName) {
|
||||
* @private
|
||||
*/
|
||||
Flyout.prototype.createButton_ = function(btnInfo, isLabel) {
|
||||
const FlyoutButton = goog.module.get('Blockly.FlyoutButton');
|
||||
if (!FlyoutButton) {
|
||||
throw Error('Missing require for Blockly.FlyoutButton');
|
||||
}
|
||||
@@ -854,7 +856,7 @@ Flyout.prototype.createBlock = function(originalBlock) {
|
||||
}
|
||||
|
||||
// Close the flyout.
|
||||
hideChaff();
|
||||
Blockly.hideChaff();
|
||||
|
||||
const newVariables = Variables.getAddedVariables(
|
||||
this.targetWorkspace, variablesBeforeCreation);
|
||||
|
||||
@@ -10,42 +10,44 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.FlyoutButton');
|
||||
goog.module('Blockly.FlyoutButton');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.browserEvents');
|
||||
goog.require('Blockly.Css');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.style');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
|
||||
goog.requireType('Blockly.utils.toolbox');
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
const Css = goog.require('Blockly.Css');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const browserEvents = goog.require('Blockly.browserEvents');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const style = goog.require('Blockly.utils.style');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const toolbox = goog.requireType('Blockly.utils.toolbox');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a button in the flyout.
|
||||
* @param {!Blockly.WorkspaceSvg} workspace The workspace in which to place this
|
||||
* @param {!WorkspaceSvg} workspace The workspace in which to place this
|
||||
* button.
|
||||
* @param {!Blockly.WorkspaceSvg} targetWorkspace The flyout's target workspace.
|
||||
* @param {!Blockly.utils.toolbox.ButtonOrLabelInfo} json
|
||||
* @param {!WorkspaceSvg} targetWorkspace The flyout's target workspace.
|
||||
* @param {!toolbox.ButtonOrLabelInfo} json
|
||||
* The JSON specifying the label/button.
|
||||
* @param {boolean} isLabel Whether this button should be styled as a label.
|
||||
* @constructor
|
||||
* @package
|
||||
*/
|
||||
Blockly.FlyoutButton = function(workspace, targetWorkspace, json, isLabel) {
|
||||
const FlyoutButton = function(workspace, targetWorkspace, json, isLabel) {
|
||||
// Labels behave the same as buttons, but are styled differently.
|
||||
|
||||
/**
|
||||
* @type {!Blockly.WorkspaceSvg}
|
||||
* @type {!WorkspaceSvg}
|
||||
* @private
|
||||
*/
|
||||
this.workspace_ = workspace;
|
||||
|
||||
/**
|
||||
* @type {!Blockly.WorkspaceSvg}
|
||||
* @type {!WorkspaceSvg}
|
||||
* @private
|
||||
*/
|
||||
this.targetWorkspace_ = targetWorkspace;
|
||||
@@ -57,10 +59,10 @@ Blockly.FlyoutButton = function(workspace, targetWorkspace, json, isLabel) {
|
||||
this.text_ = json['text'];
|
||||
|
||||
/**
|
||||
* @type {!Blockly.utils.Coordinate}
|
||||
* @type {!Coordinate}
|
||||
* @private
|
||||
*/
|
||||
this.position_ = new Blockly.utils.Coordinate(0, 0);
|
||||
this.position_ = new Coordinate(0, 0);
|
||||
|
||||
/**
|
||||
* Whether this button should be styled as a label.
|
||||
@@ -75,8 +77,8 @@ Blockly.FlyoutButton = function(workspace, targetWorkspace, json, isLabel) {
|
||||
* @private
|
||||
*/
|
||||
this.callbackKey_ = json['callbackKey'] ||
|
||||
/* Check the lower case version too to satisfy IE */
|
||||
json['callbackkey'];
|
||||
/* Check the lower case version too to satisfy IE */
|
||||
json['callbackkey'];
|
||||
|
||||
/**
|
||||
* If specified, a CSS class to add to this button.
|
||||
@@ -87,14 +89,14 @@ Blockly.FlyoutButton = function(workspace, targetWorkspace, json, isLabel) {
|
||||
|
||||
/**
|
||||
* Mouse up event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.onMouseUpWrapper_ = null;
|
||||
|
||||
/**
|
||||
* The JSON specifying the label / button.
|
||||
* @type {!Blockly.utils.toolbox.ButtonOrLabelInfo}
|
||||
* @type {!toolbox.ButtonOrLabelInfo}
|
||||
*/
|
||||
this.info = json;
|
||||
};
|
||||
@@ -102,69 +104,70 @@ Blockly.FlyoutButton = function(workspace, targetWorkspace, json, isLabel) {
|
||||
/**
|
||||
* The horizontal margin around the text in the button.
|
||||
*/
|
||||
Blockly.FlyoutButton.MARGIN_X = 5;
|
||||
FlyoutButton.MARGIN_X = 5;
|
||||
|
||||
/**
|
||||
* The vertical margin around the text in the button.
|
||||
*/
|
||||
Blockly.FlyoutButton.MARGIN_Y = 2;
|
||||
FlyoutButton.MARGIN_Y = 2;
|
||||
|
||||
/**
|
||||
* The width of the button's rect.
|
||||
* @type {number}
|
||||
*/
|
||||
Blockly.FlyoutButton.prototype.width = 0;
|
||||
FlyoutButton.prototype.width = 0;
|
||||
|
||||
/**
|
||||
* The height of the button's rect.
|
||||
* @type {number}
|
||||
*/
|
||||
Blockly.FlyoutButton.prototype.height = 0;
|
||||
FlyoutButton.prototype.height = 0;
|
||||
|
||||
/**
|
||||
* Create the button elements.
|
||||
* @return {!SVGElement} The button's SVG group.
|
||||
*/
|
||||
Blockly.FlyoutButton.prototype.createDom = function() {
|
||||
var cssClass = this.isLabel_ ? 'blocklyFlyoutLabel' : 'blocklyFlyoutButton';
|
||||
FlyoutButton.prototype.createDom = function() {
|
||||
let cssClass = this.isLabel_ ? 'blocklyFlyoutLabel' : 'blocklyFlyoutButton';
|
||||
if (this.cssClass_) {
|
||||
cssClass += ' ' + this.cssClass_;
|
||||
}
|
||||
|
||||
this.svgGroup_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.G, {'class': cssClass},
|
||||
this.workspace_.getCanvas());
|
||||
this.svgGroup_ = dom.createSvgElement(
|
||||
Svg.G, {'class': cssClass}, this.workspace_.getCanvas());
|
||||
|
||||
let shadow;
|
||||
if (!this.isLabel_) {
|
||||
// Shadow rectangle (light source does not mirror in RTL).
|
||||
var shadow = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.RECT,
|
||||
{
|
||||
shadow = dom.createSvgElement(
|
||||
Svg.RECT, {
|
||||
'class': 'blocklyFlyoutButtonShadow',
|
||||
'rx': 4, 'ry': 4, 'x': 1, 'y': 1
|
||||
'rx': 4,
|
||||
'ry': 4,
|
||||
'x': 1,
|
||||
'y': 1
|
||||
},
|
||||
this.svgGroup_);
|
||||
}
|
||||
// Background rectangle.
|
||||
var rect = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.RECT,
|
||||
{
|
||||
'class': this.isLabel_ ?
|
||||
'blocklyFlyoutLabelBackground' : 'blocklyFlyoutButtonBackground',
|
||||
'rx': 4, 'ry': 4
|
||||
const rect = dom.createSvgElement(
|
||||
Svg.RECT, {
|
||||
'class': this.isLabel_ ? 'blocklyFlyoutLabelBackground' :
|
||||
'blocklyFlyoutButtonBackground',
|
||||
'rx': 4,
|
||||
'ry': 4
|
||||
},
|
||||
this.svgGroup_);
|
||||
|
||||
var svgText = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.TEXT,
|
||||
{
|
||||
const svgText = dom.createSvgElement(
|
||||
Svg.TEXT, {
|
||||
'class': this.isLabel_ ? 'blocklyFlyoutLabelText' : 'blocklyText',
|
||||
'x': 0,
|
||||
'y': 0,
|
||||
'text-anchor': 'middle'
|
||||
},
|
||||
this.svgGroup_);
|
||||
var text = Blockly.utils.replaceMessageReferences(this.text_);
|
||||
let text = utils.replaceMessageReferences(this.text_);
|
||||
if (this.workspace_.RTL) {
|
||||
// Force text to be RTL by adding an RLM.
|
||||
text += '\u200F';
|
||||
@@ -172,22 +175,22 @@ Blockly.FlyoutButton.prototype.createDom = function() {
|
||||
svgText.textContent = text;
|
||||
if (this.isLabel_) {
|
||||
this.svgText_ = svgText;
|
||||
this.workspace_.getThemeManager().subscribe(this.svgText_,
|
||||
'flyoutForegroundColour', 'fill');
|
||||
this.workspace_.getThemeManager().subscribe(
|
||||
this.svgText_, 'flyoutForegroundColour', 'fill');
|
||||
}
|
||||
|
||||
var fontSize = Blockly.utils.style.getComputedStyle(svgText, 'fontSize');
|
||||
var fontWeight = Blockly.utils.style.getComputedStyle(svgText, 'fontWeight');
|
||||
var fontFamily = Blockly.utils.style.getComputedStyle(svgText, 'fontFamily');
|
||||
this.width = Blockly.utils.dom.getFastTextWidthWithSizeString(svgText,
|
||||
fontSize, fontWeight, fontFamily);
|
||||
var fontMetrics = Blockly.utils.dom.measureFontMetrics(text, fontSize,
|
||||
fontWeight, fontFamily);
|
||||
const fontSize = style.getComputedStyle(svgText, 'fontSize');
|
||||
const fontWeight = style.getComputedStyle(svgText, 'fontWeight');
|
||||
const fontFamily = style.getComputedStyle(svgText, 'fontFamily');
|
||||
this.width = dom.getFastTextWidthWithSizeString(
|
||||
svgText, fontSize, fontWeight, fontFamily);
|
||||
const fontMetrics =
|
||||
dom.measureFontMetrics(text, fontSize, fontWeight, fontFamily);
|
||||
this.height = fontMetrics.height;
|
||||
|
||||
if (!this.isLabel_) {
|
||||
this.width += 2 * Blockly.FlyoutButton.MARGIN_X;
|
||||
this.height += 2 * Blockly.FlyoutButton.MARGIN_Y;
|
||||
this.width += 2 * FlyoutButton.MARGIN_X;
|
||||
this.height += 2 * FlyoutButton.MARGIN_Y;
|
||||
shadow.setAttribute('width', this.width);
|
||||
shadow.setAttribute('height', this.height);
|
||||
}
|
||||
@@ -195,12 +198,12 @@ Blockly.FlyoutButton.prototype.createDom = function() {
|
||||
rect.setAttribute('height', this.height);
|
||||
|
||||
svgText.setAttribute('x', this.width / 2);
|
||||
svgText.setAttribute('y', this.height / 2 - fontMetrics.height / 2 +
|
||||
fontMetrics.baseline);
|
||||
svgText.setAttribute(
|
||||
'y', this.height / 2 - fontMetrics.height / 2 + fontMetrics.baseline);
|
||||
|
||||
this.updateTransform_();
|
||||
|
||||
this.onMouseUpWrapper_ = Blockly.browserEvents.conditionalBind(
|
||||
this.onMouseUpWrapper_ = browserEvents.conditionalBind(
|
||||
this.svgGroup_, 'mouseup', this, this.onMouseUp_);
|
||||
return this.svgGroup_;
|
||||
};
|
||||
@@ -208,7 +211,7 @@ Blockly.FlyoutButton.prototype.createDom = function() {
|
||||
/**
|
||||
* Correctly position the flyout button and make it visible.
|
||||
*/
|
||||
Blockly.FlyoutButton.prototype.show = function() {
|
||||
FlyoutButton.prototype.show = function() {
|
||||
this.updateTransform_();
|
||||
this.svgGroup_.setAttribute('display', 'block');
|
||||
};
|
||||
@@ -217,8 +220,9 @@ Blockly.FlyoutButton.prototype.show = function() {
|
||||
* Update SVG attributes to match internal state.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FlyoutButton.prototype.updateTransform_ = function() {
|
||||
this.svgGroup_.setAttribute('transform',
|
||||
FlyoutButton.prototype.updateTransform_ = function() {
|
||||
this.svgGroup_.setAttribute(
|
||||
'transform',
|
||||
'translate(' + this.position_.x + ',' + this.position_.y + ')');
|
||||
};
|
||||
|
||||
@@ -227,7 +231,7 @@ Blockly.FlyoutButton.prototype.updateTransform_ = function() {
|
||||
* @param {number} x The new x coordinate.
|
||||
* @param {number} y The new y coordinate.
|
||||
*/
|
||||
Blockly.FlyoutButton.prototype.moveTo = function(x, y) {
|
||||
FlyoutButton.prototype.moveTo = function(x, y) {
|
||||
this.position_.x = x;
|
||||
this.position_.y = y;
|
||||
this.updateTransform_();
|
||||
@@ -236,44 +240,44 @@ Blockly.FlyoutButton.prototype.moveTo = function(x, y) {
|
||||
/**
|
||||
* @return {boolean} Whether or not the button is a label.
|
||||
*/
|
||||
Blockly.FlyoutButton.prototype.isLabel = function() {
|
||||
FlyoutButton.prototype.isLabel = function() {
|
||||
return this.isLabel_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Location of the button.
|
||||
* @return {!Blockly.utils.Coordinate} x, y coordinates.
|
||||
* @return {!Coordinate} x, y coordinates.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FlyoutButton.prototype.getPosition = function() {
|
||||
FlyoutButton.prototype.getPosition = function() {
|
||||
return this.position_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {string} Text of the button.
|
||||
*/
|
||||
Blockly.FlyoutButton.prototype.getButtonText = function() {
|
||||
FlyoutButton.prototype.getButtonText = function() {
|
||||
return this.text_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the button's target workspace.
|
||||
* @return {!Blockly.WorkspaceSvg} The target workspace of the flyout where this
|
||||
* @return {!WorkspaceSvg} The target workspace of the flyout where this
|
||||
* button resides.
|
||||
*/
|
||||
Blockly.FlyoutButton.prototype.getTargetWorkspace = function() {
|
||||
FlyoutButton.prototype.getTargetWorkspace = function() {
|
||||
return this.targetWorkspace_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispose of this button.
|
||||
*/
|
||||
Blockly.FlyoutButton.prototype.dispose = function() {
|
||||
FlyoutButton.prototype.dispose = function() {
|
||||
if (this.onMouseUpWrapper_) {
|
||||
Blockly.browserEvents.unbind(this.onMouseUpWrapper_);
|
||||
browserEvents.unbind(this.onMouseUpWrapper_);
|
||||
}
|
||||
if (this.svgGroup_) {
|
||||
Blockly.utils.dom.removeNode(this.svgGroup_);
|
||||
dom.removeNode(this.svgGroup_);
|
||||
}
|
||||
if (this.svgText_) {
|
||||
this.workspace_.getThemeManager().unsubscribe(this.svgText_);
|
||||
@@ -285,16 +289,18 @@ Blockly.FlyoutButton.prototype.dispose = function() {
|
||||
* @param {!Event} e Mouse up event.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FlyoutButton.prototype.onMouseUp_ = function(e) {
|
||||
var gesture = this.targetWorkspace_.getGesture(e);
|
||||
FlyoutButton.prototype.onMouseUp_ = function(e) {
|
||||
const gesture = this.targetWorkspace_.getGesture(e);
|
||||
if (gesture) {
|
||||
gesture.cancel();
|
||||
}
|
||||
|
||||
if (this.isLabel_ && this.callbackKey_) {
|
||||
console.warn('Labels should not have callbacks. Label text: ' + this.text_);
|
||||
} else if (!this.isLabel_ && !(this.callbackKey_ &&
|
||||
this.targetWorkspace_.getButtonCallback(this.callbackKey_))) {
|
||||
} else if (
|
||||
!this.isLabel_ &&
|
||||
!(this.callbackKey_ &&
|
||||
this.targetWorkspace_.getButtonCallback(this.callbackKey_))) {
|
||||
console.warn('Buttons should have callbacks. Button text: ' + this.text_);
|
||||
} else if (!this.isLabel_) {
|
||||
this.targetWorkspace_.getButtonCallback(this.callbackKey_)(this);
|
||||
@@ -304,7 +310,7 @@ Blockly.FlyoutButton.prototype.onMouseUp_ = function(e) {
|
||||
/**
|
||||
* CSS for buttons and labels. See css.js for use.
|
||||
*/
|
||||
Blockly.Css.register([
|
||||
Css.register([
|
||||
/* eslint-disable indent */
|
||||
'.blocklyFlyoutButton {',
|
||||
'fill: #888;',
|
||||
@@ -328,3 +334,5 @@ Blockly.Css.register([
|
||||
'}',
|
||||
/* eslint-enable indent */
|
||||
]);
|
||||
|
||||
exports = FlyoutButton;
|
||||
|
||||
@@ -22,10 +22,10 @@ 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 object = goog.require('Blockly.utils.object');
|
||||
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');
|
||||
const toolbox = goog.require('Blockly.utils.toolbox');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
@@ -39,7 +39,7 @@ const HorizontalFlyout = function(workspaceOptions) {
|
||||
HorizontalFlyout.superClass_.constructor.call(this, workspaceOptions);
|
||||
this.horizontalLayout = true;
|
||||
};
|
||||
inherits(HorizontalFlyout, Flyout);
|
||||
object.inherits(HorizontalFlyout, Flyout);
|
||||
|
||||
/**
|
||||
* Sets the translation of the flyout to match the scrollbars.
|
||||
@@ -92,7 +92,7 @@ HorizontalFlyout.prototype.getY = function() {
|
||||
const toolboxMetrics = metricsManager.getToolboxMetrics();
|
||||
|
||||
let y = 0;
|
||||
const atTop = this.toolboxPosition_ == Position.TOP;
|
||||
const atTop = this.toolboxPosition_ == toolbox.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.
|
||||
@@ -159,7 +159,7 @@ HorizontalFlyout.prototype.position = function() {
|
||||
* @private
|
||||
*/
|
||||
HorizontalFlyout.prototype.setBackgroundPath_ = function(width, height) {
|
||||
const atTop = this.toolboxPosition_ == Position.TOP;
|
||||
const atTop = this.toolboxPosition_ == toolbox.Position.TOP;
|
||||
// Start at top left.
|
||||
const path = ['M 0,' + (atTop ? 0 : this.CORNER_RADIUS)];
|
||||
|
||||
@@ -210,7 +210,7 @@ HorizontalFlyout.prototype.scrollToStart = function() {
|
||||
* @protected
|
||||
*/
|
||||
HorizontalFlyout.prototype.wheel_ = function(e) {
|
||||
const scrollDelta = getScrollDeltaPixels(e);
|
||||
const scrollDelta = utils.getScrollDeltaPixels(e);
|
||||
const delta = scrollDelta.x || scrollDelta.y;
|
||||
|
||||
if (delta) {
|
||||
@@ -326,7 +326,7 @@ HorizontalFlyout.prototype.getClientRect = function() {
|
||||
const BIG_NUM = 1000000000;
|
||||
const top = flyoutRect.top;
|
||||
|
||||
if (this.toolboxPosition_ == Position.TOP) {
|
||||
if (this.toolboxPosition_ == toolbox.Position.TOP) {
|
||||
const height = flyoutRect.height;
|
||||
return new Rect(-BIG_NUM, top + height, -BIG_NUM, BIG_NUM);
|
||||
} else { // Bottom.
|
||||
@@ -335,7 +335,7 @@ HorizontalFlyout.prototype.getClientRect = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute height of flyout. Position mat under each block.
|
||||
* Compute height of flyout. toolbox.Position mat under each block.
|
||||
* For RTL: Lay out the blocks right-aligned.
|
||||
* @protected
|
||||
*/
|
||||
@@ -362,7 +362,7 @@ HorizontalFlyout.prototype.reflowInternal_ = function() {
|
||||
}
|
||||
|
||||
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_ &&
|
||||
this.toolboxPosition_ == Position.TOP &&
|
||||
this.toolboxPosition_ == toolbox.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
|
||||
|
||||
@@ -22,10 +22,10 @@ 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 object = goog.require('Blockly.utils.object');
|
||||
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');
|
||||
const toolbox = goog.require('Blockly.utils.toolbox');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Block');
|
||||
/** @suppress {extraRequire} */
|
||||
@@ -42,7 +42,7 @@ goog.require('Blockly.constants');
|
||||
const VerticalFlyout = function(workspaceOptions) {
|
||||
VerticalFlyout.superClass_.constructor.call(this, workspaceOptions);
|
||||
};
|
||||
inherits(VerticalFlyout, Flyout);
|
||||
object.inherits(VerticalFlyout, Flyout);
|
||||
|
||||
/**
|
||||
* The name of the vertical flyout in the registry.
|
||||
@@ -94,14 +94,14 @@ VerticalFlyout.prototype.getX = function() {
|
||||
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_) {
|
||||
// If there is a category toolbox.
|
||||
if (this.targetWorkspace.getToolbox()) {
|
||||
if (this.toolboxPosition_ == Position.LEFT) {
|
||||
if (this.toolboxPosition_ == toolbox.Position.LEFT) {
|
||||
x = toolboxMetrics.width;
|
||||
} else {
|
||||
x = viewMetrics.width - this.width_;
|
||||
}
|
||||
// Simple (flyout-only) toolbox.
|
||||
} else {
|
||||
if (this.toolboxPosition_ == Position.LEFT) {
|
||||
if (this.toolboxPosition_ == toolbox.Position.LEFT) {
|
||||
x = 0;
|
||||
} else {
|
||||
// The simple flyout does not cover the workspace.
|
||||
@@ -110,7 +110,7 @@ VerticalFlyout.prototype.getX = function() {
|
||||
}
|
||||
// Trashcan flyout is opposite the main flyout.
|
||||
} else {
|
||||
if (this.toolboxPosition_ == Position.LEFT) {
|
||||
if (this.toolboxPosition_ == toolbox.Position.LEFT) {
|
||||
x = 0;
|
||||
} else {
|
||||
// Because the anchor point of the flyout is on the left, but we want
|
||||
@@ -165,7 +165,7 @@ VerticalFlyout.prototype.position = function() {
|
||||
* @private
|
||||
*/
|
||||
VerticalFlyout.prototype.setBackgroundPath_ = function(width, height) {
|
||||
const atRight = this.toolboxPosition_ == Position.RIGHT;
|
||||
const atRight = this.toolboxPosition_ == toolbox.Position.RIGHT;
|
||||
const totalWidth = width + this.CORNER_RADIUS;
|
||||
|
||||
// Decide whether to start on the left or right.
|
||||
@@ -201,7 +201,7 @@ VerticalFlyout.prototype.scrollToStart = function() {
|
||||
* @protected
|
||||
*/
|
||||
VerticalFlyout.prototype.wheel_ = function(e) {
|
||||
const scrollDelta = getScrollDeltaPixels(e);
|
||||
const scrollDelta = utils.getScrollDeltaPixels(e);
|
||||
|
||||
if (scrollDelta.y) {
|
||||
const metricsManager = this.workspace_.getMetricsManager();
|
||||
@@ -306,7 +306,7 @@ VerticalFlyout.prototype.getClientRect = function() {
|
||||
const BIG_NUM = 1000000000;
|
||||
const left = flyoutRect.left;
|
||||
|
||||
if (this.toolboxPosition_ == Position.LEFT) {
|
||||
if (this.toolboxPosition_ == toolbox.Position.LEFT) {
|
||||
const width = flyoutRect.width;
|
||||
return new Rect(-BIG_NUM, BIG_NUM, -BIG_NUM, left + width);
|
||||
} else { // Right
|
||||
@@ -315,7 +315,7 @@ VerticalFlyout.prototype.getClientRect = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute width of flyout. Position mat under each block.
|
||||
* Compute width of flyout. toolbox.Position mat under each block.
|
||||
* For RTL: Lay out the blocks and buttons to be right-aligned.
|
||||
* @protected
|
||||
*/
|
||||
@@ -363,7 +363,7 @@ VerticalFlyout.prototype.reflowInternal_ = function() {
|
||||
}
|
||||
|
||||
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_ &&
|
||||
this.toolboxPosition_ == Position.LEFT &&
|
||||
this.toolboxPosition_ == toolbox.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
|
||||
|
||||
@@ -20,9 +20,9 @@ const Block = goog.requireType('Blockly.Block');
|
||||
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 common = goog.require('Blockly.common');
|
||||
const deprecation = goog.require('Blockly.utils.deprecation');
|
||||
const {getMainWorkspace} = goog.require('Blockly');
|
||||
const internalConstants = goog.require('Blockly.internalConstants');
|
||||
|
||||
|
||||
/**
|
||||
@@ -98,7 +98,7 @@ 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 = getMainWorkspace();
|
||||
workspace = common.getMainWorkspace();
|
||||
}
|
||||
let code = [];
|
||||
this.init(workspace);
|
||||
|
||||
@@ -20,8 +20,8 @@ goog.module.declareLegacyNamespace();
|
||||
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');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Field = goog.requireType('Blockly.Field');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IBlockDragger = goog.requireType('Blockly.IBlockDragger');
|
||||
@@ -31,8 +31,8 @@ const IBubble = goog.requireType('Blockly.IBubble');
|
||||
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');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const WorkspaceDragger = goog.require('Blockly.WorkspaceDragger');
|
||||
const blockAnimations = goog.require('Blockly.blockAnimations');
|
||||
@@ -113,7 +113,7 @@ const 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().
|
||||
* Blockly.common.getMainWorkspace().
|
||||
* @type {WorkspaceSvg}
|
||||
* @protected
|
||||
*/
|
||||
|
||||
@@ -22,7 +22,7 @@ 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');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
@@ -135,7 +135,7 @@ Icon.prototype.iconClick_ = function(e) {
|
||||
// Drag operation is concluding. Don't open the editor.
|
||||
return;
|
||||
}
|
||||
if (!this.block_.isInFlyout && !isRightButton(e)) {
|
||||
if (!this.block_.isInFlyout && !utils.isRightButton(e)) {
|
||||
this.setVisible(!this.isVisible());
|
||||
}
|
||||
};
|
||||
@@ -167,7 +167,7 @@ Icon.prototype.setIconLocation = function(xy) {
|
||||
Icon.prototype.computeIconLocation = function() {
|
||||
// Find coordinates for the centre of the icon and update the arrow.
|
||||
const blockXY = this.block_.getRelativeToSurfaceXY();
|
||||
const iconXY = getRelativeXY(
|
||||
const iconXY = utils.getRelativeXY(
|
||||
/** @type {!SVGElement} */ (this.iconGroup_));
|
||||
const newXY = new Coordinate(
|
||||
blockXY.x + iconXY.x + this.SIZE / 2,
|
||||
|
||||
@@ -14,6 +14,7 @@ goog.provide('Blockly.inject');
|
||||
|
||||
goog.require('Blockly.BlockDragSurfaceSvg');
|
||||
goog.require('Blockly.browserEvents');
|
||||
goog.require('Blockly.common');
|
||||
goog.require('Blockly.Css');
|
||||
goog.require('Blockly.DropDownDiv');
|
||||
goog.require('Blockly.Events');
|
||||
@@ -33,7 +34,9 @@ goog.require('Blockly.WorkspaceDragSurfaceSvg');
|
||||
goog.require('Blockly.WorkspaceSvg');
|
||||
goog.require('Blockly.WidgetDiv');
|
||||
|
||||
goog.requireType('Blockly.BlocklyOptions');
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.WorkspaceCommentSvg');
|
||||
|
||||
|
||||
/**
|
||||
@@ -44,8 +47,6 @@ goog.requireType('Blockly.BlockSvg');
|
||||
* @return {!Blockly.WorkspaceSvg} Newly created main workspace.
|
||||
*/
|
||||
Blockly.inject = function(container, opt_options) {
|
||||
Blockly.checkBlockColourConstants();
|
||||
|
||||
if (typeof container == 'string') {
|
||||
container = document.getElementById(container) ||
|
||||
document.querySelector(container);
|
||||
@@ -77,12 +78,12 @@ Blockly.inject = function(container, opt_options) {
|
||||
Blockly.init_(workspace);
|
||||
|
||||
// Keep focus on the first workspace so entering keyboard navigation looks correct.
|
||||
Blockly.mainWorkspace = workspace;
|
||||
Blockly.common.setMainWorkspace(workspace);
|
||||
|
||||
Blockly.svgResize(workspace);
|
||||
|
||||
subContainer.addEventListener('focusin', function() {
|
||||
Blockly.mainWorkspace = workspace;
|
||||
Blockly.common.setMainWorkspace(workspace);
|
||||
});
|
||||
|
||||
return workspace;
|
||||
@@ -215,7 +216,9 @@ Blockly.extractObjectFromEvent_ = function(workspace, e) {
|
||||
break;
|
||||
case Blockly.Events.COMMENT_CREATE:
|
||||
case Blockly.Events.COMMENT_MOVE:
|
||||
object = workspace.getCommentById(e.commentId);
|
||||
object = (
|
||||
/** @type {?Blockly.WorkspaceCommentSvg} */
|
||||
(workspace.getCommentById(e.commentId)));
|
||||
break;
|
||||
}
|
||||
return object;
|
||||
@@ -439,7 +442,7 @@ Blockly.inject.bindDocumentEvents_ = function() {
|
||||
window, 'orientationchange', document, function() {
|
||||
// TODO (#397): Fix for multiple Blockly workspaces.
|
||||
Blockly.svgResize(/** @type {!Blockly.WorkspaceSvg} */
|
||||
(Blockly.getMainWorkspace()));
|
||||
(Blockly.common.getMainWorkspace()));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ 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');
|
||||
const Connection = goog.requireType('Blockly.Connection');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Field = goog.requireType('Blockly.Field');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
|
||||
@@ -11,19 +11,22 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.inputTypes');
|
||||
goog.module('Blockly.inputTypes');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.connectionTypes');
|
||||
const connectionTypes = goog.require('Blockly.connectionTypes');
|
||||
|
||||
/**
|
||||
* Enum for the type of a connection or input.
|
||||
* @enum {number}
|
||||
*/
|
||||
Blockly.inputTypes = {
|
||||
const inputTypes = {
|
||||
// A right-facing value input. E.g. 'set item to' or 'return'.
|
||||
VALUE: Blockly.connectionTypes.INPUT_VALUE,
|
||||
VALUE: connectionTypes.INPUT_VALUE,
|
||||
// A down-facing block stack. E.g. 'if-do' or 'else'.
|
||||
STATEMENT: Blockly.connectionTypes.NEXT_STATEMENT,
|
||||
STATEMENT: connectionTypes.NEXT_STATEMENT,
|
||||
// A dummy input. Used to add field(s) with no input.
|
||||
DUMMY: 5
|
||||
};
|
||||
|
||||
exports = inputTypes;
|
||||
|
||||
@@ -10,34 +10,45 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.InsertionMarkerManager');
|
||||
goog.module('Blockly.InsertionMarkerManager');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.blockAnimations');
|
||||
goog.require('Blockly.ComponentManager');
|
||||
goog.require('Blockly.connectionTypes');
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.internalConstants');
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.RenderedConnection');
|
||||
goog.requireType('Blockly.utils.Coordinate');
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
// 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 ComponentManager = goog.require('Blockly.ComponentManager');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Coordinate = goog.requireType('Blockly.utils.Coordinate');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
/* 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 RenderedConnection = goog.requireType('Blockly.RenderedConnection');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const blockAnimations = goog.require('Blockly.blockAnimations');
|
||||
const connectionTypes = goog.require('Blockly.connectionTypes');
|
||||
const constants = goog.require('Blockly.constants');
|
||||
const internalConstants = goog.require('Blockly.internalConstants');
|
||||
|
||||
|
||||
/**
|
||||
* Class that controls updates to connections during drags. It is primarily
|
||||
* responsible for finding the closest eligible connection and highlighting or
|
||||
* unhiglighting it as needed during a drag.
|
||||
* @param {!Blockly.BlockSvg} block The top block in the stack being dragged.
|
||||
* @param {!BlockSvg} block The top block in the stack being dragged.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.InsertionMarkerManager = function(block) {
|
||||
const InsertionMarkerManager = function(block) {
|
||||
Blockly.selected = block;
|
||||
|
||||
/**
|
||||
* The top block in the stack being dragged.
|
||||
* Does not change during a drag.
|
||||
* @type {!Blockly.BlockSvg}
|
||||
* @type {!BlockSvg}
|
||||
* @private
|
||||
*/
|
||||
this.topBlock_ = block;
|
||||
@@ -45,7 +56,7 @@ Blockly.InsertionMarkerManager = function(block) {
|
||||
/**
|
||||
* The workspace on which these connections are being dragged.
|
||||
* Does not change during a drag.
|
||||
* @type {!Blockly.WorkspaceSvg}
|
||||
* @type {!WorkspaceSvg}
|
||||
* @private
|
||||
*/
|
||||
this.workspace_ = block.workspace;
|
||||
@@ -54,7 +65,7 @@ Blockly.InsertionMarkerManager = function(block) {
|
||||
* The last connection on the stack, if it's not the last connection on the
|
||||
* first block.
|
||||
* Set in initAvailableConnections, if at all.
|
||||
* @type {Blockly.RenderedConnection}
|
||||
* @type {RenderedConnection}
|
||||
* @private
|
||||
*/
|
||||
this.lastOnStack_ = null;
|
||||
@@ -63,7 +74,7 @@ Blockly.InsertionMarkerManager = function(block) {
|
||||
* The insertion marker corresponding to the last block in the stack, if
|
||||
* that's not the same as the first block in the stack.
|
||||
* Set in initAvailableConnections, if at all
|
||||
* @type {Blockly.BlockSvg}
|
||||
* @type {BlockSvg}
|
||||
* @private
|
||||
*/
|
||||
this.lastMarker_ = null;
|
||||
@@ -71,7 +82,7 @@ Blockly.InsertionMarkerManager = function(block) {
|
||||
/**
|
||||
* The insertion marker that shows up between blocks to show where a block
|
||||
* would go if dropped immediately.
|
||||
* @type {Blockly.BlockSvg}
|
||||
* @type {BlockSvg}
|
||||
* @private
|
||||
*/
|
||||
this.firstMarker_ = this.createMarkerBlock_(this.topBlock_);
|
||||
@@ -80,7 +91,7 @@ Blockly.InsertionMarkerManager = function(block) {
|
||||
* The connection that this block would connect to if released immediately.
|
||||
* Updated on every mouse move.
|
||||
* This is not on any of the blocks that are being dragged.
|
||||
* @type {Blockly.RenderedConnection}
|
||||
* @type {RenderedConnection}
|
||||
* @private
|
||||
*/
|
||||
this.closestConnection_ = null;
|
||||
@@ -91,7 +102,7 @@ Blockly.InsertionMarkerManager = function(block) {
|
||||
* Updated on every mouse move.
|
||||
* This is on the top block that is being dragged or the last block in the
|
||||
* dragging stack.
|
||||
* @type {Blockly.RenderedConnection}
|
||||
* @type {RenderedConnection}
|
||||
* @private
|
||||
*/
|
||||
this.localConnection_ = null;
|
||||
@@ -107,21 +118,21 @@ Blockly.InsertionMarkerManager = function(block) {
|
||||
/**
|
||||
* Connection on the insertion marker block that corresponds to
|
||||
* this.localConnection_ on the currently dragged block.
|
||||
* @type {Blockly.RenderedConnection}
|
||||
* @type {RenderedConnection}
|
||||
* @private
|
||||
*/
|
||||
this.markerConnection_ = null;
|
||||
|
||||
/**
|
||||
* The block that currently has an input being highlighted, or null.
|
||||
* @type {Blockly.BlockSvg}
|
||||
* @type {BlockSvg}
|
||||
* @private
|
||||
*/
|
||||
this.highlightedBlock_ = null;
|
||||
|
||||
/**
|
||||
* The block being faded to indicate replacement, or null.
|
||||
* @type {Blockly.BlockSvg}
|
||||
* @type {BlockSvg}
|
||||
* @private
|
||||
*/
|
||||
this.fadedBlock_ = null;
|
||||
@@ -131,7 +142,7 @@ Blockly.InsertionMarkerManager = function(block) {
|
||||
* other blocks. This includes all open connections on the top block, as well
|
||||
* as the last connection on the block stack.
|
||||
* Does not change during a drag.
|
||||
* @type {!Array<!Blockly.RenderedConnection>}
|
||||
* @type {!Array<!RenderedConnection>}
|
||||
* @private
|
||||
*/
|
||||
this.availableConnections_ = this.initAvailableConnections_();
|
||||
@@ -142,7 +153,7 @@ Blockly.InsertionMarkerManager = function(block) {
|
||||
* could display.
|
||||
* @enum {number}
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.PREVIEW_TYPE = {
|
||||
InsertionMarkerManager.PREVIEW_TYPE = {
|
||||
INSERTION_MARKER: 0,
|
||||
INPUT_OUTLINE: 1,
|
||||
REPLACEMENT_FADE: 2,
|
||||
@@ -154,7 +165,7 @@ Blockly.InsertionMarkerManager.PREVIEW_TYPE = {
|
||||
* @type {string}
|
||||
* @const
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.DUPLICATE_BLOCK_ERROR = 'The insertion marker ' +
|
||||
InsertionMarkerManager.DUPLICATE_BLOCK_ERROR = 'The insertion marker ' +
|
||||
'manager tried to create a marker but the result is missing %1. If ' +
|
||||
'you are using a mutator, make sure your domToMutation method is ' +
|
||||
'properly defined.';
|
||||
@@ -163,10 +174,10 @@ Blockly.InsertionMarkerManager.DUPLICATE_BLOCK_ERROR = 'The insertion marker ' +
|
||||
* Sever all links from this object.
|
||||
* @package
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.dispose = function() {
|
||||
InsertionMarkerManager.prototype.dispose = function() {
|
||||
this.availableConnections_.length = 0;
|
||||
|
||||
Blockly.Events.disable();
|
||||
Events.disable();
|
||||
try {
|
||||
if (this.firstMarker_) {
|
||||
this.firstMarker_.dispose();
|
||||
@@ -175,7 +186,7 @@ Blockly.InsertionMarkerManager.prototype.dispose = function() {
|
||||
this.lastMarker_.dispose();
|
||||
}
|
||||
} finally {
|
||||
Blockly.Events.enable();
|
||||
Events.enable();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -184,7 +195,7 @@ Blockly.InsertionMarkerManager.prototype.dispose = function() {
|
||||
* change if a block is unplugged and the stack is healed.
|
||||
* @package
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.updateAvailableConnections = function() {
|
||||
InsertionMarkerManager.prototype.updateAvailableConnections = function() {
|
||||
this.availableConnections_ = this.initAvailableConnections_();
|
||||
};
|
||||
|
||||
@@ -194,7 +205,7 @@ Blockly.InsertionMarkerManager.prototype.updateAvailableConnections = function()
|
||||
* @return {boolean} True if the block would be deleted if dropped immediately.
|
||||
* @package
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.wouldDeleteBlock = function() {
|
||||
InsertionMarkerManager.prototype.wouldDeleteBlock = function() {
|
||||
return this.wouldDeleteBlock_;
|
||||
};
|
||||
|
||||
@@ -205,7 +216,7 @@ Blockly.InsertionMarkerManager.prototype.wouldDeleteBlock = function() {
|
||||
* immediately.
|
||||
* @package
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.wouldConnectBlock = function() {
|
||||
InsertionMarkerManager.prototype.wouldConnectBlock = function() {
|
||||
return !!this.closestConnection_;
|
||||
};
|
||||
|
||||
@@ -214,23 +225,23 @@ Blockly.InsertionMarkerManager.prototype.wouldConnectBlock = function() {
|
||||
* This should be called at the end of a drag.
|
||||
* @package
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.applyConnections = function() {
|
||||
InsertionMarkerManager.prototype.applyConnections = function() {
|
||||
if (this.closestConnection_) {
|
||||
// Don't fire events for insertion markers.
|
||||
Blockly.Events.disable();
|
||||
Events.disable();
|
||||
this.hidePreview_();
|
||||
Blockly.Events.enable();
|
||||
Events.enable();
|
||||
// Connect two blocks together.
|
||||
this.localConnection_.connect(this.closestConnection_);
|
||||
if (this.topBlock_.rendered) {
|
||||
// Trigger a connection animation.
|
||||
// Determine which connection is inferior (lower in the source stack).
|
||||
var inferiorConnection = this.localConnection_.isSuperior() ?
|
||||
this.closestConnection_ : this.localConnection_;
|
||||
Blockly.blockAnimations.connectionUiEffect(
|
||||
inferiorConnection.getSourceBlock());
|
||||
const inferiorConnection = this.localConnection_.isSuperior() ?
|
||||
this.closestConnection_ :
|
||||
this.localConnection_;
|
||||
blockAnimations.connectionUiEffect(inferiorConnection.getSourceBlock());
|
||||
// Bring the just-edited stack to the front.
|
||||
var rootBlock = this.topBlock_.getRootBlock();
|
||||
const rootBlock = this.topBlock_.getRootBlock();
|
||||
rootBlock.bringToFront();
|
||||
}
|
||||
}
|
||||
@@ -238,46 +249,47 @@ Blockly.InsertionMarkerManager.prototype.applyConnections = function() {
|
||||
|
||||
/**
|
||||
* Update connections based on the most recent move location.
|
||||
* @param {!Blockly.utils.Coordinate} dxy Position relative to drag start,
|
||||
* @param {!Coordinate} dxy Position relative to drag start,
|
||||
* in workspace units.
|
||||
* @param {?Blockly.IDragTarget} dragTarget The drag target that the block is
|
||||
* @param {?IDragTarget} dragTarget The drag target that the block is
|
||||
* currently over.
|
||||
* @package
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.update = function(dxy, dragTarget) {
|
||||
var candidate = this.getCandidate_(dxy);
|
||||
InsertionMarkerManager.prototype.update = function(dxy, dragTarget) {
|
||||
const candidate = this.getCandidate_(dxy);
|
||||
|
||||
this.wouldDeleteBlock_ = this.shouldDelete_(candidate, dragTarget);
|
||||
|
||||
var shouldUpdate = this.wouldDeleteBlock_ ||
|
||||
this.shouldUpdatePreviews_(candidate, dxy);
|
||||
const shouldUpdate =
|
||||
this.wouldDeleteBlock_ || this.shouldUpdatePreviews_(candidate, dxy);
|
||||
|
||||
if (shouldUpdate) {
|
||||
// Don't fire events for insertion marker creation or movement.
|
||||
Blockly.Events.disable();
|
||||
Events.disable();
|
||||
this.maybeHidePreview_(candidate);
|
||||
this.maybeShowPreview_(candidate);
|
||||
Blockly.Events.enable();
|
||||
Events.enable();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an insertion marker that represents the given block.
|
||||
* @param {!Blockly.BlockSvg} sourceBlock The block that the insertion marker
|
||||
* @param {!BlockSvg} sourceBlock The block that the insertion marker
|
||||
* will represent.
|
||||
* @return {!Blockly.BlockSvg} The insertion marker that represents the given
|
||||
* @return {!BlockSvg} The insertion marker that represents the given
|
||||
* block.
|
||||
* @private
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.createMarkerBlock_ = function(sourceBlock) {
|
||||
var imType = sourceBlock.type;
|
||||
InsertionMarkerManager.prototype.createMarkerBlock_ = function(sourceBlock) {
|
||||
const imType = sourceBlock.type;
|
||||
|
||||
Blockly.Events.disable();
|
||||
Events.disable();
|
||||
let result;
|
||||
try {
|
||||
var result = this.workspace_.newBlock(imType);
|
||||
result = this.workspace_.newBlock(imType);
|
||||
result.setInsertionMarker(true);
|
||||
if (sourceBlock.mutationToDom) {
|
||||
var oldMutationDom = sourceBlock.mutationToDom();
|
||||
const oldMutationDom = sourceBlock.mutationToDom();
|
||||
if (oldMutationDom) {
|
||||
result.domToMutation(oldMutationDom);
|
||||
}
|
||||
@@ -285,22 +297,22 @@ Blockly.InsertionMarkerManager.prototype.createMarkerBlock_ = function(sourceBlo
|
||||
// Copy field values from the other block. These values may impact the
|
||||
// rendered size of the insertion marker. Note that we do not care about
|
||||
// child blocks here.
|
||||
for (var i = 0; i < sourceBlock.inputList.length; i++) {
|
||||
var sourceInput = sourceBlock.inputList[i];
|
||||
if (sourceInput.name == Blockly.constants.COLLAPSED_INPUT_NAME) {
|
||||
for (let i = 0; i < sourceBlock.inputList.length; i++) {
|
||||
const sourceInput = sourceBlock.inputList[i];
|
||||
if (sourceInput.name == constants.COLLAPSED_INPUT_NAME) {
|
||||
continue; // Ignore the collapsed input.
|
||||
}
|
||||
var resultInput = result.inputList[i];
|
||||
const resultInput = result.inputList[i];
|
||||
if (!resultInput) {
|
||||
throw new Error(Blockly.InsertionMarkerManager.DUPLICATE_BLOCK_ERROR
|
||||
.replace('%1', 'an input'));
|
||||
throw new Error(InsertionMarkerManager.DUPLICATE_BLOCK_ERROR.replace(
|
||||
'%1', 'an input'));
|
||||
}
|
||||
for (var j = 0; j < sourceInput.fieldRow.length; j++) {
|
||||
var sourceField = sourceInput.fieldRow[j];
|
||||
var resultField = resultInput.fieldRow[j];
|
||||
for (let j = 0; j < sourceInput.fieldRow.length; j++) {
|
||||
const sourceField = sourceInput.fieldRow[j];
|
||||
const resultField = resultInput.fieldRow[j];
|
||||
if (!resultField) {
|
||||
throw new Error(Blockly.InsertionMarkerManager.DUPLICATE_BLOCK_ERROR
|
||||
.replace('%1', 'a field'));
|
||||
throw new Error(InsertionMarkerManager.DUPLICATE_BLOCK_ERROR.replace(
|
||||
'%1', 'a field'));
|
||||
}
|
||||
resultField.setValue(sourceField.getValue());
|
||||
}
|
||||
@@ -312,7 +324,7 @@ Blockly.InsertionMarkerManager.prototype.createMarkerBlock_ = function(sourceBlo
|
||||
result.initSvg();
|
||||
result.getSvgRoot().setAttribute('visibility', 'hidden');
|
||||
} finally {
|
||||
Blockly.Events.enable();
|
||||
Events.enable();
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -323,23 +335,23 @@ Blockly.InsertionMarkerManager.prototype.createMarkerBlock_ = function(sourceBlo
|
||||
* only be called once, at the beginning of a drag.
|
||||
* If the stack has more than one block, this function will populate
|
||||
* lastOnStack_ and create the corresponding insertion marker.
|
||||
* @return {!Array<!Blockly.RenderedConnection>} A list of available
|
||||
* @return {!Array<!RenderedConnection>} A list of available
|
||||
* connections.
|
||||
* @private
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.initAvailableConnections_ = function() {
|
||||
var available = this.topBlock_.getConnections_(false);
|
||||
InsertionMarkerManager.prototype.initAvailableConnections_ = function() {
|
||||
const available = this.topBlock_.getConnections_(false);
|
||||
// Also check the last connection on this stack
|
||||
var lastOnStack = this.topBlock_.lastConnectionInStack(true);
|
||||
const lastOnStack = this.topBlock_.lastConnectionInStack(true);
|
||||
if (lastOnStack && lastOnStack != this.topBlock_.nextConnection) {
|
||||
available.push(lastOnStack);
|
||||
this.lastOnStack_ = lastOnStack;
|
||||
if (this.lastMarker_) {
|
||||
Blockly.Events.disable();
|
||||
Events.disable();
|
||||
try {
|
||||
this.lastMarker_.dispose();
|
||||
} finally {
|
||||
Blockly.Events.enable();
|
||||
Events.enable();
|
||||
}
|
||||
}
|
||||
this.lastMarker_ = this.createMarkerBlock_(lastOnStack.getSourceBlock());
|
||||
@@ -352,16 +364,16 @@ Blockly.InsertionMarkerManager.prototype.initAvailableConnections_ = function()
|
||||
* updated based on the closest candidate and the current drag distance.
|
||||
* @param {!Object} candidate An object containing a local connection, a closest
|
||||
* connection, and a radius. Returned by getCandidate_.
|
||||
* @param {!Blockly.utils.Coordinate} dxy Position relative to drag start,
|
||||
* @param {!Coordinate} dxy Position relative to drag start,
|
||||
* in workspace units.
|
||||
* @return {boolean} Whether the preview should be updated.
|
||||
* @private
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.shouldUpdatePreviews_ = function(
|
||||
InsertionMarkerManager.prototype.shouldUpdatePreviews_ = function(
|
||||
candidate, dxy) {
|
||||
var candidateLocal = candidate.local;
|
||||
var candidateClosest = candidate.closest;
|
||||
var radius = candidate.radius;
|
||||
const candidateLocal = candidate.local;
|
||||
const candidateClosest = candidate.closest;
|
||||
const radius = candidate.radius;
|
||||
|
||||
// Found a connection!
|
||||
if (candidateLocal && candidateClosest) {
|
||||
@@ -373,57 +385,55 @@ Blockly.InsertionMarkerManager.prototype.shouldUpdatePreviews_ = function(
|
||||
this.localConnection_ == candidateLocal) {
|
||||
return false;
|
||||
}
|
||||
var xDiff = this.localConnection_.x + dxy.x - this.closestConnection_.x;
|
||||
var yDiff = this.localConnection_.y + dxy.y - this.closestConnection_.y;
|
||||
var curDistance = Math.sqrt(xDiff * xDiff + yDiff * yDiff);
|
||||
const xDiff = this.localConnection_.x + dxy.x - this.closestConnection_.x;
|
||||
const yDiff = this.localConnection_.y + dxy.y - this.closestConnection_.y;
|
||||
const curDistance = Math.sqrt(xDiff * xDiff + yDiff * yDiff);
|
||||
// Slightly prefer the existing preview over a new preview.
|
||||
return !(
|
||||
candidateClosest &&
|
||||
radius > curDistance -
|
||||
Blockly.internalConstants.CURRENT_CONNECTION_PREFERENCE);
|
||||
radius >
|
||||
curDistance - internalConstants.CURRENT_CONNECTION_PREFERENCE);
|
||||
} else if (!this.localConnection_ && !this.closestConnection_) {
|
||||
// We weren't showing a preview before, but we should now.
|
||||
// We weren't showing a preview before, but we should now.
|
||||
return true;
|
||||
} else {
|
||||
console.error('Only one of localConnection_ and closestConnection_ was set.');
|
||||
console.error(
|
||||
'Only one of localConnection_ and closestConnection_ was set.');
|
||||
}
|
||||
} else { // No connection found.
|
||||
// Only need to update if we were showing a preview before.
|
||||
return !!(this.localConnection_ && this.closestConnection_);
|
||||
}
|
||||
|
||||
console.error('Returning true from shouldUpdatePreviews, but it\'s not clear why.');
|
||||
console.error(
|
||||
'Returning true from shouldUpdatePreviews, but it\'s not clear why.');
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the nearest valid connection, which may be the same as the current
|
||||
* closest connection.
|
||||
* @param {!Blockly.utils.Coordinate} dxy Position relative to drag start,
|
||||
* @param {!Coordinate} dxy Position relative to drag start,
|
||||
* in workspace units.
|
||||
* @return {!Object} An object containing a local connection, a closest
|
||||
* connection, and a radius.
|
||||
* @private
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.getCandidate_ = function(dxy) {
|
||||
var radius = this.getStartRadius_();
|
||||
var candidateClosest = null;
|
||||
var candidateLocal = null;
|
||||
InsertionMarkerManager.prototype.getCandidate_ = function(dxy) {
|
||||
let radius = this.getStartRadius_();
|
||||
let candidateClosest = null;
|
||||
let candidateLocal = null;
|
||||
|
||||
for (var i = 0; i < this.availableConnections_.length; i++) {
|
||||
var myConnection = this.availableConnections_[i];
|
||||
var neighbour = myConnection.closest(radius, dxy);
|
||||
for (let i = 0; i < this.availableConnections_.length; i++) {
|
||||
const myConnection = this.availableConnections_[i];
|
||||
const neighbour = myConnection.closest(radius, dxy);
|
||||
if (neighbour.connection) {
|
||||
candidateClosest = neighbour.connection;
|
||||
candidateLocal = myConnection;
|
||||
radius = neighbour.radius;
|
||||
}
|
||||
}
|
||||
return {
|
||||
closest: candidateClosest,
|
||||
local: candidateLocal,
|
||||
radius: radius
|
||||
};
|
||||
return {closest: candidateClosest, local: candidateLocal, radius: radius};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -432,38 +442,38 @@ Blockly.InsertionMarkerManager.prototype.getCandidate_ = function(dxy) {
|
||||
* connection.
|
||||
* @private
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.getStartRadius_ = function() {
|
||||
InsertionMarkerManager.prototype.getStartRadius_ = function() {
|
||||
// If there is already a connection highlighted,
|
||||
// increase the radius we check for making new connections.
|
||||
// Why? When a connection is highlighted, blocks move around when the insertion
|
||||
// marker is created, which could cause the connection became out of range.
|
||||
// By increasing radiusConnection when a connection already exists,
|
||||
// we never "lose" the connection from the offset.
|
||||
// Why? When a connection is highlighted, blocks move around when the
|
||||
// insertion marker is created, which could cause the connection became out of
|
||||
// range. By increasing radiusConnection when a connection already exists, we
|
||||
// never "lose" the connection from the offset.
|
||||
if (this.closestConnection_ && this.localConnection_) {
|
||||
return Blockly.internalConstants.CONNECTING_SNAP_RADIUS;
|
||||
return internalConstants.CONNECTING_SNAP_RADIUS;
|
||||
}
|
||||
return Blockly.internalConstants.SNAP_RADIUS;
|
||||
return internalConstants.SNAP_RADIUS;
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether ending the drag would delete the block.
|
||||
* @param {!Object} candidate An object containing a local connection, a closest
|
||||
* connection, and a radius.
|
||||
* @param {?Blockly.IDragTarget} dragTarget The drag target that the block is
|
||||
* @param {?IDragTarget} dragTarget The drag target that the block is
|
||||
* currently over.
|
||||
* @return {boolean} Whether dropping the block immediately would delete the
|
||||
* block.
|
||||
* @private
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.shouldDelete_ = function(
|
||||
InsertionMarkerManager.prototype.shouldDelete_ = function(
|
||||
candidate, 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))
|
||||
/** @type {!IDeleteArea} */ (dragTarget))
|
||||
.wouldDelete(this.topBlock_, candidate && !!candidate.closest);
|
||||
}
|
||||
}
|
||||
@@ -479,13 +489,13 @@ Blockly.InsertionMarkerManager.prototype.shouldDelete_ = function(
|
||||
* connection, and a radius.
|
||||
* @private
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.maybeShowPreview_ = function(candidate) {
|
||||
InsertionMarkerManager.prototype.maybeShowPreview_ = function(candidate) {
|
||||
// Nope, don't add a marker.
|
||||
if (this.wouldDeleteBlock_) {
|
||||
return;
|
||||
}
|
||||
var closest = candidate.closest;
|
||||
var local = candidate.local;
|
||||
const closest = candidate.closest;
|
||||
const local = candidate.local;
|
||||
|
||||
// Nothing to connect to.
|
||||
if (!closest) {
|
||||
@@ -509,22 +519,22 @@ Blockly.InsertionMarkerManager.prototype.maybeShowPreview_ = function(candidate)
|
||||
* highlight or an insertion marker, and shows the appropriate one.
|
||||
* @private
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.showPreview_ = function() {
|
||||
var closest = this.closestConnection_;
|
||||
var renderer = this.workspace_.getRenderer();
|
||||
var method = renderer.getConnectionPreviewMethod(
|
||||
/** @type {!Blockly.RenderedConnection} */ (closest),
|
||||
/** @type {!Blockly.RenderedConnection} */ (this.localConnection_),
|
||||
InsertionMarkerManager.prototype.showPreview_ = function() {
|
||||
const closest = this.closestConnection_;
|
||||
const renderer = this.workspace_.getRenderer();
|
||||
const method = renderer.getConnectionPreviewMethod(
|
||||
/** @type {!RenderedConnection} */ (closest),
|
||||
/** @type {!RenderedConnection} */ (this.localConnection_),
|
||||
this.topBlock_);
|
||||
|
||||
switch (method) {
|
||||
case Blockly.InsertionMarkerManager.PREVIEW_TYPE.INPUT_OUTLINE:
|
||||
case InsertionMarkerManager.PREVIEW_TYPE.INPUT_OUTLINE:
|
||||
this.showInsertionInputOutline_();
|
||||
break;
|
||||
case Blockly.InsertionMarkerManager.PREVIEW_TYPE.INSERTION_MARKER:
|
||||
case InsertionMarkerManager.PREVIEW_TYPE.INSERTION_MARKER:
|
||||
this.showInsertionMarker_();
|
||||
break;
|
||||
case Blockly.InsertionMarkerManager.PREVIEW_TYPE.REPLACEMENT_FADE:
|
||||
case InsertionMarkerManager.PREVIEW_TYPE.REPLACEMENT_FADE:
|
||||
this.showReplacementFade_();
|
||||
break;
|
||||
}
|
||||
@@ -544,7 +554,7 @@ Blockly.InsertionMarkerManager.prototype.showPreview_ = function() {
|
||||
* connection, and a radius.
|
||||
* @private
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.maybeHidePreview_ = function(candidate) {
|
||||
InsertionMarkerManager.prototype.maybeHidePreview_ = function(candidate) {
|
||||
// If there's no new preview, remove the old one but don't bother deleting it.
|
||||
// We might need it later, and this saves disposing of it and recreating it.
|
||||
if (!candidate.closest) {
|
||||
@@ -552,12 +562,14 @@ Blockly.InsertionMarkerManager.prototype.maybeHidePreview_ = function(candidate)
|
||||
} else {
|
||||
// If there's a new preview and there was an preview before, and either
|
||||
// connection has changed, remove the old preview.
|
||||
var hadPreview = this.closestConnection_ && this.localConnection_;
|
||||
var closestChanged = this.closestConnection_ != candidate.closest;
|
||||
var localChanged = this.localConnection_ != candidate.local;
|
||||
const hadPreview = this.closestConnection_ && this.localConnection_;
|
||||
const closestChanged = this.closestConnection_ != candidate.closest;
|
||||
const localChanged = this.localConnection_ != candidate.local;
|
||||
|
||||
// Also hide if we had a preview before but now we're going to delete instead.
|
||||
if (hadPreview && (closestChanged || localChanged || this.wouldDeleteBlock_)) {
|
||||
// Also hide if we had a preview before but now we're going to delete
|
||||
// instead.
|
||||
if (hadPreview &&
|
||||
(closestChanged || localChanged || this.wouldDeleteBlock_)) {
|
||||
this.hidePreview_();
|
||||
}
|
||||
}
|
||||
@@ -573,10 +585,10 @@ Blockly.InsertionMarkerManager.prototype.maybeHidePreview_ = function(candidate)
|
||||
* highlight or an insertion marker, and hides the appropriate one.
|
||||
* @private
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.hidePreview_ = function() {
|
||||
InsertionMarkerManager.prototype.hidePreview_ = function() {
|
||||
if (this.closestConnection_ && this.closestConnection_.targetBlock() &&
|
||||
this.workspace_.getRenderer()
|
||||
.shouldHighlightConnection(this.closestConnection_)) {
|
||||
this.workspace_.getRenderer().shouldHighlightConnection(
|
||||
this.closestConnection_)) {
|
||||
this.closestConnection_.unhighlight();
|
||||
}
|
||||
if (this.fadedBlock_) {
|
||||
@@ -593,16 +605,17 @@ Blockly.InsertionMarkerManager.prototype.hidePreview_ = function() {
|
||||
* manager state).
|
||||
* @private
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.showInsertionMarker_ = function() {
|
||||
var local = this.localConnection_;
|
||||
var closest = this.closestConnection_;
|
||||
InsertionMarkerManager.prototype.showInsertionMarker_ = function() {
|
||||
const local = this.localConnection_;
|
||||
const closest = this.closestConnection_;
|
||||
|
||||
var isLastInStack = this.lastOnStack_ && local == this.lastOnStack_;
|
||||
var imBlock = isLastInStack ? this.lastMarker_ : this.firstMarker_;
|
||||
var imConn = imBlock.getMatchingConnection(local.getSourceBlock(), local);
|
||||
const isLastInStack = this.lastOnStack_ && local == this.lastOnStack_;
|
||||
const imBlock = isLastInStack ? this.lastMarker_ : this.firstMarker_;
|
||||
const imConn = imBlock.getMatchingConnection(local.getSourceBlock(), local);
|
||||
|
||||
if (imConn == this.markerConnection_) {
|
||||
throw Error('Made it to showInsertionMarker_ even though the marker isn\'t ' +
|
||||
throw Error(
|
||||
'Made it to showInsertionMarker_ even though the marker isn\'t ' +
|
||||
'changing');
|
||||
}
|
||||
|
||||
@@ -629,23 +642,22 @@ Blockly.InsertionMarkerManager.prototype.showInsertionMarker_ = function() {
|
||||
* to their original state.
|
||||
* @private
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.hideInsertionMarker_ = function() {
|
||||
InsertionMarkerManager.prototype.hideInsertionMarker_ = function() {
|
||||
if (!this.markerConnection_) {
|
||||
console.log('No insertion marker connection to disconnect');
|
||||
return;
|
||||
}
|
||||
|
||||
var imConn = this.markerConnection_;
|
||||
var imBlock = imConn.getSourceBlock();
|
||||
var markerNext = imBlock.nextConnection;
|
||||
var markerPrev = imBlock.previousConnection;
|
||||
var markerOutput = imBlock.outputConnection;
|
||||
const imConn = this.markerConnection_;
|
||||
const imBlock = imConn.getSourceBlock();
|
||||
const markerNext = imBlock.nextConnection;
|
||||
const markerPrev = imBlock.previousConnection;
|
||||
const markerOutput = imBlock.outputConnection;
|
||||
|
||||
var isFirstInStatementStack =
|
||||
const isFirstInStatementStack =
|
||||
(imConn == markerNext && !(markerPrev && markerPrev.targetConnection));
|
||||
|
||||
var isFirstInOutputStack =
|
||||
imConn.type == Blockly.connectionTypes.INPUT_VALUE &&
|
||||
const isFirstInOutputStack = imConn.type == connectionTypes.INPUT_VALUE &&
|
||||
!(markerOutput && markerOutput.targetConnection);
|
||||
// The insertion marker is the first block in a stack. Unplug won't do
|
||||
// anything in that case. Instead, unplug the following block.
|
||||
@@ -653,12 +665,12 @@ Blockly.InsertionMarkerManager.prototype.hideInsertionMarker_ = function() {
|
||||
imConn.targetBlock().unplug(false);
|
||||
}
|
||||
// Inside of a C-block, first statement connection.
|
||||
else if (imConn.type == Blockly.connectionTypes.NEXT_STATEMENT &&
|
||||
imConn != markerNext) {
|
||||
var innerConnection = imConn.targetConnection;
|
||||
else if (
|
||||
imConn.type == connectionTypes.NEXT_STATEMENT && imConn != markerNext) {
|
||||
const innerConnection = imConn.targetConnection;
|
||||
innerConnection.getSourceBlock().unplug(false);
|
||||
|
||||
var previousBlockNextConnection =
|
||||
const previousBlockNextConnection =
|
||||
markerPrev ? markerPrev.targetConnection : null;
|
||||
|
||||
imBlock.unplug(true);
|
||||
@@ -670,12 +682,13 @@ Blockly.InsertionMarkerManager.prototype.hideInsertionMarker_ = function() {
|
||||
}
|
||||
|
||||
if (imConn.targetConnection) {
|
||||
throw Error('markerConnection_ still connected at the end of ' +
|
||||
throw Error(
|
||||
'markerConnection_ still connected at the end of ' +
|
||||
'disconnectInsertionMarker');
|
||||
}
|
||||
|
||||
this.markerConnection_ = null;
|
||||
var svg = imBlock.getSvgRoot();
|
||||
const svg = imBlock.getSvgRoot();
|
||||
if (svg) {
|
||||
svg.setAttribute('visibility', 'hidden');
|
||||
}
|
||||
@@ -685,8 +698,8 @@ Blockly.InsertionMarkerManager.prototype.hideInsertionMarker_ = function() {
|
||||
* Shows an outline around the input the closest connection belongs to.
|
||||
* @private
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.showInsertionInputOutline_ = function() {
|
||||
var closest = this.closestConnection_;
|
||||
InsertionMarkerManager.prototype.showInsertionInputOutline_ = function() {
|
||||
const closest = this.closestConnection_;
|
||||
this.highlightedBlock_ = closest.getSourceBlock();
|
||||
this.highlightedBlock_.highlightShapeForInput(closest, true);
|
||||
};
|
||||
@@ -695,7 +708,7 @@ Blockly.InsertionMarkerManager.prototype.showInsertionInputOutline_ = function()
|
||||
* Hides any visible input outlines.
|
||||
* @private
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.hideInsertionInputOutline_ = function() {
|
||||
InsertionMarkerManager.prototype.hideInsertionInputOutline_ = function() {
|
||||
this.highlightedBlock_.highlightShapeForInput(this.closestConnection_, false);
|
||||
this.highlightedBlock_ = null;
|
||||
};
|
||||
@@ -705,7 +718,7 @@ Blockly.InsertionMarkerManager.prototype.hideInsertionInputOutline_ = function()
|
||||
* (the block that is currently connected to it).
|
||||
* @private
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.showReplacementFade_ = function() {
|
||||
InsertionMarkerManager.prototype.showReplacementFade_ = function() {
|
||||
this.fadedBlock_ = this.closestConnection_.targetBlock();
|
||||
this.fadedBlock_.fadeForReplacement(true);
|
||||
};
|
||||
@@ -714,7 +727,7 @@ Blockly.InsertionMarkerManager.prototype.showReplacementFade_ = function() {
|
||||
* Hides/Removes any visible fade affects.
|
||||
* @private
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.hideReplacementFade_ = function() {
|
||||
InsertionMarkerManager.prototype.hideReplacementFade_ = function() {
|
||||
this.fadedBlock_.fadeForReplacement(false);
|
||||
this.fadedBlock_ = null;
|
||||
};
|
||||
@@ -722,12 +735,12 @@ Blockly.InsertionMarkerManager.prototype.hideReplacementFade_ = function() {
|
||||
/**
|
||||
* 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.
|
||||
* @package
|
||||
*/
|
||||
Blockly.InsertionMarkerManager.prototype.getInsertionMarkers = function() {
|
||||
var result = [];
|
||||
InsertionMarkerManager.prototype.getInsertionMarkers = function() {
|
||||
const result = [];
|
||||
if (this.firstMarker_) {
|
||||
result.push(this.firstMarker_);
|
||||
}
|
||||
@@ -736,3 +749,5 @@ Blockly.InsertionMarkerManager.prototype.getInsertionMarkers = function() {
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
exports = InsertionMarkerManager;
|
||||
|
||||
@@ -15,7 +15,7 @@ goog.module('Blockly.IASTNodeLocationSvg');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IASTNodeLocation = goog.require('Blockly.IASTNodeLocation');
|
||||
const IASTNodeLocation = goog.requireType('Blockly.IASTNodeLocation');
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,7 @@ 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');
|
||||
const IASTNodeLocation = goog.requireType('Blockly.IASTNodeLocation');
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,7 +16,7 @@ goog.module('Blockly.IAutoHideable');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IComponent = goog.require('Blockly.IComponent');
|
||||
const IComponent = goog.requireType('Blockly.IComponent');
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,9 +19,9 @@ 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');
|
||||
const IContextMenu = goog.requireType('Blockly.IContextMenu');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDraggable = goog.require('Blockly.IDraggable');
|
||||
const IDraggable = goog.requireType('Blockly.IDraggable');
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,7 +15,7 @@ goog.module('Blockly.ICollapsibleToolboxItem');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const ISelectableToolboxItem = goog.require('Blockly.ISelectableToolboxItem');
|
||||
const ISelectableToolboxItem = goog.requireType('Blockly.ISelectableToolboxItem');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IToolboxItem = goog.requireType('Blockly.IToolboxItem');
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ goog.module.declareLegacyNamespace();
|
||||
/* 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');
|
||||
const IDragTarget = goog.requireType('Blockly.IDragTarget');
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,7 +16,7 @@ goog.module('Blockly.IDragTarget');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IComponent = goog.require('Blockly.IComponent');
|
||||
const IComponent = goog.requireType('Blockly.IComponent');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDraggable = goog.requireType('Blockly.IDraggable');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
|
||||
@@ -15,7 +15,7 @@ goog.module('Blockly.IDraggable');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDeletable = goog.require('Blockly.IDeletable');
|
||||
const IDeletable = goog.requireType('Blockly.IDeletable');
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,13 +19,13 @@ 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');
|
||||
const IRegistrable = goog.requireType('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');
|
||||
const toolbox = goog.requireType('Blockly.utils.toolbox');
|
||||
|
||||
|
||||
/**
|
||||
@@ -142,7 +142,7 @@ IFlyout.prototype.hide;
|
||||
|
||||
/**
|
||||
* Show and populate the flyout.
|
||||
* @param {!FlyoutDefinition|string} flyoutDef Contents to
|
||||
* @param {!toolbox.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.
|
||||
*/
|
||||
|
||||
@@ -17,9 +17,9 @@ goog.module.declareLegacyNamespace();
|
||||
/* 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');
|
||||
const MetricsManager = goog.requireType('Blockly.MetricsManager');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const {AbsoluteMetrics, ContainerRegion, ToolboxMetrics} = goog.requireType('Blockly.MetricsManager');
|
||||
const Size = goog.requireType('Blockly.utils.Size');
|
||||
|
||||
|
||||
/**
|
||||
@@ -39,13 +39,13 @@ 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 {!ContainerRegion=} opt_viewMetrics The view
|
||||
* @param {!MetricsManager.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 {!ContainerRegion=} opt_contentMetrics The
|
||||
* @param {!MetricsManager.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 {!ContainerRegion} The metrics for the scroll
|
||||
* @return {!MetricsManager.ContainerRegion} The metrics for the scroll
|
||||
* container
|
||||
*/
|
||||
IMetricsManager.prototype.getScrollMetrics;
|
||||
@@ -55,7 +55,7 @@ IMetricsManager.prototype.getScrollMetrics;
|
||||
* 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 {!ToolboxMetrics} The width and height of the
|
||||
* @return {!MetricsManager.ToolboxMetrics} The width and height of the
|
||||
* flyout.
|
||||
* @public
|
||||
*/
|
||||
@@ -66,7 +66,7 @@ IMetricsManager.prototype.getFlyoutMetrics;
|
||||
* 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 {!ToolboxMetrics} The object with the width,
|
||||
* @return {!MetricsManager.ToolboxMetrics} The object with the width,
|
||||
* height and position of the toolbox.
|
||||
* @public
|
||||
*/
|
||||
@@ -84,7 +84,7 @@ 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 {!AbsoluteMetrics} The absolute metrics for
|
||||
* @return {!MetricsManager.AbsoluteMetrics} The absolute metrics for
|
||||
* the workspace.
|
||||
* @public
|
||||
*/
|
||||
@@ -95,7 +95,7 @@ IMetricsManager.prototype.getAbsoluteMetrics;
|
||||
* 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 {!ContainerRegion} The width, height, top and
|
||||
* @return {!MetricsManager.ContainerRegion} The width, height, top and
|
||||
* left of the viewport in either workspace coordinates or pixel
|
||||
* coordinates.
|
||||
* @public
|
||||
@@ -108,7 +108,7 @@ 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 {!ContainerRegion} The
|
||||
* @return {!MetricsManager.ContainerRegion} The
|
||||
* metrics for the content container.
|
||||
* @public
|
||||
*/
|
||||
|
||||
@@ -15,11 +15,11 @@ goog.module('Blockly.IPositionable');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IComponent = goog.require('Blockly.IComponent');
|
||||
const IComponent = goog.requireType('Blockly.IComponent');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const MetricsManager = goog.requireType('Blockly.MetricsManager');
|
||||
/* 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');
|
||||
|
||||
|
||||
/**
|
||||
@@ -31,7 +31,7 @@ const IPositionable = function() {};
|
||||
|
||||
/**
|
||||
* Positions the element. Called when the window is resized.
|
||||
* @param {!UiMetrics} metrics The workspace metrics.
|
||||
* @param {!MetricsManager.UiMetrics} metrics The workspace metrics.
|
||||
* @param {!Array<!Rect>} savedPositions List of rectangles that
|
||||
* are already on the workspace.
|
||||
*/
|
||||
|
||||
@@ -15,9 +15,9 @@ goog.module('Blockly.ISelectableToolboxItem');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IToolboxItem = goog.require('Blockly.IToolboxItem');
|
||||
const IToolboxItem = goog.requireType('Blockly.IToolboxItem');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const {FlyoutItemInfoArray} = goog.requireType('Blockly.utils.toolbox');
|
||||
const toolbox = goog.requireType('Blockly.utils.toolbox');
|
||||
|
||||
|
||||
/**
|
||||
@@ -37,7 +37,7 @@ 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
|
||||
* @return {!toolbox.FlyoutItemInfoArray|string} The definition
|
||||
* of items to be displayed in the flyout.
|
||||
* @public
|
||||
*/
|
||||
|
||||
@@ -17,13 +17,13 @@ goog.module.declareLegacyNamespace();
|
||||
/* 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');
|
||||
const IRegistrable = goog.requireType('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');
|
||||
const toolbox = goog.requireType('Blockly.utils.toolbox');
|
||||
|
||||
|
||||
/**
|
||||
@@ -41,7 +41,7 @@ IToolbox.prototype.init;
|
||||
|
||||
/**
|
||||
* Fills the toolbox with new toolbox items and removes any old contents.
|
||||
* @param {!ToolboxInfo} toolboxDef Object holding information
|
||||
* @param {!toolbox.ToolboxInfo} toolboxDef Object holding information
|
||||
* for creating a toolbox.
|
||||
*/
|
||||
IToolbox.prototype.render;
|
||||
|
||||
@@ -10,18 +10,25 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.ASTNode');
|
||||
goog.module('Blockly.ASTNode');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.connectionTypes');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
goog.requireType('Blockly.Connection');
|
||||
goog.requireType('Blockly.Field');
|
||||
goog.requireType('Blockly.IASTNodeLocation');
|
||||
goog.requireType('Blockly.IASTNodeLocationWithBlock');
|
||||
goog.requireType('Blockly.Input');
|
||||
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 Connection = goog.requireType('Blockly.Connection');
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Field = goog.requireType('Blockly.Field');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IASTNodeLocation = goog.requireType('Blockly.IASTNodeLocation');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IASTNodeLocationWithBlock = goog.requireType('Blockly.IASTNodeLocationWithBlock');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Input = goog.requireType('Blockly.Input');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Workspace = goog.requireType('Blockly.Workspace');
|
||||
const connectionTypes = goog.require('Blockly.connectionTypes');
|
||||
|
||||
|
||||
/**
|
||||
@@ -29,19 +36,19 @@ goog.requireType('Blockly.Workspace');
|
||||
* It is recommended that you use one of the createNode methods instead of
|
||||
* creating a node directly.
|
||||
* @param {string} type The type of the location.
|
||||
* Must be in Blockly.ASTNode.types.
|
||||
* @param {!Blockly.IASTNodeLocation} location The position in the AST.
|
||||
* @param {!Blockly.ASTNode.Params=} opt_params Optional dictionary of options.
|
||||
* Must be in ASTNode.types.
|
||||
* @param {!IASTNodeLocation} location The position in the AST.
|
||||
* @param {!ASTNode.Params=} opt_params Optional dictionary of options.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.ASTNode = function(type, location, opt_params) {
|
||||
const ASTNode = function(type, location, opt_params) {
|
||||
if (!location) {
|
||||
throw Error('Cannot create a node without a location.');
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of the location.
|
||||
* One of Blockly.ASTNode.types
|
||||
* One of ASTNode.types
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
@@ -52,18 +59,18 @@ Blockly.ASTNode = function(type, location, opt_params) {
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.isConnection_ = Blockly.ASTNode.isConnectionType_(type);
|
||||
this.isConnection_ = ASTNode.isConnectionType_(type);
|
||||
|
||||
/**
|
||||
* The location of the AST node.
|
||||
* @type {!Blockly.IASTNodeLocation}
|
||||
* @type {!IASTNodeLocation}
|
||||
* @private
|
||||
*/
|
||||
this.location_ = location;
|
||||
|
||||
/**
|
||||
* The coordinate on the workspace.
|
||||
* @type {Blockly.utils.Coordinate}
|
||||
* @type {Coordinate}
|
||||
* @private
|
||||
*/
|
||||
this.wsCoordinate_ = null;
|
||||
@@ -73,16 +80,16 @@ Blockly.ASTNode = function(type, location, opt_params) {
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* wsCoordinate: Blockly.utils.Coordinate
|
||||
* wsCoordinate: Coordinate
|
||||
* }}
|
||||
*/
|
||||
Blockly.ASTNode.Params;
|
||||
ASTNode.Params;
|
||||
|
||||
/**
|
||||
* Object holding different types for an AST node.
|
||||
* @enum {string}
|
||||
*/
|
||||
Blockly.ASTNode.types = {
|
||||
ASTNode.types = {
|
||||
FIELD: 'field',
|
||||
BLOCK: 'block',
|
||||
INPUT: 'input',
|
||||
@@ -97,7 +104,7 @@ Blockly.ASTNode.types = {
|
||||
* True to navigate to all fields. False to only navigate to clickable fields.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.ASTNode.NAVIGATE_ALL_FIELDS = false;
|
||||
ASTNode.NAVIGATE_ALL_FIELDS = false;
|
||||
|
||||
/**
|
||||
* The default y offset to use when moving the cursor from a stack to the
|
||||
@@ -105,20 +112,20 @@ Blockly.ASTNode.NAVIGATE_ALL_FIELDS = false;
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
Blockly.ASTNode.DEFAULT_OFFSET_Y = -20;
|
||||
ASTNode.DEFAULT_OFFSET_Y = -20;
|
||||
|
||||
/**
|
||||
* Whether an AST node of the given type points to a connection.
|
||||
* @param {string} type The type to check. One of Blockly.ASTNode.types.
|
||||
* @param {string} type The type to check. One of ASTNode.types.
|
||||
* @return {boolean} True if a node of the given type points to a connection.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ASTNode.isConnectionType_ = function(type) {
|
||||
ASTNode.isConnectionType_ = function(type) {
|
||||
switch (type) {
|
||||
case Blockly.ASTNode.types.PREVIOUS:
|
||||
case Blockly.ASTNode.types.NEXT:
|
||||
case Blockly.ASTNode.types.INPUT:
|
||||
case Blockly.ASTNode.types.OUTPUT:
|
||||
case ASTNode.types.PREVIOUS:
|
||||
case ASTNode.types.NEXT:
|
||||
case ASTNode.types.INPUT:
|
||||
case ASTNode.types.OUTPUT:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -126,39 +133,39 @@ Blockly.ASTNode.isConnectionType_ = function(type) {
|
||||
|
||||
/**
|
||||
* Create an AST node pointing to a field.
|
||||
* @param {Blockly.Field} field The location of the AST node.
|
||||
* @return {Blockly.ASTNode} An AST node pointing to a field.
|
||||
* @param {Field} field The location of the AST node.
|
||||
* @return {ASTNode} An AST node pointing to a field.
|
||||
*/
|
||||
Blockly.ASTNode.createFieldNode = function(field) {
|
||||
ASTNode.createFieldNode = function(field) {
|
||||
if (!field) {
|
||||
return null;
|
||||
}
|
||||
return new Blockly.ASTNode(Blockly.ASTNode.types.FIELD, field);
|
||||
return new ASTNode(ASTNode.types.FIELD, field);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an AST node pointing to a connection. If the connection has a parent
|
||||
* input then create an AST node of type input that will hold the connection.
|
||||
* @param {Blockly.Connection} connection This is the connection the node will
|
||||
* @param {Connection} connection This is the connection the node will
|
||||
* point to.
|
||||
* @return {Blockly.ASTNode} An AST node pointing to a connection.
|
||||
* @return {ASTNode} An AST node pointing to a connection.
|
||||
*/
|
||||
Blockly.ASTNode.createConnectionNode = function(connection) {
|
||||
ASTNode.createConnectionNode = function(connection) {
|
||||
if (!connection) {
|
||||
return null;
|
||||
}
|
||||
var type = connection.type;
|
||||
if (type == Blockly.connectionTypes.INPUT_VALUE) {
|
||||
return Blockly.ASTNode.createInputNode(connection.getParentInput());
|
||||
} else if (type == Blockly.connectionTypes.NEXT_STATEMENT &&
|
||||
connection.getParentInput()) {
|
||||
return Blockly.ASTNode.createInputNode(connection.getParentInput());
|
||||
} else if (type == Blockly.connectionTypes.NEXT_STATEMENT) {
|
||||
return new Blockly.ASTNode(Blockly.ASTNode.types.NEXT, connection);
|
||||
} else if (type == Blockly.connectionTypes.OUTPUT_VALUE) {
|
||||
return new Blockly.ASTNode(Blockly.ASTNode.types.OUTPUT, connection);
|
||||
} else if (type == Blockly.connectionTypes.PREVIOUS_STATEMENT) {
|
||||
return new Blockly.ASTNode(Blockly.ASTNode.types.PREVIOUS, connection);
|
||||
const type = connection.type;
|
||||
if (type == connectionTypes.INPUT_VALUE) {
|
||||
return ASTNode.createInputNode(connection.getParentInput());
|
||||
} else if (
|
||||
type == connectionTypes.NEXT_STATEMENT && connection.getParentInput()) {
|
||||
return ASTNode.createInputNode(connection.getParentInput());
|
||||
} else if (type == connectionTypes.NEXT_STATEMENT) {
|
||||
return new ASTNode(ASTNode.types.NEXT, connection);
|
||||
} else if (type == connectionTypes.OUTPUT_VALUE) {
|
||||
return new ASTNode(ASTNode.types.OUTPUT, connection);
|
||||
} else if (type == connectionTypes.PREVIOUS_STATEMENT) {
|
||||
return new ASTNode(ASTNode.types.PREVIOUS, connection);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
@@ -166,86 +173,83 @@ Blockly.ASTNode.createConnectionNode = function(connection) {
|
||||
/**
|
||||
* Creates an AST node pointing to an input. Stores the input connection as the
|
||||
* location.
|
||||
* @param {Blockly.Input} input The input used to create an AST node.
|
||||
* @return {Blockly.ASTNode} An AST node pointing to a input.
|
||||
* @param {Input} input The input used to create an AST node.
|
||||
* @return {ASTNode} An AST node pointing to a input.
|
||||
*/
|
||||
Blockly.ASTNode.createInputNode = function(input) {
|
||||
ASTNode.createInputNode = function(input) {
|
||||
if (!input || !input.connection) {
|
||||
return null;
|
||||
}
|
||||
return new Blockly.ASTNode(Blockly.ASTNode.types.INPUT, input.connection);
|
||||
return new ASTNode(ASTNode.types.INPUT, input.connection);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an AST node pointing to a block.
|
||||
* @param {Blockly.Block} block The block used to create an AST node.
|
||||
* @return {Blockly.ASTNode} An AST node pointing to a block.
|
||||
* @param {Block} block The block used to create an AST node.
|
||||
* @return {ASTNode} An AST node pointing to a block.
|
||||
*/
|
||||
Blockly.ASTNode.createBlockNode = function(block) {
|
||||
ASTNode.createBlockNode = function(block) {
|
||||
if (!block) {
|
||||
return null;
|
||||
}
|
||||
return new Blockly.ASTNode(Blockly.ASTNode.types.BLOCK, block);
|
||||
return new ASTNode(ASTNode.types.BLOCK, block);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an AST node of type stack. A stack, represented by its top block, is
|
||||
* the set of all blocks connected to a top block, including the top block.
|
||||
* @param {Blockly.Block} topBlock A top block has no parent and can be found
|
||||
* @param {Block} topBlock A top block has no parent and can be found
|
||||
* in the list returned by workspace.getTopBlocks().
|
||||
* @return {Blockly.ASTNode} An AST node of type stack that points to the top
|
||||
* @return {ASTNode} An AST node of type stack that points to the top
|
||||
* block on the stack.
|
||||
*/
|
||||
Blockly.ASTNode.createStackNode = function(topBlock) {
|
||||
ASTNode.createStackNode = function(topBlock) {
|
||||
if (!topBlock) {
|
||||
return null;
|
||||
}
|
||||
return new Blockly.ASTNode(Blockly.ASTNode.types.STACK, topBlock);
|
||||
return new ASTNode(ASTNode.types.STACK, topBlock);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an AST node pointing to a workspace.
|
||||
* @param {!Blockly.Workspace} workspace The workspace that we are on.
|
||||
* @param {Blockly.utils.Coordinate} wsCoordinate The position on the workspace
|
||||
* @param {!Workspace} workspace The workspace that we are on.
|
||||
* @param {Coordinate} wsCoordinate The position on the workspace
|
||||
* for this node.
|
||||
* @return {Blockly.ASTNode} An AST node pointing to a workspace and a position
|
||||
* @return {ASTNode} An AST node pointing to a workspace and a position
|
||||
* on the workspace.
|
||||
*/
|
||||
Blockly.ASTNode.createWorkspaceNode = function(workspace, wsCoordinate) {
|
||||
ASTNode.createWorkspaceNode = function(workspace, wsCoordinate) {
|
||||
if (!wsCoordinate || !workspace) {
|
||||
return null;
|
||||
}
|
||||
var params = {
|
||||
wsCoordinate: wsCoordinate
|
||||
};
|
||||
return new Blockly.ASTNode(
|
||||
Blockly.ASTNode.types.WORKSPACE, workspace, params);
|
||||
const params = {wsCoordinate: wsCoordinate};
|
||||
return new ASTNode(ASTNode.types.WORKSPACE, workspace, params);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an AST node for the top position on a block.
|
||||
* This is either an output connection, previous connection, or block.
|
||||
* @param {!Blockly.Block} block The block to find the top most AST node on.
|
||||
* @return {Blockly.ASTNode} The AST node holding the top most position on the
|
||||
* @param {!Block} block The block to find the top most AST node on.
|
||||
* @return {ASTNode} The AST node holding the top most position on the
|
||||
* block.
|
||||
*/
|
||||
Blockly.ASTNode.createTopNode = function(block) {
|
||||
var astNode;
|
||||
var topConnection = block.previousConnection || block.outputConnection;
|
||||
ASTNode.createTopNode = function(block) {
|
||||
let astNode;
|
||||
const topConnection = block.previousConnection || block.outputConnection;
|
||||
if (topConnection) {
|
||||
astNode = Blockly.ASTNode.createConnectionNode(topConnection);
|
||||
astNode = ASTNode.createConnectionNode(topConnection);
|
||||
} else {
|
||||
astNode = Blockly.ASTNode.createBlockNode(block);
|
||||
astNode = ASTNode.createBlockNode(block);
|
||||
}
|
||||
return astNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse the optional parameters.
|
||||
* @param {?Blockly.ASTNode.Params} params The user specified parameters.
|
||||
* @param {?ASTNode.Params} params The user specified parameters.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ASTNode.prototype.processParams_ = function(params) {
|
||||
ASTNode.prototype.processParams_ = function(params) {
|
||||
if (!params) {
|
||||
return;
|
||||
}
|
||||
@@ -258,28 +262,28 @@ Blockly.ASTNode.prototype.processParams_ = function(params) {
|
||||
* Gets the value pointed to by this node.
|
||||
* It is the callers responsibility to check the node type to figure out what
|
||||
* type of object they get back from this.
|
||||
* @return {!Blockly.IASTNodeLocation} The current field, connection, workspace, or
|
||||
* @return {!IASTNodeLocation} The current field, connection, workspace, or
|
||||
* block the cursor is on.
|
||||
*/
|
||||
Blockly.ASTNode.prototype.getLocation = function() {
|
||||
ASTNode.prototype.getLocation = function() {
|
||||
return this.location_;
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of the current location.
|
||||
* One of Blockly.ASTNode.types
|
||||
* One of ASTNode.types
|
||||
* @return {string} The type of the location.
|
||||
*/
|
||||
Blockly.ASTNode.prototype.getType = function() {
|
||||
ASTNode.prototype.getType = function() {
|
||||
return this.type_;
|
||||
};
|
||||
|
||||
/**
|
||||
* The coordinate on the workspace.
|
||||
* @return {Blockly.utils.Coordinate} The workspace coordinate or null if the
|
||||
* @return {Coordinate} The workspace coordinate or null if the
|
||||
* location is not a workspace.
|
||||
*/
|
||||
Blockly.ASTNode.prototype.getWsCoordinate = function() {
|
||||
ASTNode.prototype.getWsCoordinate = function() {
|
||||
return this.wsCoordinate_;
|
||||
};
|
||||
|
||||
@@ -288,7 +292,7 @@ Blockly.ASTNode.prototype.getWsCoordinate = function() {
|
||||
* @return {boolean} [description]
|
||||
* @package
|
||||
*/
|
||||
Blockly.ASTNode.prototype.isConnection = function() {
|
||||
ASTNode.prototype.isConnection = function() {
|
||||
return this.isConnection_;
|
||||
};
|
||||
|
||||
@@ -296,25 +300,27 @@ Blockly.ASTNode.prototype.isConnection = function() {
|
||||
* Given an input find the next editable field or an input with a non null
|
||||
* connection in the same block. The current location must be an input
|
||||
* connection.
|
||||
* @return {Blockly.ASTNode} The AST node holding the next field or connection
|
||||
* @return {ASTNode} The AST node holding the next field or connection
|
||||
* or null if there is no editable field or input connection after the given
|
||||
* input.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ASTNode.prototype.findNextForInput_ = function() {
|
||||
var location = /** @type {!Blockly.Connection} */ (this.location_);
|
||||
var parentInput = location.getParentInput();
|
||||
var block = parentInput.getSourceBlock();
|
||||
var curIdx = block.inputList.indexOf(parentInput);
|
||||
for (var i = curIdx + 1, input; (input = block.inputList[i]); i++) {
|
||||
var fieldRow = input.fieldRow;
|
||||
for (var j = 0, field; (field = fieldRow[j]); j++) {
|
||||
if (field.isClickable() || Blockly.ASTNode.NAVIGATE_ALL_FIELDS) {
|
||||
return Blockly.ASTNode.createFieldNode(field);
|
||||
ASTNode.prototype.findNextForInput_ = function() {
|
||||
const location = /** @type {!Connection} */ (this.location_);
|
||||
const parentInput = location.getParentInput();
|
||||
const block = parentInput.getSourceBlock();
|
||||
const curIdx = block.inputList.indexOf(parentInput);
|
||||
for (let i = curIdx + 1; i < block.inputList.length; i++) {
|
||||
const input = block.inputList[i];
|
||||
const fieldRow = input.fieldRow;
|
||||
for (let j = 0; j < fieldRow.length; j++) {
|
||||
const field = fieldRow[j];
|
||||
if (field.isClickable() || ASTNode.NAVIGATE_ALL_FIELDS) {
|
||||
return ASTNode.createFieldNode(field);
|
||||
}
|
||||
}
|
||||
if (input.connection) {
|
||||
return Blockly.ASTNode.createInputNode(input);
|
||||
return ASTNode.createInputNode(input);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -323,28 +329,29 @@ Blockly.ASTNode.prototype.findNextForInput_ = function() {
|
||||
/**
|
||||
* Given a field find the next editable field or an input with a non null
|
||||
* connection in the same block. The current location must be a field.
|
||||
* @return {Blockly.ASTNode} The AST node pointing to the next field or
|
||||
* @return {ASTNode} The AST node pointing to the next field or
|
||||
* connection or null if there is no editable field or input connection
|
||||
* after the given input.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ASTNode.prototype.findNextForField_ = function() {
|
||||
var location = /** @type {!Blockly.Field} */ (this.location_);
|
||||
var input = location.getParentInput();
|
||||
var block = location.getSourceBlock();
|
||||
var curIdx = block.inputList.indexOf(/** @type {!Blockly.Input} */ (input));
|
||||
var fieldIdx = input.fieldRow.indexOf(location) + 1;
|
||||
for (var i = curIdx, newInput; (newInput = block.inputList[i]); i++) {
|
||||
var fieldRow = newInput.fieldRow;
|
||||
ASTNode.prototype.findNextForField_ = function() {
|
||||
const location = /** @type {!Field} */ (this.location_);
|
||||
const input = location.getParentInput();
|
||||
const block = location.getSourceBlock();
|
||||
const curIdx = block.inputList.indexOf(/** @type {!Input} */ (input));
|
||||
let fieldIdx = input.fieldRow.indexOf(location) + 1;
|
||||
for (let i = curIdx; i < block.inputList.length; i++) {
|
||||
const newInput = block.inputList[i];
|
||||
const fieldRow = newInput.fieldRow;
|
||||
while (fieldIdx < fieldRow.length) {
|
||||
if (fieldRow[fieldIdx].isClickable() || Blockly.ASTNode.NAVIGATE_ALL_FIELDS) {
|
||||
return Blockly.ASTNode.createFieldNode(fieldRow[fieldIdx]);
|
||||
if (fieldRow[fieldIdx].isClickable() || ASTNode.NAVIGATE_ALL_FIELDS) {
|
||||
return ASTNode.createFieldNode(fieldRow[fieldIdx]);
|
||||
}
|
||||
fieldIdx++;
|
||||
}
|
||||
fieldIdx = 0;
|
||||
if (newInput.connection) {
|
||||
return Blockly.ASTNode.createInputNode(newInput);
|
||||
return ASTNode.createInputNode(newInput);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -354,23 +361,25 @@ Blockly.ASTNode.prototype.findNextForField_ = function() {
|
||||
* Given an input find the previous editable field or an input with a non null
|
||||
* connection in the same block. The current location must be an input
|
||||
* connection.
|
||||
* @return {Blockly.ASTNode} The AST node holding the previous field or
|
||||
* @return {ASTNode} The AST node holding the previous field or
|
||||
* connection.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ASTNode.prototype.findPrevForInput_ = function() {
|
||||
var location = /** @type {!Blockly.Connection} */ (this.location_);
|
||||
var parentInput = location.getParentInput();
|
||||
var block = parentInput.getSourceBlock();
|
||||
var curIdx = block.inputList.indexOf(parentInput);
|
||||
for (var i = curIdx, input; (input = block.inputList[i]); i--) {
|
||||
ASTNode.prototype.findPrevForInput_ = function() {
|
||||
const location = /** @type {!Connection} */ (this.location_);
|
||||
const parentInput = location.getParentInput();
|
||||
const block = parentInput.getSourceBlock();
|
||||
const curIdx = block.inputList.indexOf(parentInput);
|
||||
for (let i = curIdx; i >= 0; i--) {
|
||||
const input = block.inputList[i];
|
||||
if (input.connection && input !== parentInput) {
|
||||
return Blockly.ASTNode.createInputNode(input);
|
||||
return ASTNode.createInputNode(input);
|
||||
}
|
||||
var fieldRow = input.fieldRow;
|
||||
for (var j = fieldRow.length - 1, field; (field = fieldRow[j]); j--) {
|
||||
if (field.isClickable() || Blockly.ASTNode.NAVIGATE_ALL_FIELDS) {
|
||||
return Blockly.ASTNode.createFieldNode(field);
|
||||
const fieldRow = input.fieldRow;
|
||||
for (let j = fieldRow.length - 1; j >= 0; j--) {
|
||||
const field = fieldRow[j];
|
||||
if (field.isClickable() || ASTNode.NAVIGATE_ALL_FIELDS) {
|
||||
return ASTNode.createFieldNode(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -380,24 +389,25 @@ Blockly.ASTNode.prototype.findPrevForInput_ = function() {
|
||||
/**
|
||||
* Given a field find the previous editable field or an input with a non null
|
||||
* connection in the same block. The current location must be a field.
|
||||
* @return {Blockly.ASTNode} The AST node holding the previous input or field.
|
||||
* @return {ASTNode} The AST node holding the previous input or field.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ASTNode.prototype.findPrevForField_ = function() {
|
||||
var location = /** @type {!Blockly.Field} */ (this.location_);
|
||||
var parentInput = location.getParentInput();
|
||||
var block = location.getSourceBlock();
|
||||
var curIdx = block.inputList.indexOf(
|
||||
/** @type {!Blockly.Input} */ (parentInput));
|
||||
var fieldIdx = parentInput.fieldRow.indexOf(location) - 1;
|
||||
for (var i = curIdx, input; (input = block.inputList[i]); i--) {
|
||||
ASTNode.prototype.findPrevForField_ = function() {
|
||||
const location = /** @type {!Field} */ (this.location_);
|
||||
const parentInput = location.getParentInput();
|
||||
const block = location.getSourceBlock();
|
||||
const curIdx = block.inputList.indexOf(
|
||||
/** @type {!Input} */ (parentInput));
|
||||
let fieldIdx = parentInput.fieldRow.indexOf(location) - 1;
|
||||
for (let i = curIdx; i >= 0; i--) {
|
||||
const input = block.inputList[i];
|
||||
if (input.connection && input !== parentInput) {
|
||||
return Blockly.ASTNode.createInputNode(input);
|
||||
return ASTNode.createInputNode(input);
|
||||
}
|
||||
var fieldRow = input.fieldRow;
|
||||
const fieldRow = input.fieldRow;
|
||||
while (fieldIdx > -1) {
|
||||
if (fieldRow[fieldIdx].isClickable() || Blockly.ASTNode.NAVIGATE_ALL_FIELDS) {
|
||||
return Blockly.ASTNode.createFieldNode(fieldRow[fieldIdx]);
|
||||
if (fieldRow[fieldIdx].isClickable() || ASTNode.NAVIGATE_ALL_FIELDS) {
|
||||
return ASTNode.createFieldNode(fieldRow[fieldIdx]);
|
||||
}
|
||||
fieldIdx--;
|
||||
}
|
||||
@@ -412,29 +422,30 @@ Blockly.ASTNode.prototype.findPrevForField_ = function() {
|
||||
/**
|
||||
* Navigate between stacks of blocks on the workspace.
|
||||
* @param {boolean} forward True to go forward. False to go backwards.
|
||||
* @return {Blockly.ASTNode} The first block of the next stack or null if there
|
||||
* @return {ASTNode} The first block of the next stack or null if there
|
||||
* are no blocks on the workspace.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ASTNode.prototype.navigateBetweenStacks_ = function(forward) {
|
||||
ASTNode.prototype.navigateBetweenStacks_ = function(forward) {
|
||||
var curLocation = this.getLocation();
|
||||
if (curLocation.getSourceBlock) {
|
||||
curLocation = /** @type {!Blockly.IASTNodeLocationWithBlock} */ (
|
||||
curLocation).getSourceBlock();
|
||||
curLocation = /** @type {!IASTNodeLocationWithBlock} */ (curLocation)
|
||||
.getSourceBlock();
|
||||
}
|
||||
if (!curLocation || !curLocation.workspace) {
|
||||
return null;
|
||||
}
|
||||
var curRoot = curLocation.getRootBlock();
|
||||
var topBlocks = curRoot.workspace.getTopBlocks(true);
|
||||
for (var i = 0, topBlock; (topBlock = topBlocks[i]); i++) {
|
||||
const curRoot = curLocation.getRootBlock();
|
||||
const topBlocks = curRoot.workspace.getTopBlocks(true);
|
||||
for (let i = 0; i < topBlocks.length; i++) {
|
||||
const topBlock = topBlocks[i];
|
||||
if (curRoot.id == topBlock.id) {
|
||||
var offset = forward ? 1 : -1;
|
||||
var resultIndex = i + offset;
|
||||
const offset = forward ? 1 : -1;
|
||||
const resultIndex = i + offset;
|
||||
if (resultIndex == -1 || resultIndex == topBlocks.length) {
|
||||
return null;
|
||||
}
|
||||
return Blockly.ASTNode.createStackNode(topBlocks[resultIndex]);
|
||||
return ASTNode.createStackNode(topBlocks[resultIndex]);
|
||||
}
|
||||
}
|
||||
throw Error('Couldn\'t find ' + (forward ? 'next' : 'previous') + ' stack?!');
|
||||
@@ -444,69 +455,71 @@ Blockly.ASTNode.prototype.navigateBetweenStacks_ = function(forward) {
|
||||
* Finds the top most AST node for a given block.
|
||||
* This is either the previous connection, output connection or block depending
|
||||
* on what kind of connections the block has.
|
||||
* @param {!Blockly.Block} block The block that we want to find the top
|
||||
* @param {!Block} block The block that we want to find the top
|
||||
* connection on.
|
||||
* @return {!Blockly.ASTNode} The AST node containing the top connection.
|
||||
* @return {!ASTNode} The AST node containing the top connection.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ASTNode.prototype.findTopASTNodeForBlock_ = function(block) {
|
||||
var topConnection = block.previousConnection || block.outputConnection;
|
||||
ASTNode.prototype.findTopASTNodeForBlock_ = function(block) {
|
||||
const topConnection = block.previousConnection || block.outputConnection;
|
||||
if (topConnection) {
|
||||
return /** @type {!Blockly.ASTNode} */ (Blockly.ASTNode.createConnectionNode(
|
||||
topConnection));
|
||||
return /** @type {!ASTNode} */ (
|
||||
ASTNode.createConnectionNode(topConnection));
|
||||
} else {
|
||||
return /** @type {!Blockly.ASTNode} */ (Blockly.ASTNode.createBlockNode(
|
||||
block));
|
||||
return /** @type {!ASTNode} */ (ASTNode.createBlockNode(block));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the AST node pointing to the input that the block is nested under or if
|
||||
* the block is not nested then get the stack AST node.
|
||||
* @param {Blockly.Block} block The source block of the current location.
|
||||
* @return {Blockly.ASTNode} The AST node pointing to the input connection or
|
||||
* @param {Block} block The source block of the current location.
|
||||
* @return {ASTNode} The AST node pointing to the input connection or
|
||||
* the top block of the stack this block is in.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ASTNode.prototype.getOutAstNodeForBlock_ = function(block) {
|
||||
ASTNode.prototype.getOutAstNodeForBlock_ = function(block) {
|
||||
if (!block) {
|
||||
return null;
|
||||
}
|
||||
var topBlock;
|
||||
let topBlock;
|
||||
// If the block doesn't have a previous connection then it is the top of the
|
||||
// substack.
|
||||
topBlock = block.getTopStackBlock();
|
||||
var topConnection = topBlock.previousConnection || topBlock.outputConnection;
|
||||
const topConnection =
|
||||
topBlock.previousConnection || topBlock.outputConnection;
|
||||
// If the top connection has a parentInput, create an AST node pointing to
|
||||
// that input.
|
||||
if (topConnection && topConnection.targetConnection &&
|
||||
topConnection.targetConnection.getParentInput()) {
|
||||
return Blockly.ASTNode.createInputNode(
|
||||
return ASTNode.createInputNode(
|
||||
topConnection.targetConnection.getParentInput());
|
||||
} else {
|
||||
// Go to stack level if you are not underneath an input.
|
||||
return Blockly.ASTNode.createStackNode(topBlock);
|
||||
return ASTNode.createStackNode(topBlock);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the first editable field or input with a connection on a given block.
|
||||
* @param {!Blockly.Block} block The source block of the current location.
|
||||
* @return {Blockly.ASTNode} An AST node pointing to the first field or input.
|
||||
* @param {!Block} block The source block of the current location.
|
||||
* @return {ASTNode} An AST node pointing to the first field or input.
|
||||
* Null if there are no editable fields or inputs with connections on the block.
|
||||
* @private
|
||||
*/
|
||||
Blockly.ASTNode.prototype.findFirstFieldOrInput_ = function(block) {
|
||||
var inputs = block.inputList;
|
||||
for (var i = 0, input; (input = inputs[i]); i++) {
|
||||
var fieldRow = input.fieldRow;
|
||||
for (var j = 0, field; (field = fieldRow[j]); j++) {
|
||||
if (field.isClickable() || Blockly.ASTNode.NAVIGATE_ALL_FIELDS) {
|
||||
return Blockly.ASTNode.createFieldNode(field);
|
||||
ASTNode.prototype.findFirstFieldOrInput_ = function(block) {
|
||||
const inputs = block.inputList;
|
||||
for (let i = 0; i < inputs.length; i++) {
|
||||
const input = inputs[i];
|
||||
const fieldRow = input.fieldRow;
|
||||
for (let j = 0; j < fieldRow.length; j++) {
|
||||
const field = fieldRow[j];
|
||||
if (field.isClickable() || ASTNode.NAVIGATE_ALL_FIELDS) {
|
||||
return ASTNode.createFieldNode(field);
|
||||
}
|
||||
}
|
||||
if (input.connection) {
|
||||
return Blockly.ASTNode.createInputNode(input);
|
||||
return ASTNode.createInputNode(input);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -514,55 +527,56 @@ Blockly.ASTNode.prototype.findFirstFieldOrInput_ = function(block) {
|
||||
|
||||
/**
|
||||
* Finds the source block of the location of this node.
|
||||
* @return {Blockly.Block} The source block of the location, or null if the node
|
||||
* @return {Block} The source block of the location, or null if the node
|
||||
* is of type workspace.
|
||||
*/
|
||||
Blockly.ASTNode.prototype.getSourceBlock = function() {
|
||||
if (this.getType() === Blockly.ASTNode.types.BLOCK) {
|
||||
return /** @type {Blockly.Block} */ (this.getLocation());
|
||||
} else if (this.getType() === Blockly.ASTNode.types.STACK) {
|
||||
return /** @type {Blockly.Block} */ (this.getLocation());
|
||||
} else if (this.getType() === Blockly.ASTNode.types.WORKSPACE) {
|
||||
ASTNode.prototype.getSourceBlock = function() {
|
||||
if (this.getType() === ASTNode.types.BLOCK) {
|
||||
return /** @type {Block} */ (this.getLocation());
|
||||
} else if (this.getType() === ASTNode.types.STACK) {
|
||||
return /** @type {Block} */ (this.getLocation());
|
||||
} else if (this.getType() === ASTNode.types.WORKSPACE) {
|
||||
return null;
|
||||
} else {
|
||||
return /** @type {Blockly.IASTNodeLocationWithBlock} */ (
|
||||
this.getLocation()).getSourceBlock();
|
||||
return /** @type {IASTNodeLocationWithBlock} */ (this.getLocation())
|
||||
.getSourceBlock();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the element to the right of the current element in the AST.
|
||||
* @return {Blockly.ASTNode} An AST node that wraps the next field, connection,
|
||||
* @return {ASTNode} An AST node that wraps the next field, connection,
|
||||
* block, or workspace. Or null if there is no node to the right.
|
||||
*/
|
||||
Blockly.ASTNode.prototype.next = function() {
|
||||
ASTNode.prototype.next = function() {
|
||||
switch (this.type_) {
|
||||
case Blockly.ASTNode.types.STACK:
|
||||
case ASTNode.types.STACK:
|
||||
return this.navigateBetweenStacks_(true);
|
||||
|
||||
case Blockly.ASTNode.types.OUTPUT:
|
||||
var connection = /** @type {!Blockly.Connection} */ (this.location_);
|
||||
return Blockly.ASTNode.createBlockNode(connection.getSourceBlock());
|
||||
|
||||
case Blockly.ASTNode.types.FIELD:
|
||||
case ASTNode.types.OUTPUT: {
|
||||
const connection = /** @type {!Connection} */ (this.location_);
|
||||
return ASTNode.createBlockNode(connection.getSourceBlock());
|
||||
}
|
||||
case ASTNode.types.FIELD:
|
||||
return this.findNextForField_();
|
||||
|
||||
case Blockly.ASTNode.types.INPUT:
|
||||
case ASTNode.types.INPUT:
|
||||
return this.findNextForInput_();
|
||||
|
||||
case Blockly.ASTNode.types.BLOCK:
|
||||
var block = /** @type {!Blockly.Block} */ (this.location_);
|
||||
var nextConnection = block.nextConnection;
|
||||
return Blockly.ASTNode.createConnectionNode(nextConnection);
|
||||
|
||||
case Blockly.ASTNode.types.PREVIOUS:
|
||||
var connection = /** @type {!Blockly.Connection} */ (this.location_);
|
||||
return Blockly.ASTNode.createBlockNode(connection.getSourceBlock());
|
||||
|
||||
case Blockly.ASTNode.types.NEXT:
|
||||
var connection = /** @type {!Blockly.Connection} */ (this.location_);
|
||||
var targetConnection = connection.targetConnection;
|
||||
return Blockly.ASTNode.createConnectionNode(targetConnection);
|
||||
case ASTNode.types.BLOCK: {
|
||||
const block = /** @type {!Block} */ (this.location_);
|
||||
const nextConnection = block.nextConnection;
|
||||
return ASTNode.createConnectionNode(nextConnection);
|
||||
}
|
||||
case ASTNode.types.PREVIOUS: {
|
||||
const connection = /** @type {!Connection} */ (this.location_);
|
||||
return ASTNode.createBlockNode(connection.getSourceBlock());
|
||||
}
|
||||
case ASTNode.types.NEXT: {
|
||||
const connection = /** @type {!Connection} */ (this.location_);
|
||||
const targetConnection = connection.targetConnection;
|
||||
return ASTNode.createConnectionNode(targetConnection);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -571,31 +585,32 @@ Blockly.ASTNode.prototype.next = function() {
|
||||
/**
|
||||
* Find the element one level below and all the way to the left of the current
|
||||
* location.
|
||||
* @return {Blockly.ASTNode} An AST node that wraps the next field, connection,
|
||||
* @return {ASTNode} An AST node that wraps the next field, connection,
|
||||
* workspace, or block. Or null if there is nothing below this node.
|
||||
*/
|
||||
Blockly.ASTNode.prototype.in = function() {
|
||||
ASTNode.prototype.in = function() {
|
||||
switch (this.type_) {
|
||||
case Blockly.ASTNode.types.WORKSPACE:
|
||||
var workspace = /** @type {!Blockly.Workspace} */ (this.location_);
|
||||
var topBlocks = workspace.getTopBlocks(true);
|
||||
case ASTNode.types.WORKSPACE: {
|
||||
const workspace = /** @type {!Workspace} */ (this.location_);
|
||||
const topBlocks = workspace.getTopBlocks(true);
|
||||
if (topBlocks.length > 0) {
|
||||
return Blockly.ASTNode.createStackNode(topBlocks[0]);
|
||||
return ASTNode.createStackNode(topBlocks[0]);
|
||||
}
|
||||
break;
|
||||
|
||||
case Blockly.ASTNode.types.STACK:
|
||||
var block = /** @type {!Blockly.Block} */ (this.location_);
|
||||
}
|
||||
case ASTNode.types.STACK: {
|
||||
const block = /** @type {!Block} */ (this.location_);
|
||||
return this.findTopASTNodeForBlock_(block);
|
||||
|
||||
case Blockly.ASTNode.types.BLOCK:
|
||||
var block = /** @type {!Blockly.Block} */ (this.location_);
|
||||
}
|
||||
case ASTNode.types.BLOCK: {
|
||||
const block = /** @type {!Block} */ (this.location_);
|
||||
return this.findFirstFieldOrInput_(block);
|
||||
|
||||
case Blockly.ASTNode.types.INPUT:
|
||||
var connection = /** @type {!Blockly.Connection} */ (this.location_);
|
||||
var targetConnection = connection.targetConnection;
|
||||
return Blockly.ASTNode.createConnectionNode(targetConnection);
|
||||
}
|
||||
case ASTNode.types.INPUT: {
|
||||
const connection = /** @type {!Connection} */ (this.location_);
|
||||
const targetConnection = connection.targetConnection;
|
||||
return ASTNode.createConnectionNode(targetConnection);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -603,40 +618,41 @@ Blockly.ASTNode.prototype.in = function() {
|
||||
|
||||
/**
|
||||
* Find the element to the left of the current element in the AST.
|
||||
* @return {Blockly.ASTNode} An AST node that wraps the previous field,
|
||||
* @return {ASTNode} An AST node that wraps the previous field,
|
||||
* connection, workspace or block. Or null if no node exists to the left.
|
||||
* null.
|
||||
*/
|
||||
Blockly.ASTNode.prototype.prev = function() {
|
||||
ASTNode.prototype.prev = function() {
|
||||
switch (this.type_) {
|
||||
case Blockly.ASTNode.types.STACK:
|
||||
case ASTNode.types.STACK:
|
||||
return this.navigateBetweenStacks_(false);
|
||||
|
||||
case Blockly.ASTNode.types.OUTPUT:
|
||||
case ASTNode.types.OUTPUT:
|
||||
return null;
|
||||
|
||||
case Blockly.ASTNode.types.FIELD:
|
||||
case ASTNode.types.FIELD:
|
||||
return this.findPrevForField_();
|
||||
|
||||
case Blockly.ASTNode.types.INPUT:
|
||||
case ASTNode.types.INPUT:
|
||||
return this.findPrevForInput_();
|
||||
|
||||
case Blockly.ASTNode.types.BLOCK:
|
||||
var block = /** @type {!Blockly.Block} */ (this.location_);
|
||||
var topConnection = block.previousConnection || block.outputConnection;
|
||||
return Blockly.ASTNode.createConnectionNode(topConnection);
|
||||
|
||||
case Blockly.ASTNode.types.PREVIOUS:
|
||||
var connection = /** @type {!Blockly.Connection} */ (this.location_);
|
||||
var targetConnection = connection.targetConnection;
|
||||
case ASTNode.types.BLOCK: {
|
||||
const block = /** @type {!Block} */ (this.location_);
|
||||
const topConnection = block.previousConnection || block.outputConnection;
|
||||
return ASTNode.createConnectionNode(topConnection);
|
||||
}
|
||||
case ASTNode.types.PREVIOUS: {
|
||||
const connection = /** @type {!Connection} */ (this.location_);
|
||||
const targetConnection = connection.targetConnection;
|
||||
if (targetConnection && !targetConnection.getParentInput()) {
|
||||
return Blockly.ASTNode.createConnectionNode(targetConnection);
|
||||
return ASTNode.createConnectionNode(targetConnection);
|
||||
}
|
||||
break;
|
||||
|
||||
case Blockly.ASTNode.types.NEXT:
|
||||
var connection = /** @type {!Blockly.Connection} */ (this.location_);
|
||||
return Blockly.ASTNode.createBlockNode(connection.getSourceBlock());
|
||||
}
|
||||
case ASTNode.types.NEXT: {
|
||||
const connection = /** @type {!Connection} */ (this.location_);
|
||||
return ASTNode.createBlockNode(connection.getSourceBlock());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -645,47 +661,50 @@ Blockly.ASTNode.prototype.prev = function() {
|
||||
/**
|
||||
* Find the next element that is one position above and all the way to the left
|
||||
* of the current location.
|
||||
* @return {Blockly.ASTNode} An AST node that wraps the next field, connection,
|
||||
* @return {ASTNode} An AST node that wraps the next field, connection,
|
||||
* workspace or block. Or null if we are at the workspace level.
|
||||
*/
|
||||
Blockly.ASTNode.prototype.out = function() {
|
||||
ASTNode.prototype.out = function() {
|
||||
switch (this.type_) {
|
||||
case Blockly.ASTNode.types.STACK:
|
||||
var block = /** @type {!Blockly.Block} */ (this.location_);
|
||||
var blockPos = block.getRelativeToSurfaceXY();
|
||||
case ASTNode.types.STACK: {
|
||||
const block = /** @type {!Block} */ (this.location_);
|
||||
const blockPos = block.getRelativeToSurfaceXY();
|
||||
// TODO: Make sure this is in the bounds of the workspace.
|
||||
var wsCoordinate = new Blockly.utils.Coordinate(
|
||||
blockPos.x, blockPos.y + Blockly.ASTNode.DEFAULT_OFFSET_Y);
|
||||
return Blockly.ASTNode.createWorkspaceNode(block.workspace, wsCoordinate);
|
||||
|
||||
case Blockly.ASTNode.types.OUTPUT:
|
||||
var connection = /** @type {!Blockly.Connection} */ (this.location_);
|
||||
var target = connection.targetConnection;
|
||||
const wsCoordinate =
|
||||
new Coordinate(blockPos.x, blockPos.y + ASTNode.DEFAULT_OFFSET_Y);
|
||||
return ASTNode.createWorkspaceNode(block.workspace, wsCoordinate);
|
||||
}
|
||||
case ASTNode.types.OUTPUT: {
|
||||
const connection = /** @type {!Connection} */ (this.location_);
|
||||
const target = connection.targetConnection;
|
||||
if (target) {
|
||||
return Blockly.ASTNode.createConnectionNode(target);
|
||||
return ASTNode.createConnectionNode(target);
|
||||
}
|
||||
return Blockly.ASTNode.createStackNode(connection.getSourceBlock());
|
||||
|
||||
case Blockly.ASTNode.types.FIELD:
|
||||
var field = /** @type {!Blockly.Field} */ (this.location_);
|
||||
return Blockly.ASTNode.createBlockNode(field.getSourceBlock());
|
||||
|
||||
case Blockly.ASTNode.types.INPUT:
|
||||
var connection = /** @type {!Blockly.Connection} */ (this.location_);
|
||||
return Blockly.ASTNode.createBlockNode(connection.getSourceBlock());
|
||||
|
||||
case Blockly.ASTNode.types.BLOCK:
|
||||
var block = /** @type {!Blockly.Block} */ (this.location_);
|
||||
return ASTNode.createStackNode(connection.getSourceBlock());
|
||||
}
|
||||
case ASTNode.types.FIELD: {
|
||||
const field = /** @type {!Field} */ (this.location_);
|
||||
return ASTNode.createBlockNode(field.getSourceBlock());
|
||||
}
|
||||
case ASTNode.types.INPUT: {
|
||||
const connection = /** @type {!Connection} */ (this.location_);
|
||||
return ASTNode.createBlockNode(connection.getSourceBlock());
|
||||
}
|
||||
case ASTNode.types.BLOCK: {
|
||||
const block = /** @type {!Block} */ (this.location_);
|
||||
return this.getOutAstNodeForBlock_(block);
|
||||
|
||||
case Blockly.ASTNode.types.PREVIOUS:
|
||||
var connection = /** @type {!Blockly.Connection} */ (this.location_);
|
||||
}
|
||||
case ASTNode.types.PREVIOUS: {
|
||||
const connection = /** @type {!Connection} */ (this.location_);
|
||||
return this.getOutAstNodeForBlock_(connection.getSourceBlock());
|
||||
|
||||
case Blockly.ASTNode.types.NEXT:
|
||||
var connection = /** @type {!Blockly.Connection} */ (this.location_);
|
||||
}
|
||||
case ASTNode.types.NEXT: {
|
||||
const connection = /** @type {!Connection} */ (this.location_);
|
||||
return this.getOutAstNodeForBlock_(connection.getSourceBlock());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
exports = ASTNode;
|
||||
|
||||
@@ -16,8 +16,8 @@ goog.module.declareLegacyNamespace();
|
||||
|
||||
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');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
@@ -30,7 +30,7 @@ const {inherits} = goog.require('Blockly.utils.object');
|
||||
const BasicCursor = function() {
|
||||
BasicCursor.superClass_.constructor.call(this);
|
||||
};
|
||||
inherits(BasicCursor, Cursor);
|
||||
object.inherits(BasicCursor, Cursor);
|
||||
|
||||
/**
|
||||
* Name used for registering a basic cursor.
|
||||
@@ -214,6 +214,7 @@ BasicCursor.prototype.getRightMostChild_ = function(node) {
|
||||
return this.getRightMostChild_(newNode);
|
||||
};
|
||||
|
||||
register(Type.CURSOR, BasicCursor.registrationName, BasicCursor);
|
||||
registry.register(
|
||||
registry.Type.CURSOR, BasicCursor.registrationName, BasicCursor);
|
||||
|
||||
exports = BasicCursor;
|
||||
|
||||
@@ -16,8 +16,8 @@ goog.module.declareLegacyNamespace();
|
||||
|
||||
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');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
@@ -34,7 +34,7 @@ const Cursor = function() {
|
||||
*/
|
||||
this.type = 'cursor';
|
||||
};
|
||||
inherits(Cursor, Marker);
|
||||
object.inherits(Cursor, Marker);
|
||||
|
||||
/**
|
||||
* Find the next connection, field, or block.
|
||||
@@ -134,6 +134,6 @@ Cursor.prototype.out = function() {
|
||||
return newNode;
|
||||
};
|
||||
|
||||
register(Type.CURSOR, DEFAULT, Cursor);
|
||||
registry.register(registry.Type.CURSOR, registry.DEFAULT, Cursor);
|
||||
|
||||
exports = Cursor;
|
||||
|
||||
@@ -11,11 +11,13 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Marker');
|
||||
goog.module('Blockly.Marker');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.ASTNode');
|
||||
|
||||
goog.requireType('Blockly.blockRendering.MarkerSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const ASTNode = goog.requireType('Blockly.ASTNode');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const MarkerSvg = goog.requireType('Blockly.blockRendering.MarkerSvg');
|
||||
|
||||
|
||||
/**
|
||||
@@ -23,7 +25,7 @@ goog.requireType('Blockly.blockRendering.MarkerSvg');
|
||||
* This is used in keyboard navigation to save a location in the Blockly AST.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Marker = function() {
|
||||
const Marker = function() {
|
||||
/**
|
||||
* The colour of the marker.
|
||||
* @type {?string}
|
||||
@@ -32,14 +34,15 @@ Blockly.Marker = function() {
|
||||
|
||||
/**
|
||||
* The current location of the marker.
|
||||
* @type {Blockly.ASTNode}
|
||||
* @type {ASTNode}
|
||||
* @private
|
||||
*/
|
||||
this.curNode_ = null;
|
||||
|
||||
/**
|
||||
* The object in charge of drawing the visual representation of the current node.
|
||||
* @type {Blockly.blockRendering.MarkerSvg}
|
||||
* The object in charge of drawing the visual representation of the current
|
||||
* node.
|
||||
* @type {MarkerSvg}
|
||||
* @private
|
||||
*/
|
||||
this.drawer_ = null;
|
||||
@@ -53,28 +56,28 @@ Blockly.Marker = function() {
|
||||
|
||||
/**
|
||||
* Sets the object in charge of drawing the marker.
|
||||
* @param {Blockly.blockRendering.MarkerSvg} drawer The object in charge of
|
||||
* @param {MarkerSvg} drawer The object in charge of
|
||||
* drawing the marker.
|
||||
*/
|
||||
Blockly.Marker.prototype.setDrawer = function(drawer) {
|
||||
Marker.prototype.setDrawer = function(drawer) {
|
||||
this.drawer_ = drawer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current drawer for the marker.
|
||||
* @return {Blockly.blockRendering.MarkerSvg} The object in charge of drawing
|
||||
* @return {MarkerSvg} The object in charge of drawing
|
||||
* the marker.
|
||||
*/
|
||||
Blockly.Marker.prototype.getDrawer = function() {
|
||||
Marker.prototype.getDrawer = function() {
|
||||
return this.drawer_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the current location of the marker.
|
||||
* @return {Blockly.ASTNode} The current field, connection, or block the marker
|
||||
* @return {ASTNode} The current field, connection, or block the marker
|
||||
* is on.
|
||||
*/
|
||||
Blockly.Marker.prototype.getCurNode = function() {
|
||||
Marker.prototype.getCurNode = function() {
|
||||
return this.curNode_;
|
||||
};
|
||||
|
||||
@@ -82,10 +85,10 @@ Blockly.Marker.prototype.getCurNode = function() {
|
||||
* Set the location of the marker and call the update method.
|
||||
* Setting isStack to true will only work if the newLocation is the top most
|
||||
* output or previous connection on a stack.
|
||||
* @param {Blockly.ASTNode} newNode The new location of the marker.
|
||||
* @param {ASTNode} newNode The new location of the marker.
|
||||
*/
|
||||
Blockly.Marker.prototype.setCurNode = function(newNode) {
|
||||
var oldNode = this.curNode_;
|
||||
Marker.prototype.setCurNode = function(newNode) {
|
||||
const oldNode = this.curNode_;
|
||||
this.curNode_ = newNode;
|
||||
if (this.drawer_) {
|
||||
this.drawer_.draw(oldNode, this.curNode_);
|
||||
@@ -96,7 +99,7 @@ Blockly.Marker.prototype.setCurNode = function(newNode) {
|
||||
* Redraw the current marker.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Marker.prototype.draw = function() {
|
||||
Marker.prototype.draw = function() {
|
||||
if (this.drawer_) {
|
||||
this.drawer_.draw(this.curNode_, this.curNode_);
|
||||
}
|
||||
@@ -105,7 +108,7 @@ Blockly.Marker.prototype.draw = function() {
|
||||
/**
|
||||
* Hide the marker SVG.
|
||||
*/
|
||||
Blockly.Marker.prototype.hide = function() {
|
||||
Marker.prototype.hide = function() {
|
||||
if (this.drawer_) {
|
||||
this.drawer_.hide();
|
||||
}
|
||||
@@ -114,8 +117,10 @@ Blockly.Marker.prototype.hide = function() {
|
||||
/**
|
||||
* Dispose of this marker.
|
||||
*/
|
||||
Blockly.Marker.prototype.dispose = function() {
|
||||
Marker.prototype.dispose = function() {
|
||||
if (this.getDrawer()) {
|
||||
this.getDrawer().dispose();
|
||||
}
|
||||
};
|
||||
|
||||
exports = Marker;
|
||||
|
||||
@@ -18,7 +18,7 @@ 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');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
|
||||
|
||||
/**
|
||||
@@ -29,7 +29,7 @@ const {inherits} = goog.require('Blockly.utils.object');
|
||||
const TabNavigateCursor = function() {
|
||||
TabNavigateCursor.superClass_.constructor.call(this);
|
||||
};
|
||||
inherits(TabNavigateCursor, BasicCursor);
|
||||
object.inherits(TabNavigateCursor, BasicCursor);
|
||||
|
||||
/**
|
||||
* Skip all nodes except for tab navigable fields.
|
||||
|
||||
@@ -10,11 +10,12 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.MenuItem');
|
||||
goog.module('Blockly.MenuItem');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.utils.aria');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.IdGenerator');
|
||||
const aria = goog.require('Blockly.utils.aria');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const idGenerator = goog.require('Blockly.utils.IdGenerator');
|
||||
|
||||
|
||||
/**
|
||||
@@ -25,7 +26,7 @@ goog.require('Blockly.utils.IdGenerator');
|
||||
* @param {string=} opt_value Data/model associated with the menu item.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.MenuItem = function(content, opt_value) {
|
||||
const MenuItem = function(content, opt_value) {
|
||||
/**
|
||||
* Human-readable text of this menu item, or the HTML element to display.
|
||||
* @type {string|!HTMLElement}
|
||||
@@ -63,7 +64,7 @@ Blockly.MenuItem = function(content, opt_value) {
|
||||
|
||||
/**
|
||||
* ARIA name for this menu.
|
||||
* @type {?Blockly.utils.aria.Role}
|
||||
* @type {?aria.Role}
|
||||
* @private
|
||||
*/
|
||||
this.roleName_ = null;
|
||||
@@ -102,9 +103,9 @@ Blockly.MenuItem = function(content, opt_value) {
|
||||
* Creates the menuitem's DOM.
|
||||
* @return {!Element} Completed DOM.
|
||||
*/
|
||||
Blockly.MenuItem.prototype.createDom = function() {
|
||||
var element = document.createElement('div');
|
||||
element.id = Blockly.utils.IdGenerator.getNextUniqueId();
|
||||
MenuItem.prototype.createDom = function() {
|
||||
const element = document.createElement('div');
|
||||
element.id = idGenerator.getNextUniqueId();
|
||||
this.element_ = element;
|
||||
|
||||
// Set class and style
|
||||
@@ -112,20 +113,20 @@ Blockly.MenuItem.prototype.createDom = function() {
|
||||
element.className = 'blocklyMenuItem goog-menuitem ' +
|
||||
(this.enabled_ ? '' : 'blocklyMenuItemDisabled goog-menuitem-disabled ') +
|
||||
(this.checked_ ? 'blocklyMenuItemSelected goog-option-selected ' : '') +
|
||||
(this.highlight_ ?
|
||||
'blocklyMenuItemHighlight goog-menuitem-highlight ' : '') +
|
||||
(this.highlight_ ? 'blocklyMenuItemHighlight goog-menuitem-highlight ' :
|
||||
'') +
|
||||
(this.rightToLeft_ ? 'blocklyMenuItemRtl goog-menuitem-rtl ' : '');
|
||||
|
||||
var content = document.createElement('div');
|
||||
const content = document.createElement('div');
|
||||
content.className = 'blocklyMenuItemContent goog-menuitem-content';
|
||||
// Add a checkbox for checkable menu items.
|
||||
if (this.checkable_) {
|
||||
var checkbox = document.createElement('div');
|
||||
const checkbox = document.createElement('div');
|
||||
checkbox.className = 'blocklyMenuItemCheckbox goog-menuitem-checkbox';
|
||||
content.appendChild(checkbox);
|
||||
}
|
||||
|
||||
var contentDom = /** @type {!HTMLElement} */ (this.content_);
|
||||
let contentDom = /** @type {!HTMLElement} */ (this.content_);
|
||||
if (typeof this.content_ == 'string') {
|
||||
contentDom = document.createTextNode(this.content_);
|
||||
}
|
||||
@@ -134,12 +135,12 @@ Blockly.MenuItem.prototype.createDom = function() {
|
||||
|
||||
// Initialize ARIA role and state.
|
||||
if (this.roleName_) {
|
||||
Blockly.utils.aria.setRole(element, this.roleName_);
|
||||
aria.setRole(element, this.roleName_);
|
||||
}
|
||||
Blockly.utils.aria.setState(element, Blockly.utils.aria.State.SELECTED,
|
||||
aria.setState(
|
||||
element, aria.State.SELECTED,
|
||||
(this.checkable_ && this.checked_) || false);
|
||||
Blockly.utils.aria.setState(element, Blockly.utils.aria.State.DISABLED,
|
||||
!this.enabled_);
|
||||
aria.setState(element, aria.State.DISABLED, !this.enabled_);
|
||||
|
||||
return element;
|
||||
};
|
||||
@@ -147,7 +148,7 @@ Blockly.MenuItem.prototype.createDom = function() {
|
||||
/**
|
||||
* Dispose of this menu item.
|
||||
*/
|
||||
Blockly.MenuItem.prototype.dispose = function() {
|
||||
MenuItem.prototype.dispose = function() {
|
||||
this.element_ = null;
|
||||
};
|
||||
|
||||
@@ -156,7 +157,7 @@ Blockly.MenuItem.prototype.dispose = function() {
|
||||
* @return {?Element} The DOM element.
|
||||
* @package
|
||||
*/
|
||||
Blockly.MenuItem.prototype.getElement = function() {
|
||||
MenuItem.prototype.getElement = function() {
|
||||
return this.element_;
|
||||
};
|
||||
|
||||
@@ -165,7 +166,7 @@ Blockly.MenuItem.prototype.getElement = function() {
|
||||
* @return {string} Unique component ID.
|
||||
* @package
|
||||
*/
|
||||
Blockly.MenuItem.prototype.getId = function() {
|
||||
MenuItem.prototype.getId = function() {
|
||||
return this.element_.id;
|
||||
};
|
||||
|
||||
@@ -174,7 +175,7 @@ Blockly.MenuItem.prototype.getId = function() {
|
||||
* @return {*} value Value associated with the menu item.
|
||||
* @package
|
||||
*/
|
||||
Blockly.MenuItem.prototype.getValue = function() {
|
||||
MenuItem.prototype.getValue = function() {
|
||||
return this.value_;
|
||||
};
|
||||
|
||||
@@ -183,16 +184,16 @@ Blockly.MenuItem.prototype.getValue = function() {
|
||||
* @param {boolean} rtl True if RTL, false if LTR.
|
||||
* @package
|
||||
*/
|
||||
Blockly.MenuItem.prototype.setRightToLeft = function(rtl) {
|
||||
MenuItem.prototype.setRightToLeft = function(rtl) {
|
||||
this.rightToLeft_ = rtl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the menu item's accessibility role.
|
||||
* @param {!Blockly.utils.aria.Role} roleName Role name.
|
||||
* @param {!aria.Role} roleName Role name.
|
||||
* @package
|
||||
*/
|
||||
Blockly.MenuItem.prototype.setRole = function(roleName) {
|
||||
MenuItem.prototype.setRole = function(roleName) {
|
||||
this.roleName_ = roleName;
|
||||
};
|
||||
|
||||
@@ -202,7 +203,7 @@ Blockly.MenuItem.prototype.setRole = function(roleName) {
|
||||
* @param {boolean} checkable Whether the menu item is checkable.
|
||||
* @package
|
||||
*/
|
||||
Blockly.MenuItem.prototype.setCheckable = function(checkable) {
|
||||
MenuItem.prototype.setCheckable = function(checkable) {
|
||||
this.checkable_ = checkable;
|
||||
};
|
||||
|
||||
@@ -211,7 +212,7 @@ Blockly.MenuItem.prototype.setCheckable = function(checkable) {
|
||||
* @param {boolean} checked Whether to check or uncheck the component.
|
||||
* @package
|
||||
*/
|
||||
Blockly.MenuItem.prototype.setChecked = function(checked) {
|
||||
MenuItem.prototype.setChecked = function(checked) {
|
||||
this.checked_ = checked;
|
||||
};
|
||||
|
||||
@@ -220,21 +221,21 @@ Blockly.MenuItem.prototype.setChecked = function(checked) {
|
||||
* @param {boolean} highlight Whether to highlight or unhighlight the component.
|
||||
* @package
|
||||
*/
|
||||
Blockly.MenuItem.prototype.setHighlighted = function(highlight) {
|
||||
MenuItem.prototype.setHighlighted = function(highlight) {
|
||||
this.highlight_ = highlight;
|
||||
|
||||
var el = this.getElement();
|
||||
const el = this.getElement();
|
||||
if (el && this.isEnabled()) {
|
||||
// goog-menuitem-highlight is deprecated, use blocklyMenuItemHighlight.
|
||||
// May 2020.
|
||||
var name = 'blocklyMenuItemHighlight';
|
||||
var nameDep = 'goog-menuitem-highlight';
|
||||
const name = 'blocklyMenuItemHighlight';
|
||||
const nameDep = 'goog-menuitem-highlight';
|
||||
if (highlight) {
|
||||
Blockly.utils.dom.addClass(el, name);
|
||||
Blockly.utils.dom.addClass(el, nameDep);
|
||||
dom.addClass(el, name);
|
||||
dom.addClass(el, nameDep);
|
||||
} else {
|
||||
Blockly.utils.dom.removeClass(el, name);
|
||||
Blockly.utils.dom.removeClass(el, nameDep);
|
||||
dom.removeClass(el, name);
|
||||
dom.removeClass(el, nameDep);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -244,7 +245,7 @@ Blockly.MenuItem.prototype.setHighlighted = function(highlight) {
|
||||
* @return {boolean} Whether the menu item is enabled.
|
||||
* @package
|
||||
*/
|
||||
Blockly.MenuItem.prototype.isEnabled = function() {
|
||||
MenuItem.prototype.isEnabled = function() {
|
||||
return this.enabled_;
|
||||
};
|
||||
|
||||
@@ -253,7 +254,7 @@ Blockly.MenuItem.prototype.isEnabled = function() {
|
||||
* @param {boolean} enabled Whether to enable or disable the menu item.
|
||||
* @package
|
||||
*/
|
||||
Blockly.MenuItem.prototype.setEnabled = function(enabled) {
|
||||
MenuItem.prototype.setEnabled = function(enabled) {
|
||||
this.enabled_ = enabled;
|
||||
};
|
||||
|
||||
@@ -262,7 +263,7 @@ Blockly.MenuItem.prototype.setEnabled = function(enabled) {
|
||||
* by the user.
|
||||
* @package
|
||||
*/
|
||||
Blockly.MenuItem.prototype.performAction = function() {
|
||||
MenuItem.prototype.performAction = function() {
|
||||
if (this.isEnabled() && this.actionHandler_) {
|
||||
this.actionHandler_(this);
|
||||
}
|
||||
@@ -271,10 +272,12 @@ Blockly.MenuItem.prototype.performAction = function() {
|
||||
/**
|
||||
* Set the handler that's called when the menu item is activated by the user.
|
||||
* `obj` will be used as the 'this' object in the function when called.
|
||||
* @param {function(!Blockly.MenuItem)} fn The handler.
|
||||
* @param {function(!MenuItem)} fn The handler.
|
||||
* @param {!Object} obj Used as the 'this' object in fn when called.
|
||||
* @package
|
||||
*/
|
||||
Blockly.MenuItem.prototype.onAction = function(fn, obj) {
|
||||
MenuItem.prototype.onAction = function(fn, obj) {
|
||||
this.actionHandler_ = fn.bind(obj);
|
||||
};
|
||||
|
||||
exports = MenuItem;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
goog.provide('Blockly.FlyoutMetricsManager');
|
||||
goog.provide('Blockly.MetricsManager');
|
||||
|
||||
goog.require('Blockly.IMetricsManager');
|
||||
goog.requireType('Blockly.IMetricsManager');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.utils.Size');
|
||||
goog.require('Blockly.utils.toolbox');
|
||||
|
||||
302
core/mutator.js
302
core/mutator.js
@@ -11,81 +11,88 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Mutator');
|
||||
goog.module('Blockly.Mutator');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Bubble');
|
||||
goog.require('Blockly.Events');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Abstract = goog.requireType('Blockly.Events.Abstract');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlocklyOptions = goog.requireType('Blockly.BlocklyOptions');
|
||||
/* 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 Connection = goog.requireType('Blockly.Connection');
|
||||
/* 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');
|
||||
const Options = goog.require('Blockly.Options');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Workspace = goog.requireType('Blockly.Workspace');
|
||||
const WorkspaceSvg = goog.require('Blockly.WorkspaceSvg');
|
||||
const Xml = goog.require('Blockly.Xml');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const internalConstants = goog.require('Blockly.internalConstants');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const toolbox = goog.require('Blockly.utils.toolbox');
|
||||
const xml = goog.require('Blockly.utils.xml');
|
||||
/** @suppress {extraRequire} */
|
||||
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');
|
||||
goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
goog.require('Blockly.utils.toolbox');
|
||||
goog.require('Blockly.utils.xml');
|
||||
goog.require('Blockly.WorkspaceSvg');
|
||||
goog.require('Blockly.Xml');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.Connection');
|
||||
goog.requireType('Blockly.Events.Abstract');
|
||||
goog.requireType('Blockly.utils.Coordinate');
|
||||
goog.requireType('Blockly.Workspace');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a mutator dialog.
|
||||
* @param {!Array<string>} quarkNames List of names of sub-blocks for flyout.
|
||||
* @extends {Blockly.Icon}
|
||||
* @extends {Icon}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Mutator = function(quarkNames) {
|
||||
Blockly.Mutator.superClass_.constructor.call(this, null);
|
||||
const Mutator = function(quarkNames) {
|
||||
Mutator.superClass_.constructor.call(this, null);
|
||||
this.quarkNames_ = quarkNames;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.Mutator, Blockly.Icon);
|
||||
object.inherits(Mutator, Icon);
|
||||
|
||||
/**
|
||||
* Workspace in the mutator's bubble.
|
||||
* @type {?Blockly.WorkspaceSvg}
|
||||
* @type {?WorkspaceSvg}
|
||||
* @private
|
||||
*/
|
||||
Blockly.Mutator.prototype.workspace_ = null;
|
||||
Mutator.prototype.workspace_ = null;
|
||||
|
||||
/**
|
||||
* Width of workspace.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Mutator.prototype.workspaceWidth_ = 0;
|
||||
Mutator.prototype.workspaceWidth_ = 0;
|
||||
|
||||
/**
|
||||
* Height of workspace.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Mutator.prototype.workspaceHeight_ = 0;
|
||||
Mutator.prototype.workspaceHeight_ = 0;
|
||||
|
||||
/**
|
||||
* Set the block this mutator is associated with.
|
||||
* @param {!Blockly.BlockSvg} block The block associated with this mutator.
|
||||
* @param {!BlockSvg} block The block associated with this mutator.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Mutator.prototype.setBlock = function(block) {
|
||||
Mutator.prototype.setBlock = function(block) {
|
||||
this.block_ = block;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the workspace inside this mutator icon's bubble.
|
||||
* @return {?Blockly.WorkspaceSvg} The workspace inside this mutator icon's
|
||||
* @return {?WorkspaceSvg} The workspace inside this mutator icon's
|
||||
* bubble or null if the mutator isn't open.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Mutator.prototype.getWorkspace = function() {
|
||||
Mutator.prototype.getWorkspace = function() {
|
||||
return this.workspace_;
|
||||
};
|
||||
|
||||
@@ -94,11 +101,10 @@ Blockly.Mutator.prototype.getWorkspace = function() {
|
||||
* @param {!Element} group The icon group.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Mutator.prototype.drawIcon_ = function(group) {
|
||||
Mutator.prototype.drawIcon_ = function(group) {
|
||||
// Square with rounded corners.
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.RECT,
|
||||
{
|
||||
dom.createSvgElement(
|
||||
Svg.RECT, {
|
||||
'class': 'blocklyIconShape',
|
||||
'rx': '4',
|
||||
'ry': '4',
|
||||
@@ -107,29 +113,22 @@ Blockly.Mutator.prototype.drawIcon_ = function(group) {
|
||||
},
|
||||
group);
|
||||
// Gear teeth.
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.PATH,
|
||||
{
|
||||
dom.createSvgElement(
|
||||
Svg.PATH, {
|
||||
'class': 'blocklyIconSymbol',
|
||||
'd': 'm4.203,7.296 0,1.368 -0.92,0.677 -0.11,0.41 0.9,1.559 0.41,' +
|
||||
'0.11 1.043,-0.457 1.187,0.683 0.127,1.134 0.3,0.3 1.8,0 0.3,' +
|
||||
'-0.299 0.127,-1.138 1.185,-0.682 1.046,0.458 0.409,-0.11 0.9,' +
|
||||
'-1.559 -0.11,-0.41 -0.92,-0.677 0,-1.366 0.92,-0.677 0.11,' +
|
||||
'-0.41 -0.9,-1.559 -0.409,-0.109 -1.046,0.458 -1.185,-0.682 ' +
|
||||
'-0.127,-1.138 -0.3,-0.299 -1.8,0 -0.3,0.3 -0.126,1.135 -1.187,' +
|
||||
'0.682 -1.043,-0.457 -0.41,0.11 -0.899,1.559 0.108,0.409z'
|
||||
'0.11 1.043,-0.457 1.187,0.683 0.127,1.134 0.3,0.3 1.8,0 0.3,' +
|
||||
'-0.299 0.127,-1.138 1.185,-0.682 1.046,0.458 0.409,-0.11 0.9,' +
|
||||
'-1.559 -0.11,-0.41 -0.92,-0.677 0,-1.366 0.92,-0.677 0.11,' +
|
||||
'-0.41 -0.9,-1.559 -0.409,-0.109 -1.046,0.458 -1.185,-0.682 ' +
|
||||
'-0.127,-1.138 -0.3,-0.299 -1.8,0 -0.3,0.3 -0.126,1.135 -1.187,' +
|
||||
'0.682 -1.043,-0.457 -0.41,0.11 -0.899,1.559 0.108,0.409z'
|
||||
},
|
||||
group);
|
||||
// Axle hole.
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.CIRCLE,
|
||||
{
|
||||
'class': 'blocklyIconShape',
|
||||
'r': '2.7',
|
||||
'cx': '8',
|
||||
'cy': '8'
|
||||
},
|
||||
group);
|
||||
dom.createSvgElement(
|
||||
Svg.CIRCLE,
|
||||
{'class': 'blocklyIconShape', 'r': '2.7', 'cx': '8', 'cy': '8'}, group);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -139,9 +138,9 @@ Blockly.Mutator.prototype.drawIcon_ = function(group) {
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
Blockly.Mutator.prototype.iconClick_ = function(e) {
|
||||
Mutator.prototype.iconClick_ = function(e) {
|
||||
if (this.block_.isEditable()) {
|
||||
Blockly.Icon.prototype.iconClick_.call(this, e);
|
||||
Icon.prototype.iconClick_.call(this, e);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -150,29 +149,28 @@ Blockly.Mutator.prototype.iconClick_ = function(e) {
|
||||
* @return {!SVGElement} The top-level node of the editor.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Mutator.prototype.createEditor_ = function() {
|
||||
Mutator.prototype.createEditor_ = function() {
|
||||
/* Create the editor. Here's the markup that will be generated:
|
||||
<svg>
|
||||
[Workspace]
|
||||
</svg>
|
||||
*/
|
||||
this.svgDialog_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.SVG,
|
||||
{'x': Blockly.Bubble.BORDER_WIDTH, 'y': Blockly.Bubble.BORDER_WIDTH},
|
||||
null);
|
||||
this.svgDialog_ = dom.createSvgElement(
|
||||
Svg.SVG, {'x': Bubble.BORDER_WIDTH, 'y': Bubble.BORDER_WIDTH}, null);
|
||||
// Convert the list of names into a list of XML objects for the flyout.
|
||||
let quarkXml;
|
||||
if (this.quarkNames_.length) {
|
||||
var quarkXml = Blockly.utils.xml.createElement('xml');
|
||||
for (var i = 0, quarkName; (quarkName = this.quarkNames_[i]); i++) {
|
||||
var element = Blockly.utils.xml.createElement('block');
|
||||
quarkXml = xml.createElement('xml');
|
||||
for (let i = 0, quarkName; (quarkName = this.quarkNames_[i]); i++) {
|
||||
const element = xml.createElement('block');
|
||||
element.setAttribute('type', quarkName);
|
||||
quarkXml.appendChild(element);
|
||||
}
|
||||
} else {
|
||||
var quarkXml = null;
|
||||
quarkXml = null;
|
||||
}
|
||||
var workspaceOptions = new Blockly.Options(
|
||||
/** @type {!Blockly.BlocklyOptions} */
|
||||
const workspaceOptions = new Options(
|
||||
/** @type {!BlocklyOptions} */
|
||||
({
|
||||
// If you want to enable disabling, also remove the
|
||||
// event filter from workspaceChanged_ .
|
||||
@@ -184,25 +182,22 @@ Blockly.Mutator.prototype.createEditor_ = function() {
|
||||
'renderer': this.block_.workspace.options.renderer,
|
||||
'rendererOverrides': this.block_.workspace.options.rendererOverrides
|
||||
}));
|
||||
workspaceOptions.toolboxPosition = this.block_.RTL ?
|
||||
Blockly.utils.toolbox.Position.RIGHT :
|
||||
Blockly.utils.toolbox.Position.LEFT;
|
||||
var hasFlyout = !!quarkXml;
|
||||
workspaceOptions.toolboxPosition =
|
||||
this.block_.RTL ? toolbox.Position.RIGHT : toolbox.Position.LEFT;
|
||||
const hasFlyout = !!quarkXml;
|
||||
if (hasFlyout) {
|
||||
workspaceOptions.languageTree =
|
||||
Blockly.utils.toolbox.convertToolboxDefToJson(quarkXml);
|
||||
workspaceOptions.languageTree = toolbox.convertToolboxDefToJson(quarkXml);
|
||||
}
|
||||
this.workspace_ = new Blockly.WorkspaceSvg(workspaceOptions);
|
||||
this.workspace_ = new WorkspaceSvg(workspaceOptions);
|
||||
this.workspace_.isMutator = true;
|
||||
this.workspace_.addChangeListener(Blockly.Events.disableOrphans);
|
||||
this.workspace_.addChangeListener(Events.disableOrphans);
|
||||
|
||||
// Mutator flyouts go inside the mutator workspace's <g> rather than in
|
||||
// a top level SVG. Instead of handling scale themselves, mutators
|
||||
// inherit scale from the parent workspace.
|
||||
// To fix this, scale needs to be applied at a different level in the DOM.
|
||||
var flyoutSvg = hasFlyout ?
|
||||
this.workspace_.addFlyout(Blockly.utils.Svg.G) : null;
|
||||
var background = this.workspace_.createDom('blocklyMutatorBackground');
|
||||
const flyoutSvg = hasFlyout ? this.workspace_.addFlyout(Svg.G) : null;
|
||||
const background = this.workspace_.createDom('blocklyMutatorBackground');
|
||||
|
||||
if (flyoutSvg) {
|
||||
// Insert the flyout after the <rect> but before the block canvas so that
|
||||
@@ -218,12 +213,12 @@ Blockly.Mutator.prototype.createEditor_ = function() {
|
||||
/**
|
||||
* Add or remove the UI indicating if this icon may be clicked or not.
|
||||
*/
|
||||
Blockly.Mutator.prototype.updateEditable = function() {
|
||||
Blockly.Mutator.superClass_.updateEditable.call(this);
|
||||
Mutator.prototype.updateEditable = function() {
|
||||
Mutator.superClass_.updateEditable.call(this);
|
||||
if (!this.block_.isInFlyout) {
|
||||
if (this.block_.isEditable()) {
|
||||
if (this.iconGroup_) {
|
||||
Blockly.utils.dom.removeClass(
|
||||
dom.removeClass(
|
||||
/** @type {!Element} */ (this.iconGroup_),
|
||||
'blocklyIconGroupReadonly');
|
||||
}
|
||||
@@ -231,7 +226,7 @@ Blockly.Mutator.prototype.updateEditable = function() {
|
||||
// Close any mutator bubble. Icon is not clickable.
|
||||
this.setVisible(false);
|
||||
if (this.iconGroup_) {
|
||||
Blockly.utils.dom.addClass(
|
||||
dom.addClass(
|
||||
/** @type {!Element} */ (this.iconGroup_),
|
||||
'blocklyIconGroupReadonly');
|
||||
}
|
||||
@@ -243,15 +238,15 @@ Blockly.Mutator.prototype.updateEditable = function() {
|
||||
* Resize the bubble to match the size of the workspace.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Mutator.prototype.resizeBubble_ = function() {
|
||||
var doubleBorderWidth = 2 * Blockly.Bubble.BORDER_WIDTH;
|
||||
var workspaceSize = this.workspace_.getCanvas().getBBox();
|
||||
var width = workspaceSize.width + workspaceSize.x;
|
||||
var height = workspaceSize.height + doubleBorderWidth * 3;
|
||||
var flyout = this.workspace_.getFlyout();
|
||||
Mutator.prototype.resizeBubble_ = function() {
|
||||
const doubleBorderWidth = 2 * Bubble.BORDER_WIDTH;
|
||||
const workspaceSize = this.workspace_.getCanvas().getBBox();
|
||||
let width = workspaceSize.width + workspaceSize.x;
|
||||
let height = workspaceSize.height + doubleBorderWidth * 3;
|
||||
const flyout = this.workspace_.getFlyout();
|
||||
if (flyout) {
|
||||
var flyoutScrollMetrics = flyout.getWorkspace().getMetricsManager()
|
||||
.getScrollMetrics();
|
||||
const flyoutScrollMetrics =
|
||||
flyout.getWorkspace().getMetricsManager().getScrollMetrics();
|
||||
height = Math.max(height, flyoutScrollMetrics.height + 20);
|
||||
width += flyout.getWidth();
|
||||
}
|
||||
@@ -276,7 +271,7 @@ Blockly.Mutator.prototype.resizeBubble_ = function() {
|
||||
|
||||
if (this.block_.RTL) {
|
||||
// Scroll the workspace to always left-align.
|
||||
var translation = 'translate(' + this.workspaceWidth_ + ',0)';
|
||||
const translation = 'translate(' + this.workspaceWidth_ + ',0)';
|
||||
this.workspace_.getCanvas().setAttribute('transform', translation);
|
||||
}
|
||||
this.workspace_.resize();
|
||||
@@ -286,7 +281,7 @@ Blockly.Mutator.prototype.resizeBubble_ = function() {
|
||||
* A method handler for when the bubble is moved.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Mutator.prototype.onBubbleMove_ = function() {
|
||||
Mutator.prototype.onBubbleMove_ = function() {
|
||||
if (this.workspace_) {
|
||||
this.workspace_.recordDragTargets();
|
||||
}
|
||||
@@ -296,43 +291,44 @@ Blockly.Mutator.prototype.onBubbleMove_ = function() {
|
||||
* Show or hide the mutator bubble.
|
||||
* @param {boolean} visible True if the bubble should be visible.
|
||||
*/
|
||||
Blockly.Mutator.prototype.setVisible = function(visible) {
|
||||
Mutator.prototype.setVisible = function(visible) {
|
||||
if (visible == this.isVisible()) {
|
||||
// No change.
|
||||
return;
|
||||
}
|
||||
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BUBBLE_OPEN))(
|
||||
this.block_, visible, 'mutator'));
|
||||
Events.fire(
|
||||
new (Events.get(Events.BUBBLE_OPEN))(this.block_, visible, 'mutator'));
|
||||
if (visible) {
|
||||
// Create the bubble.
|
||||
this.bubble_ = new Blockly.Bubble(
|
||||
/** @type {!Blockly.WorkspaceSvg} */ (this.block_.workspace),
|
||||
this.bubble_ = new Bubble(
|
||||
/** @type {!WorkspaceSvg} */ (this.block_.workspace),
|
||||
this.createEditor_(), this.block_.pathObject.svgPath,
|
||||
/** @type {!Blockly.utils.Coordinate} */ (this.iconXY_), null, null);
|
||||
/** @type {!Coordinate} */ (this.iconXY_), null, null);
|
||||
// Expose this mutator's block's ID on its top-level SVG group.
|
||||
this.bubble_.setSvgId(this.block_.id);
|
||||
this.bubble_.registerMoveEvent(this.onBubbleMove_.bind(this));
|
||||
var tree = this.workspace_.options.languageTree;
|
||||
var flyout = this.workspace_.getFlyout();
|
||||
const tree = this.workspace_.options.languageTree;
|
||||
const flyout = this.workspace_.getFlyout();
|
||||
if (tree) {
|
||||
flyout.init(this.workspace_);
|
||||
flyout.show(tree);
|
||||
}
|
||||
|
||||
this.rootBlock_ = this.block_.decompose(this.workspace_);
|
||||
var blocks = this.rootBlock_.getDescendants(false);
|
||||
for (var i = 0, child; (child = blocks[i]); i++) {
|
||||
const blocks = this.rootBlock_.getDescendants(false);
|
||||
for (let i = 0, child; (child = blocks[i]); i++) {
|
||||
child.render();
|
||||
}
|
||||
// The root block should not be draggable or deletable.
|
||||
this.rootBlock_.setMovable(false);
|
||||
this.rootBlock_.setDeletable(false);
|
||||
let margin, x;
|
||||
if (flyout) {
|
||||
var margin = flyout.CORNER_RADIUS * 2;
|
||||
var x = this.rootBlock_.RTL ? flyout.getWidth() + margin : margin;
|
||||
margin = flyout.CORNER_RADIUS * 2;
|
||||
x = this.rootBlock_.RTL ? flyout.getWidth() + margin : margin;
|
||||
} else {
|
||||
var margin = 16;
|
||||
var x = margin;
|
||||
margin = 16;
|
||||
x = margin;
|
||||
}
|
||||
if (this.block_.RTL) {
|
||||
x = -x;
|
||||
@@ -340,10 +336,9 @@ Blockly.Mutator.prototype.setVisible = function(visible) {
|
||||
this.rootBlock_.moveBy(x, margin);
|
||||
// Save the initial connections, then listen for further changes.
|
||||
if (this.block_.saveConnections) {
|
||||
var thisMutator = this;
|
||||
var mutatorBlock =
|
||||
/** @type {{saveConnections: function(!Blockly.Block)}} */ (
|
||||
this.block_);
|
||||
const thisMutator = this;
|
||||
const mutatorBlock =
|
||||
/** @type {{saveConnections: function(!Block)}} */ (this.block_);
|
||||
mutatorBlock.saveConnections(this.rootBlock_);
|
||||
this.sourceListener_ = function() {
|
||||
mutatorBlock.saveConnections(thisMutator.rootBlock_);
|
||||
@@ -375,21 +370,20 @@ Blockly.Mutator.prototype.setVisible = function(visible) {
|
||||
* Update the source block when the mutator's blocks are changed.
|
||||
* Bump down any block that's too high.
|
||||
* Fired whenever a change is made to the mutator's workspace.
|
||||
* @param {!Blockly.Events.Abstract} e Custom data for event.
|
||||
* @param {!Abstract} e Custom data for event.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Mutator.prototype.workspaceChanged_ = function(e) {
|
||||
if (e.isUiEvent ||
|
||||
(e.type == Blockly.Events.CHANGE && e.element == 'disabled')) {
|
||||
Mutator.prototype.workspaceChanged_ = function(e) {
|
||||
if (e.isUiEvent || (e.type == Events.CHANGE && e.element == 'disabled')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.workspace_.isDragging()) {
|
||||
var blocks = this.workspace_.getTopBlocks(false);
|
||||
var MARGIN = 20;
|
||||
const blocks = this.workspace_.getTopBlocks(false);
|
||||
const MARGIN = 20;
|
||||
|
||||
for (var b = 0, block; (block = blocks[b]); b++) {
|
||||
var blockXY = block.getRelativeToSurfaceXY();
|
||||
for (let b = 0, block; (block = blocks[b]); b++) {
|
||||
const blockXY = block.getRelativeToSurfaceXY();
|
||||
|
||||
// Bump any block that's above the top back inside.
|
||||
if (blockXY.y < MARGIN) {
|
||||
@@ -397,8 +391,8 @@ Blockly.Mutator.prototype.workspaceChanged_ = function(e) {
|
||||
}
|
||||
// Bump any block overlapping the flyout back inside.
|
||||
if (block.RTL) {
|
||||
var right = -MARGIN;
|
||||
var flyout = this.workspace_.getFlyout();
|
||||
let right = -MARGIN;
|
||||
const flyout = this.workspace_.getFlyout();
|
||||
if (flyout) {
|
||||
right -= flyout.getWidth();
|
||||
}
|
||||
@@ -413,13 +407,13 @@ Blockly.Mutator.prototype.workspaceChanged_ = function(e) {
|
||||
|
||||
// When the mutator's workspace changes, update the source block.
|
||||
if (this.rootBlock_.workspace == this.workspace_) {
|
||||
Blockly.Events.setGroup(true);
|
||||
var block = this.block_;
|
||||
var oldMutationDom = block.mutationToDom();
|
||||
var oldMutation = oldMutationDom && Blockly.Xml.domToText(oldMutationDom);
|
||||
Events.setGroup(true);
|
||||
const block = this.block_;
|
||||
const oldMutationDom = block.mutationToDom();
|
||||
const oldMutation = oldMutationDom && Xml.domToText(oldMutationDom);
|
||||
|
||||
// Switch off rendering while the source block is rebuilt.
|
||||
var savedRendered = block.rendered;
|
||||
const savedRendered = block.rendered;
|
||||
// TODO(#4288): We should not be setting the rendered property to false.
|
||||
block.rendered = false;
|
||||
|
||||
@@ -434,18 +428,18 @@ Blockly.Mutator.prototype.workspaceChanged_ = function(e) {
|
||||
block.render();
|
||||
}
|
||||
|
||||
var newMutationDom = block.mutationToDom();
|
||||
var newMutation = newMutationDom && Blockly.Xml.domToText(newMutationDom);
|
||||
const newMutationDom = block.mutationToDom();
|
||||
const newMutation = newMutationDom && Xml.domToText(newMutationDom);
|
||||
if (oldMutation != newMutation) {
|
||||
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))(
|
||||
Events.fire(new (Events.get(Events.BLOCK_CHANGE))(
|
||||
block, 'mutation', null, oldMutation, newMutation));
|
||||
// Ensure that any bump is part of this mutation's event group.
|
||||
var group = Blockly.Events.getGroup();
|
||||
const group = Events.getGroup();
|
||||
setTimeout(function() {
|
||||
Blockly.Events.setGroup(group);
|
||||
Events.setGroup(group);
|
||||
block.bumpNeighbours();
|
||||
Blockly.Events.setGroup(false);
|
||||
}, Blockly.internalConstants.BUMP_DELAY);
|
||||
Events.setGroup(false);
|
||||
}, internalConstants.BUMP_DELAY);
|
||||
}
|
||||
|
||||
// Don't update the bubble until the drag has ended, to avoid moving blocks
|
||||
@@ -453,35 +447,35 @@ Blockly.Mutator.prototype.workspaceChanged_ = function(e) {
|
||||
if (!this.workspace_.isDragging()) {
|
||||
this.resizeBubble_();
|
||||
}
|
||||
Blockly.Events.setGroup(false);
|
||||
Events.setGroup(false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispose of this mutator.
|
||||
*/
|
||||
Blockly.Mutator.prototype.dispose = function() {
|
||||
Mutator.prototype.dispose = function() {
|
||||
this.block_.mutator = null;
|
||||
Blockly.Icon.prototype.dispose.call(this);
|
||||
Icon.prototype.dispose.call(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the styles on all blocks in the mutator.
|
||||
* @public
|
||||
*/
|
||||
Blockly.Mutator.prototype.updateBlockStyle = function() {
|
||||
var ws = this.workspace_;
|
||||
Mutator.prototype.updateBlockStyle = function() {
|
||||
const ws = this.workspace_;
|
||||
|
||||
if (ws && ws.getAllBlocks(false)) {
|
||||
var workspaceBlocks = ws.getAllBlocks(false);
|
||||
for (var i = 0, block; (block = workspaceBlocks[i]); i++) {
|
||||
const workspaceBlocks = ws.getAllBlocks(false);
|
||||
for (let i = 0, block; (block = workspaceBlocks[i]); i++) {
|
||||
block.setStyle(block.getStyleName());
|
||||
}
|
||||
|
||||
var flyout = ws.getFlyout();
|
||||
const flyout = ws.getFlyout();
|
||||
if (flyout) {
|
||||
var flyoutBlocks = flyout.workspace_.getAllBlocks(false);
|
||||
for (var i = 0, block; (block = flyoutBlocks[i]); i++) {
|
||||
const flyoutBlocks = flyout.workspace_.getAllBlocks(false);
|
||||
for (let i = 0, block; (block = flyoutBlocks[i]); i++) {
|
||||
block.setStyle(block.getStyleName());
|
||||
}
|
||||
}
|
||||
@@ -490,17 +484,17 @@ Blockly.Mutator.prototype.updateBlockStyle = function() {
|
||||
|
||||
/**
|
||||
* Reconnect an block to a mutated input.
|
||||
* @param {Blockly.Connection} connectionChild Connection on child block.
|
||||
* @param {!Blockly.Block} block Parent block.
|
||||
* @param {Connection} connectionChild Connection on child block.
|
||||
* @param {!Block} block Parent block.
|
||||
* @param {string} inputName Name of input on parent block.
|
||||
* @return {boolean} True iff a reconnection was made, false otherwise.
|
||||
*/
|
||||
Blockly.Mutator.reconnect = function(connectionChild, block, inputName) {
|
||||
Mutator.reconnect = function(connectionChild, block, inputName) {
|
||||
if (!connectionChild || !connectionChild.getSourceBlock().workspace) {
|
||||
return false; // No connection or block has been deleted.
|
||||
}
|
||||
var connectionParent = block.getInput(inputName).connection;
|
||||
var currentParent = connectionChild.targetBlock();
|
||||
const connectionParent = block.getInput(inputName).connection;
|
||||
const currentParent = connectionChild.targetBlock();
|
||||
if ((!currentParent || currentParent == block) &&
|
||||
connectionParent.targetConnection != connectionChild) {
|
||||
if (connectionParent.isConnected()) {
|
||||
@@ -516,14 +510,14 @@ Blockly.Mutator.reconnect = function(connectionChild, block, inputName) {
|
||||
/**
|
||||
* Get the parent workspace of a workspace that is inside a mutator, taking into
|
||||
* account whether it is a flyout.
|
||||
* @param {Blockly.Workspace} workspace The workspace that is inside a mutator.
|
||||
* @return {?Blockly.Workspace} The mutator's parent workspace or null.
|
||||
* @param {Workspace} workspace The workspace that is inside a mutator.
|
||||
* @return {?Workspace} The mutator's parent workspace or null.
|
||||
* @public
|
||||
*/
|
||||
Blockly.Mutator.findParentWs = function(workspace) {
|
||||
var outerWs = null;
|
||||
Mutator.findParentWs = function(workspace) {
|
||||
let outerWs = null;
|
||||
if (workspace && workspace.options) {
|
||||
var parent = workspace.options.parentWorkspace;
|
||||
const parent = workspace.options.parentWorkspace;
|
||||
// If we were in a flyout in a mutator, need to go up two levels to find
|
||||
// the actual parent.
|
||||
if (workspace.isFlyout) {
|
||||
@@ -536,3 +530,5 @@ Blockly.Mutator.findParentWs = function(workspace) {
|
||||
}
|
||||
return outerWs;
|
||||
};
|
||||
|
||||
exports = Mutator;
|
||||
|
||||
105
core/names.js
105
core/names.js
@@ -10,12 +10,18 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Names');
|
||||
goog.module('Blockly.Names');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.internalConstants');
|
||||
goog.require('Blockly.Msg');
|
||||
|
||||
goog.requireType('Blockly.VariableMap');
|
||||
const Msg = goog.require('Blockly.Msg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const VariableMap = goog.requireType('Blockly.VariableMap');
|
||||
const Variables = goog.require('Blockly.Variables');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Workspace = goog.requireType('Blockly.Workspace');
|
||||
const internalConstants = goog.require('Blockly.internalConstants');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.requireType('Blockly.Procedures');
|
||||
|
||||
|
||||
/**
|
||||
@@ -26,12 +32,12 @@ goog.requireType('Blockly.VariableMap');
|
||||
* before all variable names (but not procedure names).
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Names = function(reservedWords, opt_variablePrefix) {
|
||||
const Names = function(reservedWords, opt_variablePrefix) {
|
||||
this.variablePrefix_ = opt_variablePrefix || '';
|
||||
this.reservedDict_ = Object.create(null);
|
||||
if (reservedWords) {
|
||||
var splitWords = reservedWords.split(',');
|
||||
for (var i = 0; i < splitWords.length; i++) {
|
||||
const splitWords = reservedWords.split(',');
|
||||
for (let i = 0; i < splitWords.length; i++) {
|
||||
this.reservedDict_[splitWords[i]] = true;
|
||||
}
|
||||
}
|
||||
@@ -45,7 +51,7 @@ Blockly.Names = function(reservedWords, opt_variablePrefix) {
|
||||
* will never be shown to the user in the workspace or stored in the variable
|
||||
* map.
|
||||
*/
|
||||
Blockly.Names.DEVELOPER_VARIABLE_TYPE = 'DEVELOPER_VARIABLE';
|
||||
Names.DEVELOPER_VARIABLE_TYPE = 'DEVELOPER_VARIABLE';
|
||||
|
||||
/**
|
||||
* When JavaScript (or most other languages) is generated, variable 'foo' and
|
||||
@@ -59,7 +65,7 @@ Blockly.Names.DEVELOPER_VARIABLE_TYPE = 'DEVELOPER_VARIABLE';
|
||||
/**
|
||||
* Empty the database and start from scratch. The reserved words are kept.
|
||||
*/
|
||||
Blockly.Names.prototype.reset = function() {
|
||||
Names.prototype.reset = function() {
|
||||
this.db_ = Object.create(null);
|
||||
this.dbReverse_ = Object.create(null);
|
||||
this.variableMap_ = null;
|
||||
@@ -67,31 +73,32 @@ Blockly.Names.prototype.reset = function() {
|
||||
|
||||
/**
|
||||
* Set the variable map that maps from variable name to variable object.
|
||||
* @param {!Blockly.VariableMap} map The map to track.
|
||||
* @param {!VariableMap} map The map to track.
|
||||
*/
|
||||
Blockly.Names.prototype.setVariableMap = function(map) {
|
||||
Names.prototype.setVariableMap = function(map) {
|
||||
this.variableMap_ = map;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the name for a user-defined variable, based on its ID.
|
||||
* This should only be used for variables of realm
|
||||
* Blockly.internalConstants.VARIABLE_CATEGORY_NAME.
|
||||
* 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.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Names.prototype.getNameForUserVariable_ = function(id) {
|
||||
Names.prototype.getNameForUserVariable_ = function(id) {
|
||||
if (!this.variableMap_) {
|
||||
console.warn('Deprecated call to Blockly.Names.prototype.getName without ' +
|
||||
console.warn(
|
||||
'Deprecated call to Names.prototype.getName without ' +
|
||||
'defining a variable map. To fix, add the following code in your ' +
|
||||
'generator\'s init() function:\n' +
|
||||
'Blockly.YourGeneratorName.nameDB_.setVariableMap(' +
|
||||
'workspace.getVariableMap());');
|
||||
return null;
|
||||
}
|
||||
var variable = this.variableMap_.getVariableById(id);
|
||||
const variable = this.variableMap_.getVariableById(id);
|
||||
if (variable) {
|
||||
return variable.name;
|
||||
}
|
||||
@@ -100,27 +107,27 @@ Blockly.Names.prototype.getNameForUserVariable_ = function(id) {
|
||||
|
||||
/**
|
||||
* Generate names for user variables, but only ones that are being used.
|
||||
* @param {!Blockly.Workspace} workspace Workspace to generate variables from.
|
||||
* @param {!Workspace} workspace Workspace to generate variables from.
|
||||
*/
|
||||
Blockly.Names.prototype.populateVariables = function(workspace) {
|
||||
var variables = Blockly.Variables.allUsedVarModels(workspace);
|
||||
for (var i = 0; i < variables.length; i++) {
|
||||
Names.prototype.populateVariables = function(workspace) {
|
||||
const variables = Variables.allUsedVarModels(workspace);
|
||||
for (let i = 0; i < variables.length; i++) {
|
||||
this.getName(
|
||||
variables[i].getId(), Blockly.internalConstants.VARIABLE_CATEGORY_NAME);
|
||||
variables[i].getId(), internalConstants.VARIABLE_CATEGORY_NAME);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate names for procedures.
|
||||
* @param {!Blockly.Workspace} workspace Workspace to generate procedures from.
|
||||
* @param {!Workspace} workspace Workspace to generate procedures from.
|
||||
*/
|
||||
Blockly.Names.prototype.populateProcedures = function(workspace) {
|
||||
var procedures = Blockly.Procedures.allProcedures(workspace);
|
||||
Names.prototype.populateProcedures = function(workspace) {
|
||||
let procedures =
|
||||
goog.module.get('Blockly.Procedures').allProcedures(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.internalConstants.PROCEDURE_CATEGORY_NAME);
|
||||
for (let i = 0; i < procedures.length; i++) {
|
||||
this.getName(procedures[i][0], internalConstants.PROCEDURE_CATEGORY_NAME);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -132,29 +139,29 @@ Blockly.Names.prototype.populateProcedures = function(workspace) {
|
||||
* ('VARIABLE', 'PROCEDURE', 'DEVELOPER_VARIABLE', etc...).
|
||||
* @return {string} An entity name that is legal in the exported language.
|
||||
*/
|
||||
Blockly.Names.prototype.getName = function(nameOrId, realm) {
|
||||
var name = nameOrId;
|
||||
if (realm == Blockly.internalConstants.VARIABLE_CATEGORY_NAME) {
|
||||
var varName = this.getNameForUserVariable_(nameOrId);
|
||||
Names.prototype.getName = function(nameOrId, realm) {
|
||||
let name = nameOrId;
|
||||
if (realm == internalConstants.VARIABLE_CATEGORY_NAME) {
|
||||
const varName = this.getNameForUserVariable_(nameOrId);
|
||||
if (varName) {
|
||||
// Successful ID lookup.
|
||||
name = varName;
|
||||
}
|
||||
}
|
||||
var normalizedName = name.toLowerCase();
|
||||
const normalizedName = name.toLowerCase();
|
||||
|
||||
var isVar = realm == Blockly.internalConstants.VARIABLE_CATEGORY_NAME ||
|
||||
realm == Blockly.Names.DEVELOPER_VARIABLE_TYPE;
|
||||
const isVar = realm == internalConstants.VARIABLE_CATEGORY_NAME ||
|
||||
realm == Names.DEVELOPER_VARIABLE_TYPE;
|
||||
|
||||
var prefix = isVar ? this.variablePrefix_ : '';
|
||||
const prefix = isVar ? this.variablePrefix_ : '';
|
||||
if (!(realm in this.db_)) {
|
||||
this.db_[realm] = Object.create(null);
|
||||
}
|
||||
var realmDb = this.db_[realm];
|
||||
const realmDb = this.db_[realm];
|
||||
if (normalizedName in realmDb) {
|
||||
return prefix + realmDb[normalizedName];
|
||||
}
|
||||
var safeName = this.getDistinctName(name, realm);
|
||||
const safeName = this.getDistinctName(name, realm);
|
||||
realmDb[normalizedName] = safeName.substr(prefix.length);
|
||||
return safeName;
|
||||
};
|
||||
@@ -165,8 +172,8 @@ Blockly.Names.prototype.getName = function(nameOrId, realm) {
|
||||
* ('VARIABLE', 'PROCEDURE', 'DEVELOPER_VARIABLE', etc...).
|
||||
* @return {!Array<string>} A list of Blockly entity names (no constraints).
|
||||
*/
|
||||
Blockly.Names.prototype.getUserNames = function(realm) {
|
||||
var realmDb = this.db_[realm] || {};
|
||||
Names.prototype.getUserNames = function(realm) {
|
||||
const realmDb = this.db_[realm] || {};
|
||||
return Object.keys(realmDb);
|
||||
};
|
||||
|
||||
@@ -180,9 +187,9 @@ Blockly.Names.prototype.getUserNames = function(realm) {
|
||||
* ('VARIABLE', 'PROCEDURE', 'DEVELOPER_VARIABLE', etc...).
|
||||
* @return {string} An entity name that is legal in the exported language.
|
||||
*/
|
||||
Blockly.Names.prototype.getDistinctName = function(name, realm) {
|
||||
var safeName = this.safeName_(name);
|
||||
var i = '';
|
||||
Names.prototype.getDistinctName = function(name, realm) {
|
||||
let safeName = this.safeName_(name);
|
||||
let i = '';
|
||||
while (this.dbReverse_[safeName + i] ||
|
||||
(safeName + i) in this.reservedDict_) {
|
||||
// Collision with existing name. Create a unique name.
|
||||
@@ -190,9 +197,9 @@ Blockly.Names.prototype.getDistinctName = function(name, realm) {
|
||||
}
|
||||
safeName += i;
|
||||
this.dbReverse_[safeName] = true;
|
||||
var isVar = realm == Blockly.internalConstants.VARIABLE_CATEGORY_NAME ||
|
||||
realm == Blockly.Names.DEVELOPER_VARIABLE_TYPE;
|
||||
var prefix = isVar ? this.variablePrefix_ : '';
|
||||
const isVar = realm == internalConstants.VARIABLE_CATEGORY_NAME ||
|
||||
realm == Names.DEVELOPER_VARIABLE_TYPE;
|
||||
const prefix = isVar ? this.variablePrefix_ : '';
|
||||
return prefix + safeName;
|
||||
};
|
||||
|
||||
@@ -204,9 +211,9 @@ Blockly.Names.prototype.getDistinctName = function(name, realm) {
|
||||
* @return {string} Safe entity name.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Names.prototype.safeName_ = function(name) {
|
||||
Names.prototype.safeName_ = function(name) {
|
||||
if (!name) {
|
||||
name = Blockly.Msg['UNNAMED_KEY'] || 'unnamed';
|
||||
name = Msg['UNNAMED_KEY'] || 'unnamed';
|
||||
} else {
|
||||
// Unfortunately names in non-latin characters will look like
|
||||
// _E9_9F_B3_E4_B9_90 which is pretty meaningless.
|
||||
@@ -227,7 +234,9 @@ Blockly.Names.prototype.safeName_ = function(name) {
|
||||
* @param {string} name2 Second name.
|
||||
* @return {boolean} True if names are the same.
|
||||
*/
|
||||
Blockly.Names.equals = function(name1, name2) {
|
||||
Names.equals = function(name1, name2) {
|
||||
// name1.localeCompare(name2) is slower.
|
||||
return name1.toLowerCase() == name2.toLowerCase();
|
||||
};
|
||||
|
||||
exports = Names;
|
||||
|
||||
218
core/options.js
218
core/options.js
@@ -10,104 +10,111 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Options');
|
||||
goog.module('Blockly.Options');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.Theme');
|
||||
goog.require('Blockly.Themes.Classic');
|
||||
goog.require('Blockly.utils.IdGenerator');
|
||||
goog.require('Blockly.utils.Metrics');
|
||||
goog.require('Blockly.utils.toolbox');
|
||||
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlocklyOptions = goog.requireType('Blockly.BlocklyOptions');
|
||||
const Classic = goog.require('Blockly.Themes.Classic');
|
||||
const IdGenerator = goog.require('Blockly.utils.IdGenerator');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Metrics = goog.requireType('Blockly.utils.Metrics');
|
||||
const Theme = goog.require('Blockly.Theme');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const deprecation = goog.require('Blockly.utils.deprecation');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
const toolbox = goog.require('Blockly.utils.toolbox');
|
||||
|
||||
|
||||
/**
|
||||
* Parse the user-specified options, using reasonable defaults where behaviour
|
||||
* is unspecified.
|
||||
* @param {!Blockly.BlocklyOptions} options Dictionary of options.
|
||||
* Specification: https://developers.google.com/blockly/guides/get-started/web#configuration
|
||||
* @param {!BlocklyOptions} options Dictionary of options.
|
||||
* Specification:
|
||||
* https://developers.google.com/blockly/guides/get-started/web#configuration
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Options = function(options) {
|
||||
var readOnly = !!options['readOnly'];
|
||||
if (readOnly) {
|
||||
var toolboxJsonDef = null;
|
||||
var hasCategories = false;
|
||||
var hasTrashcan = false;
|
||||
var hasCollapse = false;
|
||||
var hasComments = false;
|
||||
var hasDisable = false;
|
||||
var hasSounds = false;
|
||||
} else {
|
||||
var toolboxJsonDef = Blockly.utils.toolbox.convertToolboxDefToJson(options['toolbox']);
|
||||
var hasCategories = Blockly.utils.toolbox.hasCategories(toolboxJsonDef);
|
||||
var hasTrashcan = options['trashcan'];
|
||||
const Options = function(options) {
|
||||
let toolboxJsonDef = null;
|
||||
let hasCategories = false;
|
||||
let hasTrashcan = false;
|
||||
let hasCollapse = false;
|
||||
let hasComments = false;
|
||||
let hasDisable = false;
|
||||
let hasSounds = false;
|
||||
const readOnly = !!options['readOnly'];
|
||||
if (!readOnly) {
|
||||
toolboxJsonDef = toolbox.convertToolboxDefToJson(options['toolbox']);
|
||||
hasCategories = toolbox.hasCategories(toolboxJsonDef);
|
||||
hasTrashcan = options['trashcan'];
|
||||
if (hasTrashcan === undefined) {
|
||||
hasTrashcan = hasCategories;
|
||||
}
|
||||
var maxTrashcanContents = options['maxTrashcanContents'];
|
||||
if (hasTrashcan) {
|
||||
if (maxTrashcanContents === undefined) {
|
||||
maxTrashcanContents = 32;
|
||||
}
|
||||
} else {
|
||||
maxTrashcanContents = 0;
|
||||
}
|
||||
var hasCollapse = options['collapse'];
|
||||
hasCollapse = options['collapse'];
|
||||
if (hasCollapse === undefined) {
|
||||
hasCollapse = hasCategories;
|
||||
}
|
||||
var hasComments = options['comments'];
|
||||
hasComments = options['comments'];
|
||||
if (hasComments === undefined) {
|
||||
hasComments = hasCategories;
|
||||
}
|
||||
var hasDisable = options['disable'];
|
||||
hasDisable = options['disable'];
|
||||
if (hasDisable === undefined) {
|
||||
hasDisable = hasCategories;
|
||||
}
|
||||
var hasSounds = options['sounds'];
|
||||
hasSounds = options['sounds'];
|
||||
if (hasSounds === undefined) {
|
||||
hasSounds = true;
|
||||
}
|
||||
}
|
||||
var rtl = !!options['rtl'];
|
||||
var horizontalLayout = options['horizontalLayout'];
|
||||
|
||||
let maxTrashcanContents = options['maxTrashcanContents'];
|
||||
if (hasTrashcan) {
|
||||
if (maxTrashcanContents === undefined) {
|
||||
maxTrashcanContents = 32;
|
||||
}
|
||||
} else {
|
||||
maxTrashcanContents = 0;
|
||||
}
|
||||
const rtl = !!options['rtl'];
|
||||
let horizontalLayout = options['horizontalLayout'];
|
||||
if (horizontalLayout === undefined) {
|
||||
horizontalLayout = false;
|
||||
}
|
||||
var toolboxAtStart = options['toolboxPosition'];
|
||||
let toolboxAtStart = options['toolboxPosition'];
|
||||
toolboxAtStart = toolboxAtStart !== 'end';
|
||||
|
||||
/** @type {!Blockly.utils.toolbox.Position} */
|
||||
var toolboxPosition;
|
||||
/** @type {!toolbox.Position} */
|
||||
let toolboxPosition;
|
||||
if (horizontalLayout) {
|
||||
toolboxPosition = toolboxAtStart ?
|
||||
Blockly.utils.toolbox.Position.TOP : Blockly.utils.toolbox.Position.BOTTOM;
|
||||
toolboxPosition =
|
||||
toolboxAtStart ? toolbox.Position.TOP : toolbox.Position.BOTTOM;
|
||||
} else {
|
||||
toolboxPosition = (toolboxAtStart == rtl) ?
|
||||
Blockly.utils.toolbox.Position.RIGHT : Blockly.utils.toolbox.Position.LEFT;
|
||||
toolboxPosition = (toolboxAtStart == rtl) ? toolbox.Position.RIGHT :
|
||||
toolbox.Position.LEFT;
|
||||
}
|
||||
|
||||
var hasCss = options['css'];
|
||||
let hasCss = options['css'];
|
||||
if (hasCss === undefined) {
|
||||
hasCss = true;
|
||||
}
|
||||
var pathToMedia = 'https://blockly-demo.appspot.com/static/media/';
|
||||
let pathToMedia = 'https://blockly-demo.appspot.com/static/media/';
|
||||
if (options['media']) {
|
||||
pathToMedia = options['media'];
|
||||
} else if (options['path']) {
|
||||
// 'path' is a deprecated option which has been replaced by 'media'.
|
||||
pathToMedia = options['path'] + 'media/';
|
||||
}
|
||||
let oneBasedIndex;
|
||||
if (options['oneBasedIndex'] === undefined) {
|
||||
var oneBasedIndex = true;
|
||||
oneBasedIndex = true;
|
||||
} else {
|
||||
var oneBasedIndex = !!options['oneBasedIndex'];
|
||||
oneBasedIndex = !!options['oneBasedIndex'];
|
||||
}
|
||||
var renderer = options['renderer'] || 'geras';
|
||||
const renderer = options['renderer'] || 'geras';
|
||||
|
||||
var plugins = options['plugins'] || {};
|
||||
const plugins = options['plugins'] || {};
|
||||
|
||||
/** @type {boolean} */
|
||||
this.RTL = rtl;
|
||||
@@ -129,8 +136,8 @@ Blockly.Options = function(options) {
|
||||
this.pathToMedia = pathToMedia;
|
||||
/** @type {boolean} */
|
||||
this.hasCategories = hasCategories;
|
||||
/** @type {!Blockly.Options.MoveOptions} */
|
||||
this.moveOptions = Blockly.Options.parseMoveOptions_(options, hasCategories);
|
||||
/** @type {!Options.MoveOptions} */
|
||||
this.moveOptions = Options.parseMoveOptions_(options, hasCategories);
|
||||
/** @deprecated January 2019 */
|
||||
this.hasScrollbars = !!this.moveOptions.scrollbars;
|
||||
/** @type {boolean} */
|
||||
@@ -143,16 +150,16 @@ Blockly.Options = function(options) {
|
||||
this.hasCss = hasCss;
|
||||
/** @type {boolean} */
|
||||
this.horizontalLayout = horizontalLayout;
|
||||
/** @type {?Blockly.utils.toolbox.ToolboxInfo} */
|
||||
/** @type {?toolbox.ToolboxInfo} */
|
||||
this.languageTree = toolboxJsonDef;
|
||||
/** @type {!Blockly.Options.GridOptions} */
|
||||
this.gridOptions = Blockly.Options.parseGridOptions_(options);
|
||||
/** @type {!Blockly.Options.ZoomOptions} */
|
||||
this.zoomOptions = Blockly.Options.parseZoomOptions_(options);
|
||||
/** @type {!Blockly.utils.toolbox.Position} */
|
||||
/** @type {!Options.GridOptions} */
|
||||
this.gridOptions = Options.parseGridOptions_(options);
|
||||
/** @type {!Options.ZoomOptions} */
|
||||
this.zoomOptions = Options.parseZoomOptions_(options);
|
||||
/** @type {!toolbox.Position} */
|
||||
this.toolboxPosition = toolboxPosition;
|
||||
/** @type {!Blockly.Theme} */
|
||||
this.theme = Blockly.Options.parseThemeOptions_(options);
|
||||
/** @type {!Theme} */
|
||||
this.theme = Options.parseThemeOptions_(options);
|
||||
/** @type {string} */
|
||||
this.renderer = renderer;
|
||||
/** @type {?Object} */
|
||||
@@ -169,7 +176,7 @@ Blockly.Options = function(options) {
|
||||
* The parent of the current workspace, or null if there is no parent
|
||||
* workspace. We can assert that this is of type WorkspaceSvg as opposed to
|
||||
* Workspace as this is only used in a rendered workspace.
|
||||
* @type {Blockly.WorkspaceSvg}
|
||||
* @type {WorkspaceSvg}
|
||||
*/
|
||||
this.parentWorkspace = options['parentWorkspace'];
|
||||
|
||||
@@ -180,14 +187,6 @@ Blockly.Options = function(options) {
|
||||
this.plugins = plugins;
|
||||
};
|
||||
|
||||
/**
|
||||
* Blockly options.
|
||||
* This interface is further described in
|
||||
* `typings/parts/blockly-interfaces.d.ts`.
|
||||
* @interface
|
||||
*/
|
||||
Blockly.BlocklyOptions = function() {};
|
||||
|
||||
/**
|
||||
* Grid Options.
|
||||
* @typedef {{
|
||||
@@ -197,17 +196,17 @@ Blockly.BlocklyOptions = function() {};
|
||||
* spacing: number
|
||||
* }}
|
||||
*/
|
||||
Blockly.Options.GridOptions;
|
||||
Options.GridOptions;
|
||||
|
||||
/**
|
||||
* Move Options.
|
||||
* @typedef {{
|
||||
* drag: boolean,
|
||||
* scrollbars: (boolean | !Blockly.Options.ScrollbarOptions),
|
||||
* scrollbars: (boolean | !Options.ScrollbarOptions),
|
||||
* wheel: boolean
|
||||
* }}
|
||||
*/
|
||||
Blockly.Options.MoveOptions;
|
||||
Options.MoveOptions;
|
||||
|
||||
/**
|
||||
* Scrollbar Options.
|
||||
@@ -216,7 +215,7 @@ Blockly.Options.MoveOptions;
|
||||
* vertical: boolean
|
||||
* }}
|
||||
*/
|
||||
Blockly.Options.ScrollbarOptions;
|
||||
Options.ScrollbarOptions;
|
||||
|
||||
/**
|
||||
* Zoom Options.
|
||||
@@ -230,7 +229,7 @@ Blockly.Options.ScrollbarOptions;
|
||||
* wheel: boolean
|
||||
* }}
|
||||
*/
|
||||
Blockly.Options.ZoomOptions;
|
||||
Options.ZoomOptions;
|
||||
|
||||
/**
|
||||
* If set, sets the translation of the workspace to match the scrollbars.
|
||||
@@ -238,25 +237,25 @@ Blockly.Options.ZoomOptions;
|
||||
* is a float between 0 and 1 specifying the degree of scrolling.
|
||||
* @return {void}
|
||||
*/
|
||||
Blockly.Options.prototype.setMetrics;
|
||||
Options.prototype.setMetrics;
|
||||
|
||||
/**
|
||||
* Return an object with the metrics required to size the workspace.
|
||||
* @return {!Blockly.utils.Metrics} Contains size and position metrics.
|
||||
* @return {!Metrics} Contains size and position metrics.
|
||||
*/
|
||||
Blockly.Options.prototype.getMetrics;
|
||||
Options.prototype.getMetrics;
|
||||
|
||||
/**
|
||||
* Parse the user-specified move options, using reasonable defaults where
|
||||
* behaviour is unspecified.
|
||||
* @param {!Object} options Dictionary of options.
|
||||
* @param {boolean} hasCategories Whether the workspace has categories or not.
|
||||
* @return {!Blockly.Options.MoveOptions} Normalized move options.
|
||||
* @return {!Options.MoveOptions} Normalized move options.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Options.parseMoveOptions_ = function(options, hasCategories) {
|
||||
var move = options['move'] || {};
|
||||
var moveOptions = {};
|
||||
Options.parseMoveOptions_ = function(options, hasCategories) {
|
||||
const move = options['move'] || {};
|
||||
const moveOptions = {};
|
||||
if (move['scrollbars'] === undefined && options['scrollbars'] === undefined) {
|
||||
moveOptions.scrollbars = hasCategories;
|
||||
} else if (typeof move['scrollbars'] == 'object') {
|
||||
@@ -268,7 +267,8 @@ Blockly.Options.parseMoveOptions_ = function(options, hasCategories) {
|
||||
// !!moveOptions.scrollbars.
|
||||
if (moveOptions.scrollbars.horizontal && moveOptions.scrollbars.vertical) {
|
||||
moveOptions.scrollbars = true;
|
||||
} else if (!moveOptions.scrollbars.horizontal &&
|
||||
} else if (
|
||||
!moveOptions.scrollbars.horizontal &&
|
||||
!moveOptions.scrollbars.vertical) {
|
||||
moveOptions.scrollbars = false;
|
||||
}
|
||||
@@ -298,12 +298,12 @@ Blockly.Options.parseMoveOptions_ = function(options, hasCategories) {
|
||||
* behaviour is unspecified. See zoom documentation:
|
||||
* https://developers.google.com/blockly/guides/configure/web/zoom
|
||||
* @param {!Object} options Dictionary of options.
|
||||
* @return {!Blockly.Options.ZoomOptions} Normalized zoom options.
|
||||
* @return {!Options.ZoomOptions} Normalized zoom options.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Options.parseZoomOptions_ = function(options) {
|
||||
var zoom = options['zoom'] || {};
|
||||
var zoomOptions = {};
|
||||
Options.parseZoomOptions_ = function(options) {
|
||||
const zoom = options['zoom'] || {};
|
||||
const zoomOptions = {};
|
||||
if (zoom['controls'] === undefined) {
|
||||
zoomOptions.controls = false;
|
||||
} else {
|
||||
@@ -347,12 +347,12 @@ Blockly.Options.parseZoomOptions_ = function(options) {
|
||||
* behaviour is unspecified. See grid documentation:
|
||||
* https://developers.google.com/blockly/guides/configure/web/grid
|
||||
* @param {!Object} options Dictionary of options.
|
||||
* @return {!Blockly.Options.GridOptions} Normalized grid options.
|
||||
* @return {!Options.GridOptions} Normalized grid options.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Options.parseGridOptions_ = function(options) {
|
||||
var grid = options['grid'] || {};
|
||||
var gridOptions = {};
|
||||
Options.parseGridOptions_ = function(options) {
|
||||
const grid = options['grid'] || {};
|
||||
const gridOptions = {};
|
||||
gridOptions.spacing = Number(grid['spacing']) || 0;
|
||||
gridOptions.colour = grid['colour'] || '#888';
|
||||
gridOptions.length =
|
||||
@@ -365,19 +365,19 @@ Blockly.Options.parseGridOptions_ = function(options) {
|
||||
* Parse the user-specified theme options, using the classic theme as a default.
|
||||
* https://developers.google.com/blockly/guides/configure/web/themes
|
||||
* @param {!Object} options Dictionary of options.
|
||||
* @return {!Blockly.Theme} A Blockly Theme.
|
||||
* @return {!Theme} A Blockly Theme.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Options.parseThemeOptions_ = function(options) {
|
||||
var theme = options['theme'] || Blockly.Themes.Classic;
|
||||
Options.parseThemeOptions_ = function(options) {
|
||||
const theme = options['theme'] || Classic;
|
||||
if (typeof theme == 'string') {
|
||||
return /** @type {!Blockly.Theme} */ (
|
||||
Blockly.registry.getObject(Blockly.registry.Type.THEME, theme));
|
||||
} else if (theme instanceof Blockly.Theme) {
|
||||
return /** @type {!Blockly.Theme} */ (theme);
|
||||
return /** @type {!Theme} */ (
|
||||
registry.getObject(registry.Type.THEME, theme));
|
||||
} else if (theme instanceof Theme) {
|
||||
return /** @type {!Theme} */ (theme);
|
||||
}
|
||||
return Blockly.Theme.defineTheme(theme.name ||
|
||||
('builtin' + Blockly.utils.IdGenerator.getNextUniqueId()), theme);
|
||||
return Theme.defineTheme(
|
||||
theme.name || ('builtin' + IdGenerator.getNextUniqueId()), theme);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -385,13 +385,13 @@ Blockly.Options.parseThemeOptions_ = function(options) {
|
||||
* @param {?Node|?string} toolboxDef DOM tree of blocks, or text representation
|
||||
* of same.
|
||||
* @return {?Node} DOM tree of blocks, or null.
|
||||
* @deprecated Use Blockly.utils.toolbox.parseToolboxTree. (2020 September 28)
|
||||
* @deprecated Use toolbox.parseToolboxTree. (2020 September 28)
|
||||
*/
|
||||
Blockly.Options.parseToolboxTree = function(toolboxDef) {
|
||||
Blockly.utils.deprecation.warn(
|
||||
'Blockly.Options.parseToolboxTree',
|
||||
'September 2020',
|
||||
'September 2021',
|
||||
'Blockly.utils.toolbox.parseToolboxTree');
|
||||
return Blockly.utils.toolbox.parseToolboxTree(toolboxDef);
|
||||
Options.parseToolboxTree = function(toolboxDef) {
|
||||
deprecation.warn(
|
||||
'Options.parseToolboxTree', 'September 2020', 'September 2021',
|
||||
'toolbox.parseToolboxTree');
|
||||
return toolbox.parseToolboxTree(toolboxDef);
|
||||
};
|
||||
|
||||
exports = Options;
|
||||
|
||||
@@ -10,171 +10,170 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.uiPosition');
|
||||
goog.module('Blockly.uiPosition');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Scrollbar');
|
||||
goog.require('Blockly.utils.Rect');
|
||||
goog.require('Blockly.utils.toolbox');
|
||||
|
||||
goog.requireType('Blockly.MetricsManager');
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const MetricsManager = goog.requireType('Blockly.MetricsManager');
|
||||
const Rect = goog.require('Blockly.utils.Rect');
|
||||
const Scrollbar = goog.require('Blockly.Scrollbar');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Size = goog.requireType('Blockly.utils.Size');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const toolbox = goog.require('Blockly.utils.toolbox');
|
||||
|
||||
|
||||
/**
|
||||
* Enum for vertical positioning.
|
||||
* @enum {number}
|
||||
* @package
|
||||
*/
|
||||
Blockly.uiPosition.verticalPosition = {
|
||||
const verticalPosition = {
|
||||
TOP: 0,
|
||||
BOTTOM: 1
|
||||
};
|
||||
/** @package */
|
||||
exports.verticalPosition = verticalPosition;
|
||||
|
||||
/**
|
||||
* Enum for horizontal positioning.
|
||||
* @enum {number}
|
||||
* @package
|
||||
*/
|
||||
Blockly.uiPosition.horizontalPosition = {
|
||||
const horizontalPosition = {
|
||||
LEFT: 0,
|
||||
RIGHT: 1
|
||||
};
|
||||
/** @package */
|
||||
exports.horizontalPosition = horizontalPosition;
|
||||
|
||||
/**
|
||||
* An object defining a horizontal and vertical positioning.
|
||||
* @typedef {{
|
||||
* horizontal: !Blockly.uiPosition.horizontalPosition,
|
||||
* vertical: !Blockly.uiPosition.verticalPosition
|
||||
* horizontal: !horizontalPosition,
|
||||
* vertical: !verticalPosition
|
||||
* }}
|
||||
* @package
|
||||
*/
|
||||
Blockly.uiPosition.Position;
|
||||
let Position;
|
||||
/** @package */
|
||||
exports.Position = Position;
|
||||
|
||||
/**
|
||||
* Enum for bump rules to use for dealing with collisions.
|
||||
* @enum {number}
|
||||
* @package
|
||||
*/
|
||||
Blockly.uiPosition.bumpDirection = {
|
||||
const bumpDirection = {
|
||||
UP: 0,
|
||||
DOWN: 1
|
||||
};
|
||||
/** @package */
|
||||
exports.bumpDirection = bumpDirection;
|
||||
|
||||
/**
|
||||
* Returns a rectangle representing reasonable position for where to place a UI
|
||||
* element of the specified size given the restraints and locations of the
|
||||
* scrollbars. This method does not take into account any already placed UI
|
||||
* elements.
|
||||
* @param {!Blockly.uiPosition.Position} position The starting
|
||||
* @param {!Position} position The starting
|
||||
* horizontal and vertical position.
|
||||
* @param {!Blockly.utils.Size} size the size of the UI element to get a start
|
||||
* @param {!Size} size the size of the UI element to get a start
|
||||
* position for.
|
||||
* @param {number} horizontalPadding The horizontal padding to use.
|
||||
* @param {number} verticalPadding The vertical padding to use.
|
||||
* @param {!Blockly.MetricsManager.UiMetrics} metrics The workspace UI metrics.
|
||||
* @param {!Blockly.WorkspaceSvg} workspace The workspace.
|
||||
* @return {!Blockly.utils.Rect} The suggested start position.
|
||||
* @package
|
||||
* @param {!MetricsManager.UiMetrics} metrics The workspace UI metrics.
|
||||
* @param {!WorkspaceSvg} workspace The workspace.
|
||||
* @return {!Rect} The suggested start position.
|
||||
*/
|
||||
Blockly.uiPosition.getStartPositionRect = function(
|
||||
position, size, horizontalPadding,
|
||||
verticalPadding, metrics, workspace) {
|
||||
const getStartPositionRect = function(
|
||||
position, size, horizontalPadding, verticalPadding, metrics, workspace) {
|
||||
// Horizontal positioning.
|
||||
var left = 0;
|
||||
var hasVerticalScrollbar =
|
||||
let left = 0;
|
||||
const hasVerticalScrollbar =
|
||||
workspace.scrollbar && workspace.scrollbar.canScrollVertically();
|
||||
if (position.horizontal ===
|
||||
Blockly.uiPosition.horizontalPosition.LEFT) {
|
||||
if (position.horizontal === horizontalPosition.LEFT) {
|
||||
left = metrics.absoluteMetrics.left + horizontalPadding;
|
||||
if (hasVerticalScrollbar && workspace.RTL) {
|
||||
left += Blockly.Scrollbar.scrollbarThickness;
|
||||
left += Scrollbar.scrollbarThickness;
|
||||
}
|
||||
} else { // position.horizontal == horizontalPosition.RIGHT
|
||||
left = metrics.absoluteMetrics.left + metrics.viewMetrics.width -
|
||||
size.width - horizontalPadding;
|
||||
if (hasVerticalScrollbar && !workspace.RTL) {
|
||||
left -= Blockly.Scrollbar.scrollbarThickness;
|
||||
left -= Scrollbar.scrollbarThickness;
|
||||
}
|
||||
}
|
||||
// Vertical positioning.
|
||||
var top = 0;
|
||||
if (position.vertical ===
|
||||
Blockly.uiPosition.verticalPosition.TOP) {
|
||||
let top = 0;
|
||||
if (position.vertical === verticalPosition.TOP) {
|
||||
top = metrics.absoluteMetrics.top + verticalPadding;
|
||||
} else { // position.vertical == verticalPosition.BOTTOM
|
||||
top = metrics.absoluteMetrics.top + metrics.viewMetrics.height -
|
||||
size.height - verticalPadding;
|
||||
if (workspace.scrollbar && workspace.scrollbar.canScrollHorizontally()) {
|
||||
// The scrollbars are always positioned on the bottom if they exist.
|
||||
top -= Blockly.Scrollbar.scrollbarThickness;
|
||||
top -= Scrollbar.scrollbarThickness;
|
||||
}
|
||||
}
|
||||
return new Blockly.utils.Rect(
|
||||
top, top + size.height, left, left + size.width);
|
||||
return new Rect(top, top + size.height, left, left + size.width);
|
||||
};
|
||||
/** @package */
|
||||
exports.getStartPositionRect = getStartPositionRect;
|
||||
|
||||
/**
|
||||
* Returns a corner position that is on the opposite side of the workspace from
|
||||
* the toolbox.
|
||||
* If in horizontal orientation, defaults to the bottom corner. If in vertical
|
||||
* orientation, defaults to the right corner.
|
||||
* @param {!Blockly.WorkspaceSvg} workspace The workspace.
|
||||
* @param {!Blockly.MetricsManager.UiMetrics} metrics The workspace metrics.
|
||||
* @return {!Blockly.uiPosition.Position} The suggested corner position.
|
||||
* @package
|
||||
* @param {!WorkspaceSvg} workspace The workspace.
|
||||
* @param {!MetricsManager.UiMetrics} metrics The workspace metrics.
|
||||
* @return {!Position} The suggested corner position.
|
||||
*/
|
||||
Blockly.uiPosition.getCornerOppositeToolbox = function(workspace, metrics) {
|
||||
var leftCorner =
|
||||
metrics.toolboxMetrics.position !== Blockly.utils.toolbox.Position.LEFT &&
|
||||
const getCornerOppositeToolbox = function(workspace, metrics) {
|
||||
const leftCorner =
|
||||
metrics.toolboxMetrics.position !== toolbox.Position.LEFT &&
|
||||
(!workspace.horizontalLayout || workspace.RTL);
|
||||
var topCorner =
|
||||
metrics.toolboxMetrics.position === Blockly.utils.toolbox.Position.BOTTOM;
|
||||
var horizontalPosition = leftCorner ?
|
||||
Blockly.uiPosition.horizontalPosition.LEFT :
|
||||
Blockly.uiPosition.horizontalPosition.RIGHT;
|
||||
var verticalPosition = topCorner ?
|
||||
Blockly.uiPosition.verticalPosition.TOP :
|
||||
Blockly.uiPosition.verticalPosition.BOTTOM;
|
||||
return {
|
||||
horizontal: horizontalPosition,
|
||||
vertical: verticalPosition
|
||||
};
|
||||
const topCorner = metrics.toolboxMetrics.position === toolbox.Position.BOTTOM;
|
||||
const hPosition =
|
||||
leftCorner ? horizontalPosition.LEFT : horizontalPosition.RIGHT;
|
||||
const vPosition = topCorner ? verticalPosition.TOP : verticalPosition.BOTTOM;
|
||||
return {horizontal: hPosition, vertical: vPosition};
|
||||
};
|
||||
/** @package */
|
||||
exports.getCornerOppositeToolbox = getCornerOppositeToolbox;
|
||||
|
||||
/**
|
||||
* Returns a position Rect based on a starting position that is bumped
|
||||
* so that it doesn't intersect with any of the provided savedPositions. This
|
||||
* method does not check that the bumped position is still within bounds.
|
||||
* @param {!Blockly.utils.Rect} startRect The starting position to use.
|
||||
* @param {!Rect} startRect The starting position to use.
|
||||
* @param {number} margin The margin to use between elements when bumping.
|
||||
* @param {!Blockly.uiPosition.bumpDirection} bumpDirection The direction
|
||||
* to bump if there is a collision with an existing UI element.
|
||||
* @param {!Array<!Blockly.utils.Rect>} savedPositions List of rectangles that
|
||||
* @param {!bumpDirection} bumpDir The direction to bump if there is a collision
|
||||
* with an existing UI element.
|
||||
* @param {!Array<!Rect>} savedPositions List of rectangles that
|
||||
* represent the positions of UI elements already placed.
|
||||
* @return {!Blockly.utils.Rect} The suggested position rectangle.
|
||||
* @package
|
||||
* @return {!Rect} The suggested position rectangle.
|
||||
*/
|
||||
Blockly.uiPosition.bumpPositionRect = function(
|
||||
startRect, margin, bumpDirection, savedPositions) {
|
||||
var top = startRect.top;
|
||||
var left = startRect.left;
|
||||
var width = startRect.right - startRect.left;
|
||||
var height = startRect.bottom - startRect.top;
|
||||
const bumpPositionRect = function(startRect, margin, bumpDir, savedPositions) {
|
||||
let top = startRect.top;
|
||||
const left = startRect.left;
|
||||
const width = startRect.right - startRect.left;
|
||||
const height = startRect.bottom - startRect.top;
|
||||
|
||||
// Check for collision and bump if needed.
|
||||
var boundingRect = startRect;
|
||||
for (var i = 0, otherEl; (otherEl = savedPositions[i]); i++) {
|
||||
let boundingRect = startRect;
|
||||
for (let i = 0; i < savedPositions.length; i++) {
|
||||
const otherEl = savedPositions[i];
|
||||
if (boundingRect.intersects(otherEl)) {
|
||||
if (bumpDirection === Blockly.uiPosition.bumpDirection.UP) {
|
||||
if (bumpDir === bumpDirection.UP) {
|
||||
top = otherEl.top - height - margin;
|
||||
} else { // bumpDirection == bumpDirection.DOWN
|
||||
} else { // bumpDir == bumpDirection.DOWN
|
||||
top = otherEl.bottom + margin;
|
||||
}
|
||||
// Recheck other savedPositions
|
||||
boundingRect = new Blockly.utils.Rect(
|
||||
top, top + height, left, left + width);
|
||||
boundingRect = new Rect(top, top + height, left, left + width);
|
||||
i = -1;
|
||||
}
|
||||
}
|
||||
return boundingRect;
|
||||
};
|
||||
/** @package */
|
||||
exports.bumpPositionRect = bumpPositionRect;
|
||||
|
||||
@@ -14,38 +14,35 @@
|
||||
* @name Blockly.Procedures
|
||||
* @namespace
|
||||
*/
|
||||
goog.provide('Blockly.Procedures');
|
||||
goog.module('Blockly.Procedures');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly.Events');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Abstract = goog.requireType('Blockly.Events.Abstract');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
const Blocks = goog.require('Blockly.Blocks');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Field = goog.requireType('Blockly.Field');
|
||||
const Msg = goog.require('Blockly.Msg');
|
||||
const Names = goog.require('Blockly.Names');
|
||||
const Variables = goog.require('Blockly.Variables');
|
||||
const Workspace = goog.require('Blockly.Workspace');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const Xml = goog.require('Blockly.Xml');
|
||||
const utilsXml = goog.require('Blockly.utils.xml');
|
||||
/** @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');
|
||||
goog.require('Blockly.Workspace');
|
||||
goog.require('Blockly.Xml');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
goog.requireType('Blockly.Events.Abstract');
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
|
||||
|
||||
/**
|
||||
* Constant to separate procedure names from variables and generated functions
|
||||
* when running generators.
|
||||
* @deprecated Use Blockly.internalConstants.PROCEDURE_CATEGORY_NAME
|
||||
*/
|
||||
Blockly.Procedures.NAME_TYPE =
|
||||
Blockly.internalConstants.PROCEDURE_CATEGORY_NAME;
|
||||
|
||||
/**
|
||||
* The default argument for a procedures_mutatorarg block.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Procedures.DEFAULT_ARG = 'x';
|
||||
const DEFAULT_ARG = 'x';
|
||||
exports.DEFAULT_ARG = DEFAULT_ARG;
|
||||
|
||||
/**
|
||||
* Procedure block type.
|
||||
@@ -55,28 +52,32 @@ Blockly.Procedures.DEFAULT_ARG = 'x';
|
||||
* getProcedureDef: function():!Array
|
||||
* }}
|
||||
*/
|
||||
Blockly.Procedures.ProcedureBlock;
|
||||
let ProcedureBlock;
|
||||
exports.ProcedureBlock = ProcedureBlock;
|
||||
|
||||
/**
|
||||
* Find all user-created procedure definitions in a workspace.
|
||||
* @param {!Blockly.Workspace} root Root workspace.
|
||||
* @param {!Workspace} root Root workspace.
|
||||
* @return {!Array<!Array<!Array>>} Pair of arrays, the
|
||||
* first contains procedures without return variables, the second with.
|
||||
* Each procedure is defined by a three-element list of name, parameter
|
||||
* list, and return value boolean.
|
||||
*/
|
||||
Blockly.Procedures.allProcedures = function(root) {
|
||||
var proceduresNoReturn = root.getBlocksByType('procedures_defnoreturn', false)
|
||||
.map(function(block) {
|
||||
return /** @type {!Blockly.Procedures.ProcedureBlock} */ (block).getProcedureDef();
|
||||
const allProcedures = function(root) {
|
||||
const proceduresNoReturn =
|
||||
root.getBlocksByType('procedures_defnoreturn', false)
|
||||
.map(function(block) {
|
||||
return /** @type {!ProcedureBlock} */ (block).getProcedureDef();
|
||||
});
|
||||
const proceduresReturn =
|
||||
root.getBlocksByType('procedures_defreturn', false).map(function(block) {
|
||||
return /** @type {!ProcedureBlock} */ (block).getProcedureDef();
|
||||
});
|
||||
var proceduresReturn = root.getBlocksByType('procedures_defreturn', false).map(function(block) {
|
||||
return /** @type {!Blockly.Procedures.ProcedureBlock} */ (block).getProcedureDef();
|
||||
});
|
||||
proceduresNoReturn.sort(Blockly.Procedures.procTupleComparator_);
|
||||
proceduresReturn.sort(Blockly.Procedures.procTupleComparator_);
|
||||
proceduresNoReturn.sort(procTupleComparator);
|
||||
proceduresReturn.sort(procTupleComparator);
|
||||
return [proceduresNoReturn, proceduresReturn];
|
||||
};
|
||||
exports.allProcedures = allProcedures;
|
||||
|
||||
/**
|
||||
* Comparison function for case-insensitive sorting of the first element of
|
||||
@@ -84,9 +85,8 @@ Blockly.Procedures.allProcedures = function(root) {
|
||||
* @param {!Array} ta First tuple.
|
||||
* @param {!Array} tb Second tuple.
|
||||
* @return {number} -1, 0, or 1 to signify greater than, equality, or less than.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Procedures.procTupleComparator_ = function(ta, tb) {
|
||||
const procTupleComparator = function(ta, tb) {
|
||||
return ta[0].localeCompare(tb[0], undefined, {sensitivity: 'base'});
|
||||
};
|
||||
|
||||
@@ -95,18 +95,18 @@ Blockly.Procedures.procTupleComparator_ = function(ta, tb) {
|
||||
* Take the proposed procedure name, and return a legal name i.e. one that
|
||||
* is not empty and doesn't collide with other procedures.
|
||||
* @param {string} name Proposed procedure name.
|
||||
* @param {!Blockly.Block} block Block to disambiguate.
|
||||
* @param {!Block} block Block to disambiguate.
|
||||
* @return {string} Non-colliding name.
|
||||
*/
|
||||
Blockly.Procedures.findLegalName = function(name, block) {
|
||||
const findLegalName = function(name, block) {
|
||||
if (block.isInFlyout) {
|
||||
// Flyouts can have multiple procedures called 'do something'.
|
||||
return name;
|
||||
}
|
||||
name = name || Blockly.Msg['UNNAMED_KEY'] || 'unnamed';
|
||||
while (!Blockly.Procedures.isLegalName_(name, block.workspace, block)) {
|
||||
name = name || Msg['UNNAMED_KEY'] || 'unnamed';
|
||||
while (!isLegalName(name, block.workspace, block)) {
|
||||
// Collision with another procedure.
|
||||
var r = name.match(/^(.*?)(\d+)$/);
|
||||
const r = name.match(/^(.*?)(\d+)$/);
|
||||
if (!r) {
|
||||
name += '2';
|
||||
} else {
|
||||
@@ -115,68 +115,68 @@ Blockly.Procedures.findLegalName = function(name, block) {
|
||||
}
|
||||
return name;
|
||||
};
|
||||
exports.findLegalName = findLegalName;
|
||||
|
||||
/**
|
||||
* Does this procedure have a legal name? Illegal names include names of
|
||||
* procedures already defined.
|
||||
* @param {string} name The questionable name.
|
||||
* @param {!Blockly.Workspace} workspace The workspace to scan for collisions.
|
||||
* @param {Blockly.Block=} opt_exclude Optional block to exclude from
|
||||
* @param {!Workspace} workspace The workspace to scan for collisions.
|
||||
* @param {Block=} opt_exclude Optional block to exclude from
|
||||
* comparisons (one doesn't want to collide with oneself).
|
||||
* @return {boolean} True if the name is legal.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Procedures.isLegalName_ = function(name, workspace, opt_exclude) {
|
||||
return !Blockly.Procedures.isNameUsed(name, workspace, opt_exclude);
|
||||
const isLegalName = function(name, workspace, opt_exclude) {
|
||||
return !isNameUsed(name, workspace, opt_exclude);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return if the given name is already a procedure name.
|
||||
* @param {string} name The questionable name.
|
||||
* @param {!Blockly.Workspace} workspace The workspace to scan for collisions.
|
||||
* @param {Blockly.Block=} opt_exclude Optional block to exclude from
|
||||
* @param {!Workspace} workspace The workspace to scan for collisions.
|
||||
* @param {Block=} opt_exclude Optional block to exclude from
|
||||
* comparisons (one doesn't want to collide with oneself).
|
||||
* @return {boolean} True if the name is used, otherwise return false.
|
||||
*/
|
||||
Blockly.Procedures.isNameUsed = function(name, workspace, opt_exclude) {
|
||||
var blocks = workspace.getAllBlocks(false);
|
||||
const isNameUsed = function(name, workspace, opt_exclude) {
|
||||
const blocks = workspace.getAllBlocks(false);
|
||||
// Iterate through every block and check the name.
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
for (let i = 0; i < blocks.length; i++) {
|
||||
if (blocks[i] == opt_exclude) {
|
||||
continue;
|
||||
}
|
||||
if (blocks[i].getProcedureDef) {
|
||||
var procedureBlock = /** @type {!Blockly.Procedures.ProcedureBlock} */ (
|
||||
blocks[i]);
|
||||
var procName = procedureBlock.getProcedureDef();
|
||||
if (Blockly.Names.equals(procName[0], name)) {
|
||||
const procedureBlock = /** @type {!ProcedureBlock} */ (blocks[i]);
|
||||
const procName = procedureBlock.getProcedureDef();
|
||||
if (Names.equals(procName[0], name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
exports.isNameUsed = isNameUsed;
|
||||
|
||||
/**
|
||||
* Rename a procedure. Called by the editable field.
|
||||
* @param {string} name The proposed new name.
|
||||
* @return {string} The accepted name.
|
||||
* @this {Blockly.Field}
|
||||
* @this {Field}
|
||||
*/
|
||||
Blockly.Procedures.rename = function(name) {
|
||||
const rename = function(name) {
|
||||
// Strip leading and trailing whitespace. Beyond this, all names are legal.
|
||||
name = name.trim();
|
||||
|
||||
var legalName = Blockly.Procedures.findLegalName(name,
|
||||
/** @type {!Blockly.Block} */ (this.getSourceBlock()));
|
||||
var oldName = this.getValue();
|
||||
const legalName = findLegalName(
|
||||
name,
|
||||
/** @type {!Block} */ (this.getSourceBlock()));
|
||||
const oldName = this.getValue();
|
||||
if (oldName != name && oldName != legalName) {
|
||||
// Rename any callers.
|
||||
var blocks = this.getSourceBlock().workspace.getAllBlocks(false);
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
const blocks = this.getSourceBlock().workspace.getAllBlocks(false);
|
||||
for (let i = 0; i < blocks.length; i++) {
|
||||
if (blocks[i].renameProcedure) {
|
||||
var procedureBlock = /** @type {!Blockly.Procedures.ProcedureBlock} */ (
|
||||
blocks[i]);
|
||||
const procedureBlock = /** @type {!ProcedureBlock} */ (blocks[i]);
|
||||
procedureBlock.renameProcedure(
|
||||
/** @type {string} */ (oldName), legalName);
|
||||
}
|
||||
@@ -184,45 +184,46 @@ Blockly.Procedures.rename = function(name) {
|
||||
}
|
||||
return legalName;
|
||||
};
|
||||
exports.rename = rename;
|
||||
|
||||
/**
|
||||
* Construct the blocks required by the flyout for the procedure category.
|
||||
* @param {!Blockly.Workspace} workspace The workspace containing procedures.
|
||||
* @param {!Workspace} workspace The workspace containing procedures.
|
||||
* @return {!Array<!Element>} Array of XML block elements.
|
||||
*/
|
||||
Blockly.Procedures.flyoutCategory = function(workspace) {
|
||||
var xmlList = [];
|
||||
if (Blockly.Blocks['procedures_defnoreturn']) {
|
||||
const flyoutCategory = function(workspace) {
|
||||
const xmlList = [];
|
||||
if (Blocks['procedures_defnoreturn']) {
|
||||
// <block type="procedures_defnoreturn" gap="16">
|
||||
// <field name="NAME">do something</field>
|
||||
// </block>
|
||||
var block = Blockly.utils.xml.createElement('block');
|
||||
const block = utilsXml.createElement('block');
|
||||
block.setAttribute('type', 'procedures_defnoreturn');
|
||||
block.setAttribute('gap', 16);
|
||||
var nameField = Blockly.utils.xml.createElement('field');
|
||||
const nameField = utilsXml.createElement('field');
|
||||
nameField.setAttribute('name', 'NAME');
|
||||
nameField.appendChild(Blockly.utils.xml.createTextNode(
|
||||
Blockly.Msg['PROCEDURES_DEFNORETURN_PROCEDURE']));
|
||||
nameField.appendChild(
|
||||
utilsXml.createTextNode(Msg['PROCEDURES_DEFNORETURN_PROCEDURE']));
|
||||
block.appendChild(nameField);
|
||||
xmlList.push(block);
|
||||
}
|
||||
if (Blockly.Blocks['procedures_defreturn']) {
|
||||
if (Blocks['procedures_defreturn']) {
|
||||
// <block type="procedures_defreturn" gap="16">
|
||||
// <field name="NAME">do something</field>
|
||||
// </block>
|
||||
var block = Blockly.utils.xml.createElement('block');
|
||||
const block = utilsXml.createElement('block');
|
||||
block.setAttribute('type', 'procedures_defreturn');
|
||||
block.setAttribute('gap', 16);
|
||||
var nameField = Blockly.utils.xml.createElement('field');
|
||||
const nameField = utilsXml.createElement('field');
|
||||
nameField.setAttribute('name', 'NAME');
|
||||
nameField.appendChild(Blockly.utils.xml.createTextNode(
|
||||
Blockly.Msg['PROCEDURES_DEFRETURN_PROCEDURE']));
|
||||
nameField.appendChild(
|
||||
utilsXml.createTextNode(Msg['PROCEDURES_DEFRETURN_PROCEDURE']));
|
||||
block.appendChild(nameField);
|
||||
xmlList.push(block);
|
||||
}
|
||||
if (Blockly.Blocks['procedures_ifreturn']) {
|
||||
if (Blocks['procedures_ifreturn']) {
|
||||
// <block type="procedures_ifreturn" gap="16"></block>
|
||||
var block = Blockly.utils.xml.createElement('block');
|
||||
const block = utilsXml.createElement('block');
|
||||
block.setAttribute('type', 'procedures_ifreturn');
|
||||
block.setAttribute('gap', 16);
|
||||
xmlList.push(block);
|
||||
@@ -233,22 +234,22 @@ Blockly.Procedures.flyoutCategory = function(workspace) {
|
||||
}
|
||||
|
||||
function populateProcedures(procedureList, templateName) {
|
||||
for (var i = 0; i < procedureList.length; i++) {
|
||||
var name = procedureList[i][0];
|
||||
var args = procedureList[i][1];
|
||||
for (let i = 0; i < procedureList.length; i++) {
|
||||
const name = procedureList[i][0];
|
||||
const args = procedureList[i][1];
|
||||
// <block type="procedures_callnoreturn" gap="16">
|
||||
// <mutation name="do something">
|
||||
// <arg name="x"></arg>
|
||||
// </mutation>
|
||||
// </block>
|
||||
var block = Blockly.utils.xml.createElement('block');
|
||||
const block = utilsXml.createElement('block');
|
||||
block.setAttribute('type', templateName);
|
||||
block.setAttribute('gap', 16);
|
||||
var mutation = Blockly.utils.xml.createElement('mutation');
|
||||
const mutation = utilsXml.createElement('mutation');
|
||||
mutation.setAttribute('name', name);
|
||||
block.appendChild(mutation);
|
||||
for (var j = 0; j < args.length; j++) {
|
||||
var arg = Blockly.utils.xml.createElement('arg');
|
||||
for (let j = 0; j < args.length; j++) {
|
||||
const arg = utilsXml.createElement('arg');
|
||||
arg.setAttribute('name', args[j]);
|
||||
mutation.appendChild(arg);
|
||||
}
|
||||
@@ -256,157 +257,155 @@ Blockly.Procedures.flyoutCategory = function(workspace) {
|
||||
}
|
||||
}
|
||||
|
||||
var tuple = Blockly.Procedures.allProcedures(workspace);
|
||||
const tuple = allProcedures(workspace);
|
||||
populateProcedures(tuple[0], 'procedures_callnoreturn');
|
||||
populateProcedures(tuple[1], 'procedures_callreturn');
|
||||
return xmlList;
|
||||
};
|
||||
exports.flyoutCategory = flyoutCategory;
|
||||
|
||||
/**
|
||||
* Updates the procedure mutator's flyout so that the arg block is not a
|
||||
* duplicate of another arg.
|
||||
* @param {!Blockly.Workspace} workspace The procedure mutator's workspace. This
|
||||
* @param {!Workspace} workspace The procedure mutator's workspace. This
|
||||
* workspace's flyout is what is being updated.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Procedures.updateMutatorFlyout_ = function(workspace) {
|
||||
var usedNames = [];
|
||||
var blocks = workspace.getBlocksByType('procedures_mutatorarg', false);
|
||||
for (var i = 0, block; (block = blocks[i]); i++) {
|
||||
const updateMutatorFlyout = function(workspace) {
|
||||
const usedNames = [];
|
||||
const blocks = workspace.getBlocksByType('procedures_mutatorarg', false);
|
||||
for (let i = 0, block; (block = blocks[i]); i++) {
|
||||
usedNames.push(block.getFieldValue('NAME'));
|
||||
}
|
||||
|
||||
var xml = Blockly.utils.xml.createElement('xml');
|
||||
var argBlock = Blockly.utils.xml.createElement('block');
|
||||
const xmlElement = utilsXml.createElement('xml');
|
||||
const argBlock = utilsXml.createElement('block');
|
||||
argBlock.setAttribute('type', 'procedures_mutatorarg');
|
||||
var nameField = Blockly.utils.xml.createElement('field');
|
||||
const nameField = utilsXml.createElement('field');
|
||||
nameField.setAttribute('name', 'NAME');
|
||||
var argValue = Blockly.Variables.generateUniqueNameFromOptions(
|
||||
Blockly.Procedures.DEFAULT_ARG, usedNames);
|
||||
var fieldContent = Blockly.utils.xml.createTextNode(argValue);
|
||||
const argValue =
|
||||
Variables.generateUniqueNameFromOptions(DEFAULT_ARG, usedNames);
|
||||
const fieldContent = utilsXml.createTextNode(argValue);
|
||||
|
||||
nameField.appendChild(fieldContent);
|
||||
argBlock.appendChild(nameField);
|
||||
xml.appendChild(argBlock);
|
||||
xmlElement.appendChild(argBlock);
|
||||
|
||||
workspace.updateToolbox(xml);
|
||||
workspace.updateToolbox(xmlElement);
|
||||
};
|
||||
|
||||
/**
|
||||
* Listens for when a procedure mutator is opened. Then it triggers a flyout
|
||||
* update and adds a mutator change listener to the mutator workspace.
|
||||
* @param {!Blockly.Events.Abstract} e The event that triggered this listener.
|
||||
* @package
|
||||
* @param {!Abstract} e The event that triggered this listener.
|
||||
*/
|
||||
Blockly.Procedures.mutatorOpenListener = function(e) {
|
||||
if (!(e.type == Blockly.Events.BUBBLE_OPEN && e.bubbleType === 'mutator' &&
|
||||
e.isOpen)) {
|
||||
const mutatorOpenListener = function(e) {
|
||||
if (!(e.type == Events.BUBBLE_OPEN && e.bubbleType === 'mutator' &&
|
||||
e.isOpen)) {
|
||||
return;
|
||||
}
|
||||
var workspaceId = /** @type {string} */ (e.workspaceId);
|
||||
var block = Blockly.Workspace.getById(workspaceId)
|
||||
.getBlockById(e.blockId);
|
||||
var type = block.type;
|
||||
const workspaceId = /** @type {string} */ (e.workspaceId);
|
||||
const block = Workspace.getById(workspaceId).getBlockById(e.blockId);
|
||||
const type = block.type;
|
||||
if (type != 'procedures_defnoreturn' && type != 'procedures_defreturn') {
|
||||
return;
|
||||
}
|
||||
var workspace = block.mutator.getWorkspace();
|
||||
Blockly.Procedures.updateMutatorFlyout_(workspace);
|
||||
workspace.addChangeListener(Blockly.Procedures.mutatorChangeListener_);
|
||||
const workspace = block.mutator.getWorkspace();
|
||||
updateMutatorFlyout(workspace);
|
||||
workspace.addChangeListener(mutatorChangeListener);
|
||||
};
|
||||
/** @package */
|
||||
exports.mutatorOpenListener = mutatorOpenListener;
|
||||
|
||||
/**
|
||||
* Listens for changes in a procedure mutator and triggers flyout updates when
|
||||
* necessary.
|
||||
* @param {!Blockly.Events.Abstract} e The event that triggered this listener.
|
||||
* @private
|
||||
* @param {!Abstract} e The event that triggered this listener.
|
||||
*/
|
||||
Blockly.Procedures.mutatorChangeListener_ = function(e) {
|
||||
if (e.type != Blockly.Events.BLOCK_CREATE &&
|
||||
e.type != Blockly.Events.BLOCK_DELETE &&
|
||||
e.type != Blockly.Events.BLOCK_CHANGE) {
|
||||
const mutatorChangeListener = function(e) {
|
||||
if (e.type != Events.BLOCK_CREATE && e.type != Events.BLOCK_DELETE &&
|
||||
e.type != Events.BLOCK_CHANGE) {
|
||||
return;
|
||||
}
|
||||
var workspaceId = /** @type {string} */ (e.workspaceId);
|
||||
var workspace = /** @type {!Blockly.WorkspaceSvg} */
|
||||
(Blockly.Workspace.getById(workspaceId));
|
||||
Blockly.Procedures.updateMutatorFlyout_(workspace);
|
||||
const workspaceId = /** @type {string} */ (e.workspaceId);
|
||||
const workspace = /** @type {!WorkspaceSvg} */
|
||||
(Workspace.getById(workspaceId));
|
||||
updateMutatorFlyout(workspace);
|
||||
};
|
||||
|
||||
/**
|
||||
* Find all the callers of a named procedure.
|
||||
* @param {string} name Name of procedure.
|
||||
* @param {!Blockly.Workspace} workspace The workspace to find callers in.
|
||||
* @return {!Array<!Blockly.Block>} Array of caller blocks.
|
||||
* @param {!Workspace} workspace The workspace to find callers in.
|
||||
* @return {!Array<!Block>} Array of caller blocks.
|
||||
*/
|
||||
Blockly.Procedures.getCallers = function(name, workspace) {
|
||||
var callers = [];
|
||||
var blocks = workspace.getAllBlocks(false);
|
||||
const getCallers = function(name, workspace) {
|
||||
const callers = [];
|
||||
const blocks = workspace.getAllBlocks(false);
|
||||
// Iterate through every block and check the name.
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
for (let i = 0; i < blocks.length; i++) {
|
||||
if (blocks[i].getProcedureCall) {
|
||||
var procedureBlock = /** @type {!Blockly.Procedures.ProcedureBlock} */ (
|
||||
blocks[i]);
|
||||
var procName = procedureBlock.getProcedureCall();
|
||||
const procedureBlock = /** @type {!ProcedureBlock} */ (blocks[i]);
|
||||
const procName = procedureBlock.getProcedureCall();
|
||||
// Procedure name may be null if the block is only half-built.
|
||||
if (procName && Blockly.Names.equals(procName, name)) {
|
||||
if (procName && Names.equals(procName, name)) {
|
||||
callers.push(blocks[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return callers;
|
||||
};
|
||||
exports.getCallers = getCallers;
|
||||
|
||||
/**
|
||||
* When a procedure definition changes its parameters, find and edit all its
|
||||
* callers.
|
||||
* @param {!Blockly.Block} defBlock Procedure definition block.
|
||||
* @param {!Block} defBlock Procedure definition block.
|
||||
*/
|
||||
Blockly.Procedures.mutateCallers = function(defBlock) {
|
||||
var oldRecordUndo = Blockly.Events.recordUndo;
|
||||
var procedureBlock = /** @type {!Blockly.Procedures.ProcedureBlock} */ (
|
||||
defBlock);
|
||||
var name = procedureBlock.getProcedureDef()[0];
|
||||
var xmlElement = defBlock.mutationToDom(true);
|
||||
var callers = Blockly.Procedures.getCallers(name, defBlock.workspace);
|
||||
for (var i = 0, caller; (caller = callers[i]); i++) {
|
||||
var oldMutationDom = caller.mutationToDom();
|
||||
var oldMutation = oldMutationDom && Blockly.Xml.domToText(oldMutationDom);
|
||||
const mutateCallers = function(defBlock) {
|
||||
const oldRecordUndo = Events.recordUndo;
|
||||
const procedureBlock = /** @type {!ProcedureBlock} */ (defBlock);
|
||||
const name = procedureBlock.getProcedureDef()[0];
|
||||
const xmlElement = defBlock.mutationToDom(true);
|
||||
const callers = getCallers(name, defBlock.workspace);
|
||||
for (let i = 0, caller; (caller = callers[i]); i++) {
|
||||
const oldMutationDom = caller.mutationToDom();
|
||||
const oldMutation = oldMutationDom && Xml.domToText(oldMutationDom);
|
||||
caller.domToMutation(xmlElement);
|
||||
var newMutationDom = caller.mutationToDom();
|
||||
var newMutation = newMutationDom && Blockly.Xml.domToText(newMutationDom);
|
||||
const newMutationDom = caller.mutationToDom();
|
||||
const newMutation = newMutationDom && Xml.domToText(newMutationDom);
|
||||
if (oldMutation != newMutation) {
|
||||
// Fire a mutation on every caller block. But don't record this as an
|
||||
// undo action since it is deterministically tied to the procedure's
|
||||
// definition mutation.
|
||||
Blockly.Events.recordUndo = false;
|
||||
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))(
|
||||
Events.recordUndo = false;
|
||||
Events.fire(new (Events.get(Events.BLOCK_CHANGE))(
|
||||
caller, 'mutation', null, oldMutation, newMutation));
|
||||
Blockly.Events.recordUndo = oldRecordUndo;
|
||||
Events.recordUndo = oldRecordUndo;
|
||||
}
|
||||
}
|
||||
};
|
||||
exports.mutateCallers = mutateCallers;
|
||||
|
||||
/**
|
||||
* Find the definition block for the named procedure.
|
||||
* @param {string} name Name of procedure.
|
||||
* @param {!Blockly.Workspace} workspace The workspace to search.
|
||||
* @return {?Blockly.Block} The procedure definition block, or null not found.
|
||||
* @param {!Workspace} workspace The workspace to search.
|
||||
* @return {?Block} The procedure definition block, or null not found.
|
||||
*/
|
||||
Blockly.Procedures.getDefinition = function(name, workspace) {
|
||||
const getDefinition = function(name, workspace) {
|
||||
// Do not assume procedure is a top block. Some languages allow nested
|
||||
// procedures. Also do not assume it is one of the built-in blocks. Only
|
||||
// rely on getProcedureDef.
|
||||
var blocks = workspace.getAllBlocks(false);
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
const blocks = workspace.getAllBlocks(false);
|
||||
for (let i = 0; i < blocks.length; i++) {
|
||||
if (blocks[i].getProcedureDef) {
|
||||
var procedureBlock = /** @type {!Blockly.Procedures.ProcedureBlock} */ (
|
||||
blocks[i]);
|
||||
var tuple = procedureBlock.getProcedureDef();
|
||||
if (tuple && Blockly.Names.equals(tuple[0], name)) {
|
||||
const procedureBlock = /** @type {!ProcedureBlock} */ (blocks[i]);
|
||||
const tuple = procedureBlock.getProcedureDef();
|
||||
if (tuple && Names.equals(tuple[0], name)) {
|
||||
return blocks[i]; // Can't use procedureBlock var due to type check.
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
exports.getDefinition = getDefinition;
|
||||
|
||||
185
core/registry.js
185
core/registry.js
@@ -11,20 +11,33 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.registry');
|
||||
goog.module('Blockly.registry');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.requireType('Blockly.blockRendering.Renderer');
|
||||
goog.requireType('Blockly.Cursor');
|
||||
goog.requireType('Blockly.Events.Abstract');
|
||||
goog.requireType('Blockly.Field');
|
||||
goog.requireType('Blockly.IBlockDragger');
|
||||
goog.requireType('Blockly.IConnectionChecker');
|
||||
goog.requireType('Blockly.IFlyout');
|
||||
goog.requireType('Blockly.IMetricsManager');
|
||||
goog.requireType('Blockly.IToolbox');
|
||||
goog.requireType('Blockly.Options');
|
||||
goog.requireType('Blockly.Theme');
|
||||
goog.requireType('Blockly.ToolboxItem');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Abstract = goog.requireType('Blockly.Events.Abstract');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Cursor = goog.requireType('Blockly.Cursor');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
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 IConnectionChecker = goog.requireType('Blockly.IConnectionChecker');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IFlyout = goog.requireType('Blockly.IFlyout');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IMetricsManager = goog.requireType('Blockly.IMetricsManager');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IToolbox = goog.requireType('Blockly.IToolbox');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Options = goog.requireType('Blockly.Options');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Renderer = goog.requireType('Blockly.blockRendering.Renderer');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Theme = goog.requireType('Blockly.Theme');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const ToolboxItem = goog.requireType('Blockly.ToolboxItem');
|
||||
|
||||
|
||||
/**
|
||||
@@ -34,13 +47,16 @@ goog.requireType('Blockly.ToolboxItem');
|
||||
*
|
||||
* @type {Object<string, Object<string, function(new:?)>>}
|
||||
*/
|
||||
Blockly.registry.typeMap_ = Object.create(null);
|
||||
const typeMap = Object.create(null);
|
||||
/** @private */
|
||||
exports.typeMap_ = typeMap;
|
||||
|
||||
/**
|
||||
* The string used to register the default class for a type of plugin.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.registry.DEFAULT = 'default';
|
||||
const DEFAULT = 'default';
|
||||
exports.DEFAULT = DEFAULT;
|
||||
|
||||
/**
|
||||
* A name with the type of the element stored in the generic.
|
||||
@@ -48,67 +64,63 @@ Blockly.registry.DEFAULT = 'default';
|
||||
* @constructor
|
||||
* @template T
|
||||
*/
|
||||
Blockly.registry.Type = function(name) {
|
||||
const Type = function(name) {
|
||||
/**
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
this.name_ = name;
|
||||
};
|
||||
exports.Type = Type;
|
||||
|
||||
/**
|
||||
* Returns the name of the type.
|
||||
* @return {string} The name.
|
||||
* @override
|
||||
*/
|
||||
Blockly.registry.Type.prototype.toString = function() {
|
||||
Type.prototype.toString = function() {
|
||||
return this.name_;
|
||||
};
|
||||
|
||||
/** @type {!Blockly.registry.Type<Blockly.IConnectionChecker>} */
|
||||
Blockly.registry.Type.CONNECTION_CHECKER =
|
||||
new Blockly.registry.Type('connectionChecker');
|
||||
/** @type {!Type<IConnectionChecker>} */
|
||||
Type.CONNECTION_CHECKER = new Type('connectionChecker');
|
||||
|
||||
/** @type {!Blockly.registry.Type<Blockly.Cursor>} */
|
||||
Blockly.registry.Type.CURSOR = new Blockly.registry.Type('cursor');
|
||||
/** @type {!Type<Cursor>} */
|
||||
Type.CURSOR = new Type('cursor');
|
||||
|
||||
/** @type {!Blockly.registry.Type<Blockly.Events.Abstract>} */
|
||||
Blockly.registry.Type.EVENT = new Blockly.registry.Type('event');
|
||||
/** @type {!Type<Abstract>} */
|
||||
Type.EVENT = new Type('event');
|
||||
|
||||
/** @type {!Blockly.registry.Type<Blockly.Field>} */
|
||||
Blockly.registry.Type.FIELD = new Blockly.registry.Type('field');
|
||||
/** @type {!Type<Field>} */
|
||||
Type.FIELD = new Type('field');
|
||||
|
||||
/** @type {!Blockly.registry.Type<Blockly.blockRendering.Renderer>} */
|
||||
Blockly.registry.Type.RENDERER = new Blockly.registry.Type('renderer');
|
||||
/** @type {!Type<Renderer>} */
|
||||
Type.RENDERER = new Type('renderer');
|
||||
|
||||
/** @type {!Blockly.registry.Type<Blockly.IToolbox>} */
|
||||
Blockly.registry.Type.TOOLBOX = new Blockly.registry.Type('toolbox');
|
||||
/** @type {!Type<IToolbox>} */
|
||||
Type.TOOLBOX = new Type('toolbox');
|
||||
|
||||
/** @type {!Blockly.registry.Type<Blockly.Theme>} */
|
||||
Blockly.registry.Type.THEME = new Blockly.registry.Type('theme');
|
||||
/** @type {!Type<Theme>} */
|
||||
Type.THEME = new Type('theme');
|
||||
|
||||
/** @type {!Blockly.registry.Type<Blockly.ToolboxItem>} */
|
||||
Blockly.registry.Type.TOOLBOX_ITEM = new Blockly.registry.Type('toolboxItem');
|
||||
/** @type {!Type<ToolboxItem>} */
|
||||
Type.TOOLBOX_ITEM = new Type('toolboxItem');
|
||||
|
||||
/** @type {!Blockly.registry.Type<Blockly.IFlyout>} */
|
||||
Blockly.registry.Type.FLYOUTS_VERTICAL_TOOLBOX =
|
||||
new Blockly.registry.Type('flyoutsVerticalToolbox');
|
||||
/** @type {!Type<IFlyout>} */
|
||||
Type.FLYOUTS_VERTICAL_TOOLBOX = new Type('flyoutsVerticalToolbox');
|
||||
|
||||
/** @type {!Blockly.registry.Type<Blockly.IFlyout>} */
|
||||
Blockly.registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX =
|
||||
new Blockly.registry.Type('flyoutsHorizontalToolbox');
|
||||
/** @type {!Type<IFlyout>} */
|
||||
Type.FLYOUTS_HORIZONTAL_TOOLBOX = new Type('flyoutsHorizontalToolbox');
|
||||
|
||||
/** @type {!Blockly.registry.Type<Blockly.IMetricsManager>} */
|
||||
Blockly.registry.Type.METRICS_MANAGER =
|
||||
new Blockly.registry.Type('metricsManager');
|
||||
/** @type {!Type<IMetricsManager>} */
|
||||
Type.METRICS_MANAGER = new Type('metricsManager');
|
||||
|
||||
/** @type {!Blockly.registry.Type<Blockly.IBlockDragger>} */
|
||||
Blockly.registry.Type.BLOCK_DRAGGER =
|
||||
new Blockly.registry.Type('blockDragger');
|
||||
/** @type {!Type<IBlockDragger>} */
|
||||
Type.BLOCK_DRAGGER = new Type('blockDragger');
|
||||
|
||||
/**
|
||||
* Registers a class based on a type and name.
|
||||
* @param {string|!Blockly.registry.Type<T>} type The type of the plugin.
|
||||
* @param {string|!Type<T>} type The type of the plugin.
|
||||
* (e.g. Field, Renderer)
|
||||
* @param {string} name The plugin's name. (Ex. field_angle, geras)
|
||||
* @param {?function(new:T, ...?)|Object} registryItem The class or object to
|
||||
@@ -120,9 +132,8 @@ Blockly.registry.Type.BLOCK_DRAGGER =
|
||||
* it's type.
|
||||
* @template T
|
||||
*/
|
||||
Blockly.registry.register = function(
|
||||
type, name, registryItem, opt_allowOverrides) {
|
||||
if ((!(type instanceof Blockly.registry.Type) && typeof type != 'string') ||
|
||||
const register = function(type, name, registryItem, opt_allowOverrides) {
|
||||
if ((!(type instanceof Type) && typeof type != 'string') ||
|
||||
String(type).trim() == '') {
|
||||
throw Error(
|
||||
'Invalid type "' + type + '". The type must be a' +
|
||||
@@ -139,14 +150,14 @@ Blockly.registry.register = function(
|
||||
if (!registryItem) {
|
||||
throw Error('Can not register a null value');
|
||||
}
|
||||
var typeRegistry = Blockly.registry.typeMap_[type];
|
||||
let typeRegistry = typeMap[type];
|
||||
// If the type registry has not been created, create it.
|
||||
if (!typeRegistry) {
|
||||
typeRegistry = Blockly.registry.typeMap_[type] = Object.create(null);
|
||||
typeRegistry = typeMap[type] = Object.create(null);
|
||||
}
|
||||
|
||||
// Validate that the given class has all the required properties.
|
||||
Blockly.registry.validate_(type, registryItem);
|
||||
validate(type, registryItem);
|
||||
|
||||
// Don't throw an error if opt_allowOverrides is true.
|
||||
if (!opt_allowOverrides && typeRegistry[name]) {
|
||||
@@ -155,6 +166,7 @@ Blockly.registry.register = function(
|
||||
}
|
||||
typeRegistry[name] = registryItem;
|
||||
};
|
||||
exports.register = register;
|
||||
|
||||
/**
|
||||
* Checks the given registry item for properties that are required based on the
|
||||
@@ -162,11 +174,10 @@ Blockly.registry.register = function(
|
||||
* @param {string} type The type of the plugin. (e.g. Field, Renderer)
|
||||
* @param {Function|Object} registryItem A class or object that we are checking
|
||||
* for the required properties.
|
||||
* @private
|
||||
*/
|
||||
Blockly.registry.validate_ = function(type, registryItem) {
|
||||
const validate = function(type, registryItem) {
|
||||
switch (type) {
|
||||
case String(Blockly.registry.Type.FIELD):
|
||||
case String(Type.FIELD):
|
||||
if (typeof registryItem.fromJson != 'function') {
|
||||
throw Error('Type "' + type + '" must have a fromJson function');
|
||||
}
|
||||
@@ -176,27 +187,29 @@ Blockly.registry.validate_ = function(type, registryItem) {
|
||||
|
||||
/**
|
||||
* Unregisters the registry item with the given type and name.
|
||||
* @param {string|!Blockly.registry.Type<T>} type The type of the plugin.
|
||||
* @param {string|!Type<T>} type The type of the plugin.
|
||||
* (e.g. Field, Renderer)
|
||||
* @param {string} name The plugin's name. (Ex. field_angle, geras)
|
||||
* @template T
|
||||
*/
|
||||
Blockly.registry.unregister = function(type, name) {
|
||||
const unregister = function(type, name) {
|
||||
type = String(type).toLowerCase();
|
||||
name = name.toLowerCase();
|
||||
var typeRegistry = Blockly.registry.typeMap_[type];
|
||||
const typeRegistry = typeMap[type];
|
||||
if (!typeRegistry || !typeRegistry[name]) {
|
||||
console.warn('Unable to unregister [' + name + '][' + type + '] from the ' +
|
||||
'registry.');
|
||||
console.warn(
|
||||
'Unable to unregister [' + name + '][' + type + '] from the ' +
|
||||
'registry.');
|
||||
return;
|
||||
}
|
||||
delete Blockly.registry.typeMap_[type][name];
|
||||
delete typeMap[type][name];
|
||||
};
|
||||
exports.unregister = unregister;
|
||||
|
||||
/**
|
||||
* Gets the registry item for the given name and type. This can be either a
|
||||
* class or an object.
|
||||
* @param {string|!Blockly.registry.Type<T>} type The type of the plugin.
|
||||
* @param {string|!Type<T>} type The type of the plugin.
|
||||
* (e.g. Field, Renderer)
|
||||
* @param {string} name The plugin's name. (Ex. field_angle, geras)
|
||||
* @param {boolean=} opt_throwIfMissing Whether or not to throw an error if we
|
||||
@@ -205,15 +218,15 @@ Blockly.registry.unregister = function(type, name) {
|
||||
* name and type or null if none exists.
|
||||
* @template T
|
||||
*/
|
||||
Blockly.registry.getItem_ = function(type, name, opt_throwIfMissing) {
|
||||
const getItem = function(type, name, opt_throwIfMissing) {
|
||||
type = String(type).toLowerCase();
|
||||
name = name.toLowerCase();
|
||||
var typeRegistry = Blockly.registry.typeMap_[type];
|
||||
const typeRegistry = typeMap[type];
|
||||
if (!typeRegistry || !typeRegistry[name]) {
|
||||
var msg = 'Unable to find [' + name + '][' + type + '] in the registry.';
|
||||
const msg = 'Unable to find [' + name + '][' + type + '] in the registry.';
|
||||
if (opt_throwIfMissing) {
|
||||
throw new Error(msg + ' You must require or register a ' + type +
|
||||
' plugin.');
|
||||
throw new Error(
|
||||
msg + ' You must require or register a ' + type + ' plugin.');
|
||||
} else {
|
||||
console.warn(msg);
|
||||
}
|
||||
@@ -225,26 +238,27 @@ Blockly.registry.getItem_ = function(type, name, opt_throwIfMissing) {
|
||||
/**
|
||||
* Returns whether or not the registry contains an item with the given type and
|
||||
* name.
|
||||
* @param {string|!Blockly.registry.Type<T>} type The type of the plugin.
|
||||
* @param {string|!Type<T>} type The type of the plugin.
|
||||
* (e.g. Field, Renderer)
|
||||
* @param {string} name The plugin's name. (Ex. field_angle, geras)
|
||||
* @return {boolean} True if the registry has an item with the given type and
|
||||
* name, false otherwise.
|
||||
* @template T
|
||||
*/
|
||||
Blockly.registry.hasItem = function(type, name) {
|
||||
const hasItem = function(type, name) {
|
||||
type = String(type).toLowerCase();
|
||||
name = name.toLowerCase();
|
||||
var typeRegistry = Blockly.registry.typeMap_[type];
|
||||
const typeRegistry = typeMap[type];
|
||||
if (!typeRegistry) {
|
||||
return false;
|
||||
}
|
||||
return !!(typeRegistry[name]);
|
||||
};
|
||||
exports.hasItem = hasItem;
|
||||
|
||||
/**
|
||||
* Gets the class for the given name and type.
|
||||
* @param {string|!Blockly.registry.Type<T>} type The type of the plugin.
|
||||
* @param {string|!Type<T>} type The type of the plugin.
|
||||
* (e.g. Field, Renderer)
|
||||
* @param {string} name The plugin's name. (Ex. field_angle, geras)
|
||||
* @param {boolean=} opt_throwIfMissing Whether or not to throw an error if we
|
||||
@@ -253,14 +267,15 @@ Blockly.registry.hasItem = function(type, name) {
|
||||
* null if none exists.
|
||||
* @template T
|
||||
*/
|
||||
Blockly.registry.getClass = function(type, name, opt_throwIfMissing) {
|
||||
const getClass = function(type, name, opt_throwIfMissing) {
|
||||
return /** @type {?function(new:T, ...?)} */ (
|
||||
Blockly.registry.getItem_(type, name, opt_throwIfMissing));
|
||||
getItem(type, name, opt_throwIfMissing));
|
||||
};
|
||||
exports.getClass = getClass;
|
||||
|
||||
/**
|
||||
* Gets the object for the given name and type.
|
||||
* @param {string|!Blockly.registry.Type<T>} type The type of the plugin.
|
||||
* @param {string|!Type<T>} type The type of the plugin.
|
||||
* (e.g. Category)
|
||||
* @param {string} name The plugin's name. (Ex. logic_category)
|
||||
* @param {boolean=} opt_throwIfMissing Whether or not to throw an error if we
|
||||
@@ -268,30 +283,30 @@ Blockly.registry.getClass = function(type, name, opt_throwIfMissing) {
|
||||
* @return {?T} The object with the given name and type or null if none exists.
|
||||
* @template T
|
||||
*/
|
||||
Blockly.registry.getObject = function(type, name, opt_throwIfMissing) {
|
||||
return /** @type {T} */ (
|
||||
Blockly.registry.getItem_(type, name, opt_throwIfMissing));
|
||||
const getObject = function(type, name, opt_throwIfMissing) {
|
||||
return /** @type {T} */ (getItem(type, name, opt_throwIfMissing));
|
||||
};
|
||||
exports.getObject = getObject;
|
||||
|
||||
/**
|
||||
* Gets the class from Blockly options for the given type.
|
||||
* This is used for plugins that override a built in feature. (e.g. Toolbox)
|
||||
* @param {!Blockly.registry.Type<T>} type The type of the plugin.
|
||||
* @param {!Blockly.Options} options The option object to check for the given
|
||||
* @param {!Type<T>} type The type of the plugin.
|
||||
* @param {!Options} options The option object to check for the given
|
||||
* plugin.
|
||||
* @param {boolean=} opt_throwIfMissing Whether or not to throw an error if we
|
||||
* are unable to find the plugin.
|
||||
* @return {?function(new:T, ...?)} The class for the plugin.
|
||||
* @template T
|
||||
*/
|
||||
Blockly.registry.getClassFromOptions = function(type, options,
|
||||
opt_throwIfMissing) {
|
||||
var typeName = type.toString();
|
||||
var plugin = options.plugins[typeName] || Blockly.registry.DEFAULT;
|
||||
const getClassFromOptions = function(type, options, opt_throwIfMissing) {
|
||||
const typeName = type.toString();
|
||||
const plugin = options.plugins[typeName] || DEFAULT;
|
||||
|
||||
// If the user passed in a plugin class instead of a registered plugin name.
|
||||
if (typeof plugin == 'function') {
|
||||
return plugin;
|
||||
}
|
||||
return Blockly.registry.getClass(type, plugin, opt_throwIfMissing);
|
||||
return getClass(type, plugin, opt_throwIfMissing);
|
||||
};
|
||||
exports.getClassFromOptions = getClassFromOptions;
|
||||
|
||||
@@ -10,36 +10,40 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.RenderedConnection');
|
||||
goog.module('Blockly.RenderedConnection');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Connection');
|
||||
goog.require('Blockly.connectionTypes');
|
||||
goog.require('Blockly.internalConstants');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.utils.deprecation');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.ConnectionDB');
|
||||
/* 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 Connection = goog.require('Blockly.Connection');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const ConnectionDB = goog.requireType('Blockly.ConnectionDB');
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
const Events = goog.require('Blockly.Events');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
const connectionTypes = goog.require('Blockly.connectionTypes');
|
||||
const deprecation = goog.require('Blockly.utils.deprecation');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const internalConstants = goog.require('Blockly.internalConstants');
|
||||
const object = goog.require('Blockly.utils.object');
|
||||
const utils = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a connection between blocks that may be rendered on screen.
|
||||
* @param {!Blockly.BlockSvg} source The block establishing this connection.
|
||||
* @param {!BlockSvg} source The block establishing this connection.
|
||||
* @param {number} type The type of the connection.
|
||||
* @extends {Blockly.Connection}
|
||||
* @extends {Connection}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.RenderedConnection = function(source, type) {
|
||||
Blockly.RenderedConnection.superClass_.constructor.call(this, source, type);
|
||||
const RenderedConnection = function(source, type) {
|
||||
RenderedConnection.superClass_.constructor.call(this, source, type);
|
||||
|
||||
/**
|
||||
* Connection database for connections of this type on the current workspace.
|
||||
* @const {!Blockly.ConnectionDB}
|
||||
* @const {!ConnectionDB}
|
||||
* @private
|
||||
*/
|
||||
this.db_ = source.workspace.connectionDBList[type];
|
||||
@@ -47,34 +51,33 @@ Blockly.RenderedConnection = function(source, type) {
|
||||
/**
|
||||
* Connection database for connections compatible with this type on the
|
||||
* current workspace.
|
||||
* @const {!Blockly.ConnectionDB}
|
||||
* @const {!ConnectionDB}
|
||||
* @private
|
||||
*/
|
||||
this.dbOpposite_ =
|
||||
source.workspace
|
||||
.connectionDBList[Blockly.internalConstants.OPPOSITE_TYPE[type]];
|
||||
source.workspace.connectionDBList[internalConstants.OPPOSITE_TYPE[type]];
|
||||
|
||||
/**
|
||||
* Workspace units, (0, 0) is top left of block.
|
||||
* @type {!Blockly.utils.Coordinate}
|
||||
* @type {!Coordinate}
|
||||
* @private
|
||||
*/
|
||||
this.offsetInBlock_ = new Blockly.utils.Coordinate(0, 0);
|
||||
this.offsetInBlock_ = new Coordinate(0, 0);
|
||||
|
||||
/**
|
||||
* Describes the state of this connection's tracked-ness.
|
||||
* @type {Blockly.RenderedConnection.TrackedState}
|
||||
* @type {RenderedConnection.TrackedState}
|
||||
* @private
|
||||
*/
|
||||
this.trackedState_ = Blockly.RenderedConnection.TrackedState.WILL_TRACK;
|
||||
this.trackedState_ = RenderedConnection.TrackedState.WILL_TRACK;
|
||||
|
||||
/**
|
||||
* Connection this connection connects to. Null if not connected.
|
||||
* @type {Blockly.RenderedConnection}
|
||||
* @type {RenderedConnection}
|
||||
*/
|
||||
this.targetConnection = null;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.RenderedConnection, Blockly.Connection);
|
||||
object.inherits(RenderedConnection, Connection);
|
||||
|
||||
/**
|
||||
* Enum for different kinds of tracked states.
|
||||
@@ -88,7 +91,7 @@ Blockly.utils.object.inherits(Blockly.RenderedConnection, Blockly.Connection);
|
||||
* TRACKED means that this connection is currently being tracked.
|
||||
* @enum {number}
|
||||
*/
|
||||
Blockly.RenderedConnection.TrackedState = {
|
||||
RenderedConnection.TrackedState = {
|
||||
WILL_TRACK: -1,
|
||||
UNTRACKED: 0,
|
||||
TRACKED: 1
|
||||
@@ -100,65 +103,65 @@ Blockly.RenderedConnection.TrackedState = {
|
||||
* @override
|
||||
* @package
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.dispose = function() {
|
||||
Blockly.RenderedConnection.superClass_.dispose.call(this);
|
||||
if (this.trackedState_ == Blockly.RenderedConnection.TrackedState.TRACKED) {
|
||||
RenderedConnection.prototype.dispose = function() {
|
||||
RenderedConnection.superClass_.dispose.call(this);
|
||||
if (this.trackedState_ == RenderedConnection.TrackedState.TRACKED) {
|
||||
this.db_.removeConnection(this, this.y);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the source block for this connection.
|
||||
* @return {!Blockly.BlockSvg} The source block.
|
||||
* @return {!BlockSvg} The source block.
|
||||
* @override
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.getSourceBlock = function() {
|
||||
return /** @type {!Blockly.BlockSvg} */ (
|
||||
Blockly.RenderedConnection.superClass_.getSourceBlock.call(this));
|
||||
RenderedConnection.prototype.getSourceBlock = function() {
|
||||
return /** @type {!BlockSvg} */ (
|
||||
RenderedConnection.superClass_.getSourceBlock.call(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the block that this connection connects to.
|
||||
* @return {?Blockly.BlockSvg} The connected block or null if none is connected.
|
||||
* @return {?BlockSvg} The connected block or null if none is connected.
|
||||
* @override
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.targetBlock = function() {
|
||||
return /** @type {Blockly.BlockSvg} */ (
|
||||
Blockly.RenderedConnection.superClass_.targetBlock.call(this));
|
||||
RenderedConnection.prototype.targetBlock = function() {
|
||||
return /** @type {BlockSvg} */ (
|
||||
RenderedConnection.superClass_.targetBlock.call(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the distance between this connection and another connection in
|
||||
* workspace units.
|
||||
* @param {!Blockly.Connection} otherConnection The other connection to measure
|
||||
* @param {!Connection} otherConnection The other connection to measure
|
||||
* the distance to.
|
||||
* @return {number} The distance between connections, in workspace units.
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.distanceFrom = function(otherConnection) {
|
||||
var xDiff = this.x - otherConnection.x;
|
||||
var yDiff = this.y - otherConnection.y;
|
||||
RenderedConnection.prototype.distanceFrom = function(otherConnection) {
|
||||
const xDiff = this.x - otherConnection.x;
|
||||
const yDiff = this.y - otherConnection.y;
|
||||
return Math.sqrt(xDiff * xDiff + yDiff * yDiff);
|
||||
};
|
||||
|
||||
/**
|
||||
* Move the block(s) belonging to the connection to a point where they don't
|
||||
* visually interfere with the specified connection.
|
||||
* @param {!Blockly.Connection} staticConnection The connection to move away
|
||||
* @param {!Connection} staticConnection The connection to move away
|
||||
* from.
|
||||
* @package
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.bumpAwayFrom = function(staticConnection) {
|
||||
RenderedConnection.prototype.bumpAwayFrom = function(staticConnection) {
|
||||
if (this.sourceBlock_.workspace.isDragging()) {
|
||||
// Don't move blocks around while the user is doing the same.
|
||||
return;
|
||||
}
|
||||
// Move the root block.
|
||||
var rootBlock = this.sourceBlock_.getRootBlock();
|
||||
let rootBlock = this.sourceBlock_.getRootBlock();
|
||||
if (rootBlock.isInFlyout) {
|
||||
// Don't move blocks around in a flyout.
|
||||
return;
|
||||
}
|
||||
var reverse = false;
|
||||
let reverse = false;
|
||||
if (!rootBlock.isMovable()) {
|
||||
// Can't bump an uneditable block away.
|
||||
// Check to see if the other block is movable.
|
||||
@@ -171,24 +174,21 @@ Blockly.RenderedConnection.prototype.bumpAwayFrom = function(staticConnection) {
|
||||
reverse = true;
|
||||
}
|
||||
// Raise it to the top for extra visibility.
|
||||
var selected = Blockly.selected == rootBlock;
|
||||
const selected = Blockly.selected == rootBlock;
|
||||
selected || rootBlock.addSelect();
|
||||
var dx =
|
||||
(staticConnection.x + Blockly.internalConstants.SNAP_RADIUS +
|
||||
Math.floor(Math.random() * Blockly.internalConstants.BUMP_RANDOMNESS)) -
|
||||
let dx = (staticConnection.x + internalConstants.SNAP_RADIUS +
|
||||
Math.floor(Math.random() * internalConstants.BUMP_RANDOMNESS)) -
|
||||
this.x;
|
||||
var dy =
|
||||
(staticConnection.y + Blockly.internalConstants.SNAP_RADIUS +
|
||||
Math.floor(Math.random() * Blockly.internalConstants.BUMP_RANDOMNESS)) -
|
||||
let dy = (staticConnection.y + internalConstants.SNAP_RADIUS +
|
||||
Math.floor(Math.random() * 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.internalConstants.SNAP_RADIUS -
|
||||
Math.floor(
|
||||
Math.random() * Blockly.internalConstants.BUMP_RANDOMNESS)) -
|
||||
dx = (staticConnection.x - internalConstants.SNAP_RADIUS -
|
||||
Math.floor(Math.random() * internalConstants.BUMP_RANDOMNESS)) -
|
||||
this.x;
|
||||
}
|
||||
rootBlock.moveBy(dx, dy);
|
||||
@@ -200,12 +200,11 @@ Blockly.RenderedConnection.prototype.bumpAwayFrom = function(staticConnection) {
|
||||
* @param {number} x New absolute x coordinate, in workspace coordinates.
|
||||
* @param {number} y New absolute y coordinate, in workspace coordinates.
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.moveTo = function(x, y) {
|
||||
if (this.trackedState_ == Blockly.RenderedConnection.TrackedState.WILL_TRACK) {
|
||||
RenderedConnection.prototype.moveTo = function(x, y) {
|
||||
if (this.trackedState_ == RenderedConnection.TrackedState.WILL_TRACK) {
|
||||
this.db_.addConnection(this, y);
|
||||
this.trackedState_ = Blockly.RenderedConnection.TrackedState.TRACKED;
|
||||
} else if (this.trackedState_ == Blockly.RenderedConnection
|
||||
.TrackedState.TRACKED) {
|
||||
this.trackedState_ = RenderedConnection.TrackedState.TRACKED;
|
||||
} else if (this.trackedState_ == RenderedConnection.TrackedState.TRACKED) {
|
||||
this.db_.removeConnection(this, this.y);
|
||||
this.db_.addConnection(this, y);
|
||||
}
|
||||
@@ -218,19 +217,19 @@ Blockly.RenderedConnection.prototype.moveTo = function(x, y) {
|
||||
* @param {number} dx Change to x coordinate, in workspace units.
|
||||
* @param {number} dy Change to y coordinate, in workspace units.
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.moveBy = function(dx, dy) {
|
||||
RenderedConnection.prototype.moveBy = function(dx, dy) {
|
||||
this.moveTo(this.x + dx, this.y + dy);
|
||||
};
|
||||
|
||||
/**
|
||||
* Move this connection to the location given by its offset within the block and
|
||||
* the location of the block's top left corner.
|
||||
* @param {!Blockly.utils.Coordinate} blockTL The location of the top left
|
||||
* @param {!Coordinate} blockTL The location of the top left
|
||||
* corner of the block, in workspace coordinates.
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.moveToOffset = function(blockTL) {
|
||||
this.moveTo(blockTL.x + this.offsetInBlock_.x,
|
||||
blockTL.y + this.offsetInBlock_.y);
|
||||
RenderedConnection.prototype.moveToOffset = function(blockTL) {
|
||||
this.moveTo(
|
||||
blockTL.x + this.offsetInBlock_.x, blockTL.y + this.offsetInBlock_.y);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -238,17 +237,17 @@ Blockly.RenderedConnection.prototype.moveToOffset = function(blockTL) {
|
||||
* @param {number} x The new relative x, in workspace units.
|
||||
* @param {number} y The new relative y, in workspace units.
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.setOffsetInBlock = function(x, y) {
|
||||
RenderedConnection.prototype.setOffsetInBlock = function(x, y) {
|
||||
this.offsetInBlock_.x = x;
|
||||
this.offsetInBlock_.y = y;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the offset of this connection relative to the top left of its block.
|
||||
* @return {!Blockly.utils.Coordinate} The offset of the connection.
|
||||
* @return {!Coordinate} The offset of the connection.
|
||||
* @package
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.getOffsetInBlock = function() {
|
||||
RenderedConnection.prototype.getOffsetInBlock = function() {
|
||||
return this.offsetInBlock_;
|
||||
};
|
||||
|
||||
@@ -256,19 +255,19 @@ Blockly.RenderedConnection.prototype.getOffsetInBlock = function() {
|
||||
* Move the blocks on either side of this connection right next to each other.
|
||||
* @package
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.tighten = function() {
|
||||
var dx = this.targetConnection.x - this.x;
|
||||
var dy = this.targetConnection.y - this.y;
|
||||
RenderedConnection.prototype.tighten = function() {
|
||||
const dx = this.targetConnection.x - this.x;
|
||||
const dy = this.targetConnection.y - this.y;
|
||||
if (dx != 0 || dy != 0) {
|
||||
var block = this.targetBlock();
|
||||
var svgRoot = block.getSvgRoot();
|
||||
const block = this.targetBlock();
|
||||
const svgRoot = block.getSvgRoot();
|
||||
if (!svgRoot) {
|
||||
throw Error('block is not rendered.');
|
||||
}
|
||||
// Workspace coordinates.
|
||||
var xy = Blockly.utils.getRelativeXY(svgRoot);
|
||||
block.getSvgRoot().setAttribute('transform',
|
||||
'translate(' + (xy.x - dx) + ',' + (xy.y - dy) + ')');
|
||||
const xy = utils.getRelativeXY(svgRoot);
|
||||
block.getSvgRoot().setAttribute(
|
||||
'transform', 'translate(' + (xy.x - dx) + ',' + (xy.y - dy) + ')');
|
||||
block.moveConnections(-dx, -dy);
|
||||
}
|
||||
};
|
||||
@@ -277,47 +276,44 @@ Blockly.RenderedConnection.prototype.tighten = function() {
|
||||
* Find the closest compatible connection to this connection.
|
||||
* All parameters are in workspace units.
|
||||
* @param {number} maxLimit The maximum radius to another connection.
|
||||
* @param {!Blockly.utils.Coordinate} dxy Offset between this connection's location
|
||||
* @param {!Coordinate} dxy Offset between this connection's location
|
||||
* in the database and the current location (as a result of dragging).
|
||||
* @return {!{connection: ?Blockly.Connection, radius: number}} Contains two
|
||||
* @return {!{connection: ?Connection, radius: number}} Contains two
|
||||
* properties: 'connection' which is either another connection or null,
|
||||
* and 'radius' which is the distance.
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.closest = function(maxLimit, dxy) {
|
||||
RenderedConnection.prototype.closest = function(maxLimit, dxy) {
|
||||
return this.dbOpposite_.searchForClosest(this, maxLimit, dxy);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add highlighting around this connection.
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.highlight = function() {
|
||||
var steps;
|
||||
var sourceBlockSvg = /** @type {!Blockly.BlockSvg} */ (this.sourceBlock_);
|
||||
var renderConstants = sourceBlockSvg.workspace.getRenderer().getConstants();
|
||||
var shape = renderConstants.shapeFor(this);
|
||||
if (this.type == Blockly.connectionTypes.INPUT_VALUE ||
|
||||
this.type == Blockly.connectionTypes.OUTPUT_VALUE) {
|
||||
RenderedConnection.prototype.highlight = function() {
|
||||
let steps;
|
||||
const sourceBlockSvg = /** @type {!BlockSvg} */ (this.sourceBlock_);
|
||||
const renderConstants = sourceBlockSvg.workspace.getRenderer().getConstants();
|
||||
const shape = renderConstants.shapeFor(this);
|
||||
if (this.type == connectionTypes.INPUT_VALUE ||
|
||||
this.type == connectionTypes.OUTPUT_VALUE) {
|
||||
// Vertical line, puzzle tab, vertical line.
|
||||
var yLen = renderConstants.TAB_OFFSET_FROM_TOP;
|
||||
steps = Blockly.utils.svgPaths.moveBy(0, -yLen) +
|
||||
Blockly.utils.svgPaths.lineOnAxis('v', yLen) +
|
||||
shape.pathDown +
|
||||
Blockly.utils.svgPaths.lineOnAxis('v', yLen);
|
||||
const yLen = renderConstants.TAB_OFFSET_FROM_TOP;
|
||||
steps = utils.svgPaths.moveBy(0, -yLen) +
|
||||
utils.svgPaths.lineOnAxis('v', yLen) + shape.pathDown +
|
||||
utils.svgPaths.lineOnAxis('v', yLen);
|
||||
} else {
|
||||
var xLen =
|
||||
const xLen =
|
||||
renderConstants.NOTCH_OFFSET_LEFT - renderConstants.CORNER_RADIUS;
|
||||
// Horizontal line, notch, horizontal line.
|
||||
steps = Blockly.utils.svgPaths.moveBy(-xLen, 0) +
|
||||
Blockly.utils.svgPaths.lineOnAxis('h', xLen) +
|
||||
shape.pathLeft +
|
||||
Blockly.utils.svgPaths.lineOnAxis('h', xLen);
|
||||
steps = utils.svgPaths.moveBy(-xLen, 0) +
|
||||
utils.svgPaths.lineOnAxis('h', xLen) + shape.pathLeft +
|
||||
utils.svgPaths.lineOnAxis('h', xLen);
|
||||
}
|
||||
var xy = this.sourceBlock_.getRelativeToSurfaceXY();
|
||||
var x = this.x - xy.x;
|
||||
var y = this.y - xy.y;
|
||||
Blockly.Connection.highlightedPath_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.PATH,
|
||||
{
|
||||
const xy = this.sourceBlock_.getRelativeToSurfaceXY();
|
||||
const x = this.x - xy.x;
|
||||
const y = this.y - xy.y;
|
||||
Connection.highlightedPath_ = dom.createSvgElement(
|
||||
Svg.PATH, {
|
||||
'class': 'blocklyHighlightedConnectionPath',
|
||||
'd': steps,
|
||||
transform: 'translate(' + x + ',' + y + ')' +
|
||||
@@ -329,9 +325,9 @@ Blockly.RenderedConnection.prototype.highlight = function() {
|
||||
/**
|
||||
* Remove the highlighting around this connection.
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.unhighlight = function() {
|
||||
Blockly.utils.dom.removeNode(Blockly.Connection.highlightedPath_);
|
||||
delete Blockly.Connection.highlightedPath_;
|
||||
RenderedConnection.prototype.unhighlight = function() {
|
||||
dom.removeNode(Connection.highlightedPath_);
|
||||
delete Connection.highlightedPath_;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -339,11 +335,11 @@ Blockly.RenderedConnection.prototype.unhighlight = function() {
|
||||
* @param {boolean} doTracking If true, start tracking. If false, stop tracking.
|
||||
* @package
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.setTracking = function(doTracking) {
|
||||
if ((doTracking && this.trackedState_ ==
|
||||
Blockly.RenderedConnection.TrackedState.TRACKED) ||
|
||||
(!doTracking && this.trackedState_ ==
|
||||
Blockly.RenderedConnection.TrackedState.UNTRACKED)) {
|
||||
RenderedConnection.prototype.setTracking = function(doTracking) {
|
||||
if ((doTracking &&
|
||||
this.trackedState_ == RenderedConnection.TrackedState.TRACKED) ||
|
||||
(!doTracking &&
|
||||
this.trackedState_ == RenderedConnection.TrackedState.UNTRACKED)) {
|
||||
return;
|
||||
}
|
||||
if (this.sourceBlock_.isInFlyout) {
|
||||
@@ -352,13 +348,13 @@ Blockly.RenderedConnection.prototype.setTracking = function(doTracking) {
|
||||
}
|
||||
if (doTracking) {
|
||||
this.db_.addConnection(this, this.y);
|
||||
this.trackedState_ = Blockly.RenderedConnection.TrackedState.TRACKED;
|
||||
this.trackedState_ = RenderedConnection.TrackedState.TRACKED;
|
||||
return;
|
||||
}
|
||||
if (this.trackedState_ == Blockly.RenderedConnection.TrackedState.TRACKED) {
|
||||
if (this.trackedState_ == RenderedConnection.TrackedState.TRACKED) {
|
||||
this.db_.removeConnection(this, this.y);
|
||||
}
|
||||
this.trackedState_ = Blockly.RenderedConnection.TrackedState.UNTRACKED;
|
||||
this.trackedState_ = RenderedConnection.TrackedState.UNTRACKED;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -369,20 +365,20 @@ Blockly.RenderedConnection.prototype.setTracking = function(doTracking) {
|
||||
* Also closes down-stream icons/bubbles.
|
||||
* @package
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.stopTrackingAll = function() {
|
||||
RenderedConnection.prototype.stopTrackingAll = function() {
|
||||
this.setTracking(false);
|
||||
if (this.targetConnection) {
|
||||
var blocks = this.targetBlock().getDescendants(false);
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
var block = blocks[i];
|
||||
const blocks = this.targetBlock().getDescendants(false);
|
||||
for (let i = 0; i < blocks.length; i++) {
|
||||
const block = blocks[i];
|
||||
// Stop tracking connections of all children.
|
||||
var connections = block.getConnections_(true);
|
||||
for (var j = 0; j < connections.length; j++) {
|
||||
const connections = block.getConnections_(true);
|
||||
for (let j = 0; j < connections.length; j++) {
|
||||
connections[j].setTracking(false);
|
||||
}
|
||||
// Close all bubbles of all children.
|
||||
var icons = block.getIcons();
|
||||
for (var j = 0; j < icons.length; j++) {
|
||||
const icons = block.getIcons();
|
||||
for (let j = 0; j < icons.length; j++) {
|
||||
icons[j].setVisible(false);
|
||||
}
|
||||
}
|
||||
@@ -392,23 +388,23 @@ Blockly.RenderedConnection.prototype.stopTrackingAll = function() {
|
||||
/**
|
||||
* Start tracking this connection, as well as all down-stream connections on
|
||||
* any block attached to this connection. This happens when a block is expanded.
|
||||
* @return {!Array<!Blockly.Block>} List of blocks to render.
|
||||
* @return {!Array<!Block>} List of blocks to render.
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.startTrackingAll = function() {
|
||||
RenderedConnection.prototype.startTrackingAll = function() {
|
||||
this.setTracking(true);
|
||||
// All blocks that are not tracked must start tracking before any
|
||||
// rendering takes place, since rendering requires knowing the dimensions
|
||||
// of lower blocks. Also, since rendering a block renders all its parents,
|
||||
// we only need to render the leaf nodes.
|
||||
var renderList = [];
|
||||
if (this.type != Blockly.connectionTypes.INPUT_VALUE &&
|
||||
this.type != Blockly.connectionTypes.NEXT_STATEMENT) {
|
||||
const renderList = [];
|
||||
if (this.type != connectionTypes.INPUT_VALUE &&
|
||||
this.type != connectionTypes.NEXT_STATEMENT) {
|
||||
// Only spider down.
|
||||
return renderList;
|
||||
}
|
||||
var block = this.targetBlock();
|
||||
const block = this.targetBlock();
|
||||
if (block) {
|
||||
var connections;
|
||||
let connections;
|
||||
if (block.isCollapsed()) {
|
||||
// This block should only be partially revealed since it is collapsed.
|
||||
connections = [];
|
||||
@@ -419,7 +415,7 @@ Blockly.RenderedConnection.prototype.startTrackingAll = function() {
|
||||
// Show all connections of this block.
|
||||
connections = block.getConnections_(true);
|
||||
}
|
||||
for (var i = 0; i < connections.length; i++) {
|
||||
for (let i = 0; i < connections.length; i++) {
|
||||
renderList.push.apply(renderList, connections[i].startTrackingAll());
|
||||
}
|
||||
if (!renderList.length) {
|
||||
@@ -432,62 +428,60 @@ Blockly.RenderedConnection.prototype.startTrackingAll = function() {
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param {number=} maxRadius The maximum radius allowed for connections, in
|
||||
* workspace units.
|
||||
* @return {boolean} True if the connection is allowed, false otherwise.
|
||||
* @deprecated July 2020
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.isConnectionAllowed = function(candidate,
|
||||
maxRadius) {
|
||||
Blockly.utils.deprecation.warn(
|
||||
'RenderedConnection.prototype.isConnectionAllowed',
|
||||
'July 2020',
|
||||
RenderedConnection.prototype.isConnectionAllowed = function(
|
||||
candidate, maxRadius) {
|
||||
deprecation.warn(
|
||||
'RenderedConnection.prototype.isConnectionAllowed', 'July 2020',
|
||||
'July 2021',
|
||||
'Blockly.Workspace.prototype.getConnectionChecker().canConnect');
|
||||
if (this.distanceFrom(candidate) > maxRadius) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Blockly.RenderedConnection.superClass_.isConnectionAllowed.call(this,
|
||||
candidate);
|
||||
return RenderedConnection.superClass_.isConnectionAllowed.call(
|
||||
this, candidate);
|
||||
};
|
||||
|
||||
/**
|
||||
* Behavior after a connection attempt fails.
|
||||
* Bumps this connection away from the other connection. Called when an
|
||||
* attempted connection fails.
|
||||
* @param {!Blockly.Connection} otherConnection Connection that this connection
|
||||
* @param {!Connection} otherConnection Connection that this connection
|
||||
* failed to connect to.
|
||||
* @package
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.onFailedConnect =
|
||||
function(otherConnection) {
|
||||
var block = this.getSourceBlock();
|
||||
if (Blockly.Events.recordUndo) {
|
||||
var group = Blockly.Events.getGroup();
|
||||
setTimeout(function() {
|
||||
if (!block.isDisposed() && !block.getParent()) {
|
||||
Blockly.Events.setGroup(group);
|
||||
this.bumpAwayFrom(otherConnection);
|
||||
Blockly.Events.setGroup(false);
|
||||
}
|
||||
}.bind(this), Blockly.internalConstants.BUMP_DELAY);
|
||||
RenderedConnection.prototype.onFailedConnect = function(otherConnection) {
|
||||
const block = this.getSourceBlock();
|
||||
if (Events.recordUndo) {
|
||||
const group = Events.getGroup();
|
||||
setTimeout(function() {
|
||||
if (!block.isDisposed() && !block.getParent()) {
|
||||
Events.setGroup(group);
|
||||
this.bumpAwayFrom(otherConnection);
|
||||
Events.setGroup(false);
|
||||
}
|
||||
};
|
||||
}.bind(this), internalConstants.BUMP_DELAY);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @override
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.disconnectInternal_ = function(parentBlock,
|
||||
childBlock) {
|
||||
Blockly.RenderedConnection.superClass_.disconnectInternal_.call(this,
|
||||
parentBlock, childBlock);
|
||||
RenderedConnection.prototype.disconnectInternal_ = function(
|
||||
parentBlock, childBlock) {
|
||||
RenderedConnection.superClass_.disconnectInternal_.call(
|
||||
this, parentBlock, childBlock);
|
||||
// Rerender the parent so that it may reflow.
|
||||
if (parentBlock.rendered) {
|
||||
parentBlock.render();
|
||||
@@ -506,9 +500,9 @@ Blockly.RenderedConnection.prototype.disconnectInternal_ = function(parentBlock,
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.respawnShadow_ = function() {
|
||||
Blockly.RenderedConnection.superClass_.respawnShadow_.call(this);
|
||||
var blockShadow = this.targetBlock();
|
||||
RenderedConnection.prototype.respawnShadow_ = function() {
|
||||
RenderedConnection.superClass_.respawnShadow_.call(this);
|
||||
const blockShadow = this.targetBlock();
|
||||
if (!blockShadow) {
|
||||
// This connection must not have a shadowDom_.
|
||||
return;
|
||||
@@ -516,7 +510,7 @@ Blockly.RenderedConnection.prototype.respawnShadow_ = function() {
|
||||
blockShadow.initSvg();
|
||||
blockShadow.render(false);
|
||||
|
||||
var parentBlock = this.getSourceBlock();
|
||||
const parentBlock = this.getSourceBlock();
|
||||
if (parentBlock.rendered) {
|
||||
parentBlock.render();
|
||||
}
|
||||
@@ -527,27 +521,27 @@ Blockly.RenderedConnection.prototype.respawnShadow_ = function() {
|
||||
* Type checking does not apply, since this function is used for bumping.
|
||||
* @param {number} maxLimit The maximum radius to another connection, in
|
||||
* workspace units.
|
||||
* @return {!Array<!Blockly.Connection>} List of connections.
|
||||
* @return {!Array<!Connection>} List of connections.
|
||||
* @package
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.neighbours = function(maxLimit) {
|
||||
RenderedConnection.prototype.neighbours = function(maxLimit) {
|
||||
return this.dbOpposite_.getNeighbours(this, maxLimit);
|
||||
};
|
||||
|
||||
/**
|
||||
* Connect two connections together. This is the connection on the superior
|
||||
* block. Rerender blocks as needed.
|
||||
* @param {!Blockly.Connection} childConnection Connection on inferior block.
|
||||
* @param {!Connection} childConnection Connection on inferior block.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.connect_ = function(childConnection) {
|
||||
Blockly.RenderedConnection.superClass_.connect_.call(this, childConnection);
|
||||
RenderedConnection.prototype.connect_ = function(childConnection) {
|
||||
RenderedConnection.superClass_.connect_.call(this, childConnection);
|
||||
|
||||
var parentConnection = this;
|
||||
var parentBlock = parentConnection.getSourceBlock();
|
||||
var childBlock = childConnection.getSourceBlock();
|
||||
var parentRendered = parentBlock.rendered;
|
||||
var childRendered = childBlock.rendered;
|
||||
const parentConnection = this;
|
||||
const parentBlock = parentConnection.getSourceBlock();
|
||||
const childBlock = childConnection.getSourceBlock();
|
||||
const parentRendered = parentBlock.rendered;
|
||||
const childRendered = childBlock.rendered;
|
||||
|
||||
if (parentRendered) {
|
||||
parentBlock.updateDisabled();
|
||||
@@ -556,8 +550,8 @@ Blockly.RenderedConnection.prototype.connect_ = function(childConnection) {
|
||||
childBlock.updateDisabled();
|
||||
}
|
||||
if (parentRendered && childRendered) {
|
||||
if (parentConnection.type == Blockly.connectionTypes.NEXT_STATEMENT ||
|
||||
parentConnection.type == Blockly.connectionTypes.PREVIOUS_STATEMENT) {
|
||||
if (parentConnection.type == connectionTypes.NEXT_STATEMENT ||
|
||||
parentConnection.type == connectionTypes.PREVIOUS_STATEMENT) {
|
||||
// Child block may need to square off its corners if it is in a stack.
|
||||
// Rendering a child will render its parent.
|
||||
childBlock.render();
|
||||
@@ -569,9 +563,9 @@ Blockly.RenderedConnection.prototype.connect_ = function(childConnection) {
|
||||
}
|
||||
|
||||
// The input the child block is connected to (if any).
|
||||
var parentInput = parentBlock.getInputWithBlock(childBlock);
|
||||
const parentInput = parentBlock.getInputWithBlock(childBlock);
|
||||
if (parentInput) {
|
||||
var visible = parentInput.isVisible();
|
||||
const visible = parentInput.isVisible();
|
||||
childBlock.getSvgRoot().style.display = visible ? 'block' : 'none';
|
||||
}
|
||||
};
|
||||
@@ -580,14 +574,17 @@ Blockly.RenderedConnection.prototype.connect_ = function(childConnection) {
|
||||
* Function to be called when this connection's compatible types have changed.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.RenderedConnection.prototype.onCheckChanged_ = function() {
|
||||
RenderedConnection.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();
|
||||
// Bump away.
|
||||
this.sourceBlock_.bumpNeighbours();
|
||||
}
|
||||
};
|
||||
|
||||
exports = RenderedConnection;
|
||||
|
||||
@@ -10,24 +10,30 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* The top level namespace for block rendering.
|
||||
* @namespace Blockly.blockRendering
|
||||
*/
|
||||
goog.provide('Blockly.blockRendering');
|
||||
goog.module('Blockly.blockRendering');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.registry');
|
||||
|
||||
goog.requireType('Blockly.blockRendering.Renderer');
|
||||
goog.requireType('Blockly.Theme');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Renderer = goog.requireType('Blockly.blockRendering.Renderer');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Theme = goog.requireType('Blockly.Theme');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
* Whether or not the debugger is turned on.
|
||||
* @type {boolean}
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.useDebugger = false;
|
||||
let useDebugger = false;
|
||||
/**
|
||||
* Returns whether the debugger is turned on.
|
||||
* @return {boolean} Whether the debugger is turned on.
|
||||
*/
|
||||
const isDebuggerEnabled = function() {
|
||||
return useDebugger;
|
||||
};
|
||||
/** @package */
|
||||
exports.isDebuggerEnabled = isDebuggerEnabled;
|
||||
|
||||
/**
|
||||
* Registers a new renderer.
|
||||
@@ -36,48 +42,54 @@ Blockly.blockRendering.useDebugger = false;
|
||||
* to register.
|
||||
* @throws {Error} if a renderer with the same name has already been registered.
|
||||
*/
|
||||
Blockly.blockRendering.register = function(name, rendererClass) {
|
||||
Blockly.registry.register(Blockly.registry.Type.RENDERER, name,
|
||||
rendererClass);
|
||||
const register = function(name, rendererClass) {
|
||||
registry.register(registry.Type.RENDERER, name, rendererClass);
|
||||
};
|
||||
exports.register = register;
|
||||
|
||||
/**
|
||||
* Unregisters the renderer registered with the given name.
|
||||
* @param {string} name The name of the renderer.
|
||||
*/
|
||||
Blockly.blockRendering.unregister = function(name) {
|
||||
Blockly.registry.unregister(Blockly.registry.Type.RENDERER, name);
|
||||
const unregister = function(name) {
|
||||
registry.unregister(registry.Type.RENDERER, name);
|
||||
};
|
||||
exports.unregister = unregister;
|
||||
|
||||
/**
|
||||
* Turn on the blocks debugger.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.startDebugger = function() {
|
||||
Blockly.blockRendering.useDebugger = true;
|
||||
const startDebugger = function() {
|
||||
useDebugger = true;
|
||||
};
|
||||
/** @package */
|
||||
exports.startDebugger = startDebugger;
|
||||
|
||||
/**
|
||||
* Turn off the blocks debugger.
|
||||
* @package
|
||||
*/
|
||||
Blockly.blockRendering.stopDebugger = function() {
|
||||
Blockly.blockRendering.useDebugger = false;
|
||||
const stopDebugger = function() {
|
||||
useDebugger = false;
|
||||
};
|
||||
/** @package */
|
||||
exports.stopDebugger = stopDebugger;
|
||||
|
||||
/**
|
||||
* Initialize anything needed for rendering (constants, etc).
|
||||
* @param {!string} name Name of the renderer to initialize.
|
||||
* @param {!Blockly.Theme} theme The workspace theme object.
|
||||
* @param {!Theme} theme The workspace theme object.
|
||||
* @param {Object=} opt_rendererOverrides Rendering constant overrides.
|
||||
* @return {!Blockly.blockRendering.Renderer} The new instance of a renderer.
|
||||
* @return {!Renderer} The new instance of a renderer.
|
||||
* Already initialized.
|
||||
* @package
|
||||
*/
|
||||
|
||||
Blockly.blockRendering.init = function(name, theme, opt_rendererOverrides) {
|
||||
var rendererClass = Blockly.registry.getClass(
|
||||
Blockly.registry.Type.RENDERER, name);
|
||||
var renderer = new rendererClass(name);
|
||||
const init = function(name, theme, opt_rendererOverrides) {
|
||||
const rendererClass = registry.getClass(registry.Type.RENDERER, name);
|
||||
const renderer = new rendererClass(name);
|
||||
renderer.init(theme, opt_rendererOverrides);
|
||||
return renderer;
|
||||
};
|
||||
/** @package */
|
||||
exports.init = init;
|
||||
|
||||
@@ -26,7 +26,7 @@ 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 Row = goog.requireType('Blockly.blockRendering.Row');
|
||||
const Types = goog.require('Blockly.blockRendering.Types');
|
||||
const svgPaths = goog.require('Blockly.utils.svgPaths');
|
||||
|
||||
@@ -73,7 +73,7 @@ Drawer.prototype.draw = function() {
|
||||
if (this.info_.RTL) {
|
||||
this.block_.pathObject.flipRTL();
|
||||
}
|
||||
if (Blockly.blockRendering.useDebugger) {
|
||||
if (Blockly.blockRendering.isDebuggerEnabled()) {
|
||||
this.block_.renderingDebugger.drawDebug(this.block_, this.info_);
|
||||
}
|
||||
this.recordSizeOnBlock_();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user