mirror of
https://github.com/google/blockly.git
synced 2026-01-10 18:37:09 +01:00
Merge branch 'goog_module' into field_textinput
This commit is contained in:
@@ -10,61 +10,63 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.BlockDragger');
|
||||
goog.module('Blockly.BlockDragger');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.blockAnimations');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.constants');
|
||||
goog.require('Blockly.Events');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IBlockDragger = goog.require('Blockly.IBlockDragger');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDragTarget = goog.requireType('Blockly.IDragTarget');
|
||||
const InsertionMarkerManager = goog.require('Blockly.InsertionMarkerManager');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
|
||||
const blockAnimation = goog.require('Blockly.blockAnimations');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const events = goog.require('Blockly.Events');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockDrag');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockMove');
|
||||
goog.require('Blockly.IBlockDragger');
|
||||
goog.require('Blockly.InsertionMarkerManager');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.utils.dom');
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.IDragTarget');
|
||||
goog.requireType('Blockly.WorkspaceSvg');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a block dragger. It moves blocks around the workspace when they
|
||||
* are being dragged by a mouse or touch.
|
||||
* @param {!Blockly.BlockSvg} block The block to drag.
|
||||
* @param {!Blockly.WorkspaceSvg} workspace The workspace to drag on.
|
||||
* @param {!BlockSvg} block The block to drag.
|
||||
* @param {!WorkspaceSvg} workspace The workspace to drag on.
|
||||
* @constructor
|
||||
* @implements {Blockly.IBlockDragger}
|
||||
* @implements {IBlockDragger}
|
||||
*/
|
||||
Blockly.BlockDragger = function(block, workspace) {
|
||||
const BlockDragger = function(block, workspace) {
|
||||
/**
|
||||
* The top block in the stack that is being dragged.
|
||||
* @type {!Blockly.BlockSvg}
|
||||
* @type {!BlockSvg}
|
||||
* @protected
|
||||
*/
|
||||
this.draggingBlock_ = block;
|
||||
|
||||
/**
|
||||
* The workspace on which the block is being dragged.
|
||||
* @type {!Blockly.WorkspaceSvg}
|
||||
* @type {!WorkspaceSvg}
|
||||
* @protected
|
||||
*/
|
||||
this.workspace_ = workspace;
|
||||
|
||||
/**
|
||||
* Object that keeps track of connections on dragged blocks.
|
||||
* @type {!Blockly.InsertionMarkerManager}
|
||||
* @type {!InsertionMarkerManager}
|
||||
* @protected
|
||||
*/
|
||||
this.draggedConnectionManager_ =
|
||||
new Blockly.InsertionMarkerManager(this.draggingBlock_);
|
||||
new InsertionMarkerManager(this.draggingBlock_);
|
||||
|
||||
/**
|
||||
* Which drag area the mouse pointer is over, if any.
|
||||
* @type {?Blockly.IDragTarget}
|
||||
* @type {?IDragTarget}
|
||||
* @private
|
||||
*/
|
||||
this.dragTarget_ = null;
|
||||
@@ -79,7 +81,7 @@ Blockly.BlockDragger = function(block, workspace) {
|
||||
/**
|
||||
* The location of the top left corner of the dragging block at the beginning
|
||||
* of the drag in workspace coordinates.
|
||||
* @type {!Blockly.utils.Coordinate}
|
||||
* @type {!Coordinate}
|
||||
* @protected
|
||||
*/
|
||||
this.startXY_ = this.draggingBlock_.getRelativeToSurfaceXY();
|
||||
@@ -91,14 +93,14 @@ Blockly.BlockDragger = function(block, workspace) {
|
||||
* @type {Array<!Object>}
|
||||
* @protected
|
||||
*/
|
||||
this.dragIconData_ = Blockly.BlockDragger.initIconData_(block);
|
||||
this.dragIconData_ = initIconData(block);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sever all links from this object.
|
||||
* @package
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.dispose = function() {
|
||||
BlockDragger.prototype.dispose = function() {
|
||||
this.dragIconData_.length = 0;
|
||||
|
||||
if (this.draggedConnectionManager_) {
|
||||
@@ -110,19 +112,19 @@ Blockly.BlockDragger.prototype.dispose = function() {
|
||||
* Make a list of all of the icons (comment, warning, and mutator) that are
|
||||
* on this block and its descendants. Moving an icon moves the bubble that
|
||||
* extends from it if that bubble is open.
|
||||
* @param {!Blockly.BlockSvg} block The root block that is being dragged.
|
||||
* @param {!BlockSvg} block The root block that is being dragged.
|
||||
* @return {!Array<!Object>} The list of all icons and their locations.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BlockDragger.initIconData_ = function(block) {
|
||||
const initIconData = function(block) {
|
||||
// Build a list of icons that need to be moved and where they started.
|
||||
var dragIconData = [];
|
||||
var descendants = block.getDescendants(false);
|
||||
for (var i = 0, descendant; (descendant = descendants[i]); i++) {
|
||||
var icons = descendant.getIcons();
|
||||
for (var j = 0; j < icons.length; j++) {
|
||||
var data = {
|
||||
// Blockly.utils.Coordinate with x and y properties (workspace
|
||||
const dragIconData = [];
|
||||
const descendants = block.getDescendants(false);
|
||||
|
||||
for (let i = 0, descendant; (descendant = descendants[i]); i++) {
|
||||
const icons = descendant.getIcons();
|
||||
for (let j = 0; j < icons.length; j++) {
|
||||
const data = {
|
||||
// Coordinate with x and y properties (workspace
|
||||
// coordinates).
|
||||
location: icons[j].getIconLocation(),
|
||||
// Blockly.Icon
|
||||
@@ -136,16 +138,15 @@ Blockly.BlockDragger.initIconData_ = function(block) {
|
||||
|
||||
/**
|
||||
* Start dragging a block. This includes moving it to the drag surface.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the position at mouse down, in pixel units.
|
||||
* @param {boolean} healStack Whether or not to heal the stack after
|
||||
* disconnecting.
|
||||
* @public
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.startDrag = function(
|
||||
currentDragDeltaXY, healStack) {
|
||||
if (!Blockly.Events.getGroup()) {
|
||||
Blockly.Events.setGroup(true);
|
||||
BlockDragger.prototype.startDrag = function(currentDragDeltaXY, healStack) {
|
||||
if (!events.getGroup()) {
|
||||
events.setGroup(true);
|
||||
}
|
||||
this.fireDragStartEvent_();
|
||||
|
||||
@@ -159,9 +160,9 @@ Blockly.BlockDragger.prototype.startDrag = function(
|
||||
|
||||
// During a drag there may be a lot of rerenders, but not field changes.
|
||||
// Turn the cache on so we don't do spurious remeasures during the drag.
|
||||
Blockly.utils.dom.startTextWidthCache();
|
||||
dom.startTextWidthCache();
|
||||
this.workspace_.setResizesEnabled(false);
|
||||
Blockly.blockAnimations.disconnectUiStop();
|
||||
blockAnimation.disconnectUiStop();
|
||||
|
||||
if (this.shouldDisconnect_(healStack)) {
|
||||
this.disconnectBlock_(healStack, currentDragDeltaXY);
|
||||
@@ -180,9 +181,9 @@ Blockly.BlockDragger.prototype.startDrag = function(
|
||||
* @return {boolean} True to disconnect the block, false otherwise.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.shouldDisconnect_ = function(healStack) {
|
||||
BlockDragger.prototype.shouldDisconnect_ = function(healStack) {
|
||||
return !!(
|
||||
this.draggingBlock_.getParent() ||
|
||||
this.draggingBlock_.getParent() ||
|
||||
(healStack && this.draggingBlock_.nextConnection &&
|
||||
this.draggingBlock_.nextConnection.targetBlock()));
|
||||
};
|
||||
@@ -191,18 +192,18 @@ Blockly.BlockDragger.prototype.shouldDisconnect_ = function(healStack) {
|
||||
* Disconnects the block and moves it to a new location.
|
||||
* @param {boolean} healStack Whether or not to heal the stack after
|
||||
* disconnecting.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the position at mouse down, in pixel units.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.disconnectBlock_ = function(
|
||||
BlockDragger.prototype.disconnectBlock_ = function(
|
||||
healStack, currentDragDeltaXY) {
|
||||
this.draggingBlock_.unplug(healStack);
|
||||
var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
|
||||
var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta);
|
||||
const delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
|
||||
const newLoc = Coordinate.sum(this.startXY_, delta);
|
||||
|
||||
this.draggingBlock_.translate(newLoc.x, newLoc.y);
|
||||
Blockly.blockAnimations.disconnectUiEffect(this.draggingBlock_);
|
||||
blockAnimation.disconnectUiEffect(this.draggingBlock_);
|
||||
this.draggedConnectionManager_.updateAvailableConnections();
|
||||
};
|
||||
|
||||
@@ -210,31 +211,31 @@ Blockly.BlockDragger.prototype.disconnectBlock_ = function(
|
||||
* Fire a UI event at the start of a block drag.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.fireDragStartEvent_ = function() {
|
||||
var event = new (Blockly.Events.get(Blockly.Events.BLOCK_DRAG))(
|
||||
BlockDragger.prototype.fireDragStartEvent_ = function() {
|
||||
const event = new (events.get(events.BLOCK_DRAG))(
|
||||
this.draggingBlock_, true, this.draggingBlock_.getDescendants(false));
|
||||
Blockly.Events.fire(event);
|
||||
events.fire(event);
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a step of block dragging, based on the given event. Update the
|
||||
* display accordingly.
|
||||
* @param {!Event} e The most recent move event.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the position at the start of the drag, in pixel units.
|
||||
* @public
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.drag = function(e, currentDragDeltaXY) {
|
||||
var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
|
||||
var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta);
|
||||
BlockDragger.prototype.drag = function(e, currentDragDeltaXY) {
|
||||
const delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
|
||||
const newLoc = Coordinate.sum(this.startXY_, delta);
|
||||
this.draggingBlock_.moveDuringDrag(newLoc);
|
||||
this.dragIcons_(delta);
|
||||
|
||||
var oldDragTarget = this.dragTarget_;
|
||||
const oldDragTarget = this.dragTarget_;
|
||||
this.dragTarget_ = this.workspace_.getDragTarget(e);
|
||||
|
||||
this.draggedConnectionManager_.update(delta, this.dragTarget_);
|
||||
var oldWouldDeleteBlock = this.wouldDeleteBlock_;
|
||||
const oldWouldDeleteBlock = this.wouldDeleteBlock_;
|
||||
this.wouldDeleteBlock_ = this.draggedConnectionManager_.wouldDeleteBlock();
|
||||
if (oldWouldDeleteBlock != this.wouldDeleteBlock_) {
|
||||
// Prevent unnecessary add/remove class calls.
|
||||
@@ -253,26 +254,26 @@ Blockly.BlockDragger.prototype.drag = function(e, currentDragDeltaXY) {
|
||||
/**
|
||||
* Finish a block drag and put the block back on the workspace.
|
||||
* @param {!Event} e The mouseup/touchend event.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the position at the start of the drag, in pixel units.
|
||||
* @public
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.endDrag = function(e, currentDragDeltaXY) {
|
||||
BlockDragger.prototype.endDrag = function(e, currentDragDeltaXY) {
|
||||
// Make sure internal state is fresh.
|
||||
this.drag(e, currentDragDeltaXY);
|
||||
this.dragIconData_ = [];
|
||||
this.fireDragEndEvent_();
|
||||
|
||||
Blockly.utils.dom.stopTextWidthCache();
|
||||
dom.stopTextWidthCache();
|
||||
|
||||
Blockly.blockAnimations.disconnectUiStop();
|
||||
blockAnimation.disconnectUiStop();
|
||||
|
||||
var preventMove = !!this.dragTarget_ &&
|
||||
const preventMove = !!this.dragTarget_ &&
|
||||
this.dragTarget_.shouldPreventMove(this.draggingBlock_);
|
||||
if (preventMove) {
|
||||
var newLoc = this.startXY_;
|
||||
} else {
|
||||
var newValues = this.getNewLocationAfterDrag_(currentDragDeltaXY);
|
||||
const newValues = this.getNewLocationAfterDrag_(currentDragDeltaXY);
|
||||
var delta = newValues.delta;
|
||||
var newLoc = newValues.newLocation;
|
||||
}
|
||||
@@ -282,7 +283,7 @@ Blockly.BlockDragger.prototype.endDrag = function(e, currentDragDeltaXY) {
|
||||
this.dragTarget_.onDrop(this.draggingBlock_);
|
||||
}
|
||||
|
||||
var deleted = this.maybeDeleteBlock_();
|
||||
const deleted = this.maybeDeleteBlock_();
|
||||
if (!deleted) {
|
||||
// These are expensive and don't need to be done if we're deleting.
|
||||
this.draggingBlock_.setDragging(false);
|
||||
@@ -299,25 +300,23 @@ Blockly.BlockDragger.prototype.endDrag = function(e, currentDragDeltaXY) {
|
||||
}
|
||||
this.workspace_.setResizesEnabled(true);
|
||||
|
||||
Blockly.Events.setGroup(false);
|
||||
events.setGroup(false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates the drag delta and new location values after a block is dragged.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the start of the drag, in pixel units.
|
||||
* @return {{delta: !Blockly.utils.Coordinate, newLocation:
|
||||
* !Blockly.utils.Coordinate}} New location after drag. delta is in
|
||||
* @return {{delta: !Coordinate, newLocation:
|
||||
* !Coordinate}} New location after drag. delta is in
|
||||
* workspace units. newLocation is the new coordinate where the block should
|
||||
* end up.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.getNewLocationAfterDrag_ = function(
|
||||
currentDragDeltaXY) {
|
||||
var newValues = {};
|
||||
BlockDragger.prototype.getNewLocationAfterDrag_ = function(currentDragDeltaXY) {
|
||||
const newValues = {};
|
||||
newValues.delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
|
||||
newValues.newLocation =
|
||||
Blockly.utils.Coordinate.sum(this.startXY_, newValues.delta);
|
||||
newValues.newLocation = Coordinate.sum(this.startXY_, newValues.delta);
|
||||
return newValues;
|
||||
};
|
||||
|
||||
@@ -328,7 +327,7 @@ Blockly.BlockDragger.prototype.getNewLocationAfterDrag_ = function(
|
||||
* @return {boolean} True if the block was deleted.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.maybeDeleteBlock_ = function() {
|
||||
BlockDragger.prototype.maybeDeleteBlock_ = function() {
|
||||
if (this.wouldDeleteBlock_) {
|
||||
// Fire a move event, so we know where to go back to for an undo.
|
||||
this.fireMoveEvent_();
|
||||
@@ -341,11 +340,11 @@ Blockly.BlockDragger.prototype.maybeDeleteBlock_ = function() {
|
||||
|
||||
/**
|
||||
* Updates the necessary information to place a block at a certain location.
|
||||
* @param {!Blockly.utils.Coordinate} delta The change in location from where
|
||||
* @param {!Coordinate} delta The change in location from where
|
||||
* the block started the drag to where it ended the drag.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.updateBlockAfterMove_ = function(delta) {
|
||||
BlockDragger.prototype.updateBlockAfterMove_ = function(delta) {
|
||||
this.draggingBlock_.moveConnections(delta.x, delta.y);
|
||||
this.fireMoveEvent_();
|
||||
if (this.draggedConnectionManager_.wouldConnectBlock()) {
|
||||
@@ -361,10 +360,10 @@ Blockly.BlockDragger.prototype.updateBlockAfterMove_ = function(delta) {
|
||||
* Fire a UI event at the end of a block drag.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.fireDragEndEvent_ = function() {
|
||||
var event = new (Blockly.Events.get(Blockly.Events.BLOCK_DRAG))(
|
||||
BlockDragger.prototype.fireDragEndEvent_ = function() {
|
||||
const event = new (events.get(events.BLOCK_DRAG))(
|
||||
this.draggingBlock_, false, this.draggingBlock_.getDescendants(false));
|
||||
Blockly.Events.fire(event);
|
||||
events.fire(event);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -374,12 +373,12 @@ Blockly.BlockDragger.prototype.fireDragEndEvent_ = function() {
|
||||
* @param {boolean} isEnd True if we are at the end of a drag, false otherwise.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.updateToolboxStyle_ = function(isEnd) {
|
||||
var toolbox = this.workspace_.getToolbox();
|
||||
BlockDragger.prototype.updateToolboxStyle_ = function(isEnd) {
|
||||
const toolbox = this.workspace_.getToolbox();
|
||||
|
||||
if (toolbox) {
|
||||
var style = this.draggingBlock_.isDeletable() ? 'blocklyToolboxDelete' :
|
||||
'blocklyToolboxGrab';
|
||||
const style = this.draggingBlock_.isDeletable() ? 'blocklyToolboxDelete' :
|
||||
'blocklyToolboxGrab';
|
||||
|
||||
if (isEnd && typeof toolbox.removeStyle == 'function') {
|
||||
toolbox.removeStyle(style);
|
||||
@@ -394,12 +393,11 @@ Blockly.BlockDragger.prototype.updateToolboxStyle_ = function(isEnd) {
|
||||
* Fire a move event at the end of a block drag.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.fireMoveEvent_ = function() {
|
||||
var event =
|
||||
new (Blockly.Events.get(Blockly.Events.BLOCK_MOVE))(this.draggingBlock_);
|
||||
BlockDragger.prototype.fireMoveEvent_ = function() {
|
||||
const event = new (events.get(events.BLOCK_MOVE))(this.draggingBlock_);
|
||||
event.oldCoordinate = this.startXY_;
|
||||
event.recordNew();
|
||||
Blockly.Events.fire(event);
|
||||
events.fire(event);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -407,7 +405,7 @@ Blockly.BlockDragger.prototype.fireMoveEvent_ = function() {
|
||||
* dragging block would be deleted if released immediately.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.updateCursorDuringBlockDrag_ = function() {
|
||||
BlockDragger.prototype.updateCursorDuringBlockDrag_ = function() {
|
||||
this.draggingBlock_.setDeleteStyle(this.wouldDeleteBlock_);
|
||||
};
|
||||
|
||||
@@ -416,14 +414,14 @@ Blockly.BlockDragger.prototype.updateCursorDuringBlockDrag_ = function() {
|
||||
* correction for mutator workspaces.
|
||||
* This function does not consider differing origins. It simply scales the
|
||||
* input's x and y values.
|
||||
* @param {!Blockly.utils.Coordinate} pixelCoord A coordinate with x and y
|
||||
* @param {!Coordinate} pixelCoord A coordinate with x and y
|
||||
* values in CSS pixel units.
|
||||
* @return {!Blockly.utils.Coordinate} The input coordinate divided by the
|
||||
* @return {!Coordinate} The input coordinate divided by the
|
||||
* workspace scale.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) {
|
||||
var result = new Blockly.utils.Coordinate(
|
||||
BlockDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) {
|
||||
const result = new Coordinate(
|
||||
pixelCoord.x / this.workspace_.scale,
|
||||
pixelCoord.y / this.workspace_.scale);
|
||||
if (this.workspace_.isMutator) {
|
||||
@@ -431,7 +429,7 @@ Blockly.BlockDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) {
|
||||
// oddities in our rendering optimizations. The actual scale is the same as
|
||||
// the scale on the parent workspace.
|
||||
// Fix that for dragging.
|
||||
var mainScale = this.workspace_.options.parentWorkspace.scale;
|
||||
const mainScale = this.workspace_.options.parentWorkspace.scale;
|
||||
result.scale(1 / mainScale);
|
||||
}
|
||||
return result;
|
||||
@@ -439,26 +437,26 @@ Blockly.BlockDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) {
|
||||
|
||||
/**
|
||||
* Move all of the icons connected to this drag.
|
||||
* @param {!Blockly.utils.Coordinate} dxy How far to move the icons from their
|
||||
* @param {!Coordinate} dxy How far to move the icons from their
|
||||
* original positions, in workspace units.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.dragIcons_ = function(dxy) {
|
||||
BlockDragger.prototype.dragIcons_ = function(dxy) {
|
||||
// Moving icons moves their associated bubbles.
|
||||
for (var i = 0; i < this.dragIconData_.length; i++) {
|
||||
var data = this.dragIconData_[i];
|
||||
data.icon.setIconLocation(Blockly.utils.Coordinate.sum(data.location, dxy));
|
||||
for (let i = 0; i < this.dragIconData_.length; i++) {
|
||||
const data = this.dragIconData_[i];
|
||||
data.icon.setIconLocation(Coordinate.sum(data.location, dxy));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a list of the insertion markers that currently exist. Drags have 0, 1,
|
||||
* or 2 insertion markers.
|
||||
* @return {!Array<!Blockly.BlockSvg>} A possibly empty list of insertion
|
||||
* @return {!Array<!BlockSvg>} A possibly empty list of insertion
|
||||
* marker blocks.
|
||||
* @public
|
||||
*/
|
||||
Blockly.BlockDragger.prototype.getInsertionMarkers = function() {
|
||||
BlockDragger.prototype.getInsertionMarkers = function() {
|
||||
// No insertion markers with the old style of dragged connection managers.
|
||||
if (this.draggedConnectionManager_ &&
|
||||
this.draggedConnectionManager_.getInsertionMarkers) {
|
||||
@@ -467,6 +465,6 @@ Blockly.BlockDragger.prototype.getInsertionMarkers = function() {
|
||||
return [];
|
||||
};
|
||||
|
||||
Blockly.registry.register(
|
||||
Blockly.registry.Type.BLOCK_DRAGGER, Blockly.registry.DEFAULT,
|
||||
Blockly.BlockDragger);
|
||||
registry.register(registry.Type.BLOCK_DRAGGER, registry.DEFAULT, BlockDragger);
|
||||
|
||||
exports = BlockDragger;
|
||||
|
||||
@@ -12,23 +12,26 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.DeleteArea');
|
||||
goog.module('Blockly.DeleteArea');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.BlockSvg');
|
||||
goog.require('Blockly.DragTarget');
|
||||
goog.require('Blockly.IDeleteArea');
|
||||
|
||||
goog.requireType('Blockly.IDraggable');
|
||||
const BlockSvg = goog.require('Blockly.BlockSvg');
|
||||
const DragTarget = goog.require('Blockly.DragTarget');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDeleteArea = goog.require('Blockly.IDeleteArea');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IDraggable = goog.requireType('Blockly.IDraggable');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
|
||||
/**
|
||||
* Abstract class for a component that can delete a block or bubble that is
|
||||
* dropped on top of it.
|
||||
* @extends {Blockly.DragTarget}
|
||||
* @implements {Blockly.IDeleteArea}
|
||||
* @extends {DragTarget}
|
||||
* @implements {IDeleteArea}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.DeleteArea = function() {
|
||||
Blockly.DeleteArea.superClass_.constructor.call(this);
|
||||
const DeleteArea = function() {
|
||||
DeleteArea.superClass_.constructor.call(this);
|
||||
|
||||
/**
|
||||
* Whether the last block or bubble dragged over this delete area would be
|
||||
@@ -39,24 +42,24 @@ Blockly.DeleteArea = function() {
|
||||
*/
|
||||
this.wouldDelete_ = false;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.DeleteArea, Blockly.DragTarget);
|
||||
inherits(DeleteArea, DragTarget);
|
||||
|
||||
/**
|
||||
* Returns whether the provided block or bubble would be deleted if dropped on
|
||||
* this area.
|
||||
* This method should check if the element is deletable and is always called
|
||||
* before onDragEnter/onDragOver/onDragExit.
|
||||
* @param {!Blockly.IDraggable} element The block or bubble currently being
|
||||
* @param {!IDraggable} element The block or bubble currently being
|
||||
* dragged.
|
||||
* @param {boolean} couldConnect Whether the element could could connect to
|
||||
* another.
|
||||
* @return {boolean} Whether the element provided would be deleted if dropped on
|
||||
* this area.
|
||||
*/
|
||||
Blockly.DeleteArea.prototype.wouldDelete = function(element, couldConnect) {
|
||||
if (element instanceof Blockly.BlockSvg) {
|
||||
var block = /** @type {Blockly.BlockSvg} */ (element);
|
||||
var couldDeleteBlock = !block.getParent() && block.isDeletable();
|
||||
DeleteArea.prototype.wouldDelete = function(element, couldConnect) {
|
||||
if (element instanceof BlockSvg) {
|
||||
const block = /** @type {BlockSvg} */ (element);
|
||||
const couldDeleteBlock = !block.getParent() && block.isDeletable();
|
||||
this.updateWouldDelete_(couldDeleteBlock && !couldConnect);
|
||||
} else {
|
||||
this.updateWouldDelete_(element.isDeletable());
|
||||
@@ -69,6 +72,8 @@ Blockly.DeleteArea.prototype.wouldDelete = function(element, couldConnect) {
|
||||
* @param {boolean} wouldDelete The new value for the wouldDelete state.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.DeleteArea.prototype.updateWouldDelete_ = function(wouldDelete) {
|
||||
DeleteArea.prototype.updateWouldDelete_ = function(wouldDelete) {
|
||||
this.wouldDelete_ = wouldDelete;
|
||||
};
|
||||
|
||||
exports = DeleteArea;
|
||||
|
||||
@@ -10,15 +10,16 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.FieldImage');
|
||||
goog.module('Blockly.FieldImage');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Field');
|
||||
goog.require('Blockly.fieldRegistry');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.utils.Size');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
const Field = goog.require('Blockly.Field');
|
||||
const Size = goog.require('Blockly.utils.Size');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
||||
const {createSvgElement, XLINK_NS} = goog.require('Blockly.utils.dom');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
const {replaceMessageReferences} = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
@@ -27,32 +28,35 @@ goog.require('Blockly.utils.Svg');
|
||||
* @param {!(string|number)} width Width of the image.
|
||||
* @param {!(string|number)} height Height of the image.
|
||||
* @param {string=} opt_alt Optional alt text for when block is collapsed.
|
||||
* @param {function(!Blockly.FieldImage)=} opt_onClick Optional function to be
|
||||
* @param {function(!FieldImage)=} opt_onClick Optional function to be
|
||||
* called when the image is clicked. If opt_onClick is defined, opt_alt must
|
||||
* also be defined.
|
||||
* @param {boolean=} opt_flipRtl Whether to flip the icon in RTL.
|
||||
* @param {Object=} opt_config A map of options used to configure the field.
|
||||
* See the [field creation documentation]{@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/image#creation}
|
||||
* See the [field creation documentation]{@link
|
||||
* https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/image#creation}
|
||||
* for a list of properties this parameter supports.
|
||||
* @extends {Blockly.Field}
|
||||
* @extends {Field}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldImage = function(src, width, height,
|
||||
opt_alt, opt_onClick, opt_flipRtl, opt_config) {
|
||||
const FieldImage = function(
|
||||
src, width, height, opt_alt, opt_onClick, opt_flipRtl, opt_config) {
|
||||
// Return early.
|
||||
if (!src) {
|
||||
throw Error('Src value of an image field is required');
|
||||
}
|
||||
src = Blockly.utils.replaceMessageReferences(src);
|
||||
var imageHeight = Number(Blockly.utils.replaceMessageReferences(height));
|
||||
var imageWidth = Number(Blockly.utils.replaceMessageReferences(width));
|
||||
src = replaceMessageReferences(src);
|
||||
const imageHeight = Number(replaceMessageReferences(height));
|
||||
const imageWidth = Number(replaceMessageReferences(width));
|
||||
if (isNaN(imageHeight) || isNaN(imageWidth)) {
|
||||
throw Error('Height and width values of an image field must cast to' +
|
||||
' numbers.');
|
||||
throw Error(
|
||||
'Height and width values of an image field must cast to' +
|
||||
' numbers.');
|
||||
}
|
||||
if (imageHeight <= 0 || imageWidth <= 0) {
|
||||
throw Error('Height and width values of an image field must be greater' +
|
||||
' than 0.');
|
||||
throw Error(
|
||||
'Height and width values of an image field must be greater' +
|
||||
' than 0.');
|
||||
}
|
||||
|
||||
// Initialize configurable properties.
|
||||
@@ -70,23 +74,21 @@ Blockly.FieldImage = function(src, width, height,
|
||||
*/
|
||||
this.altText_ = '';
|
||||
|
||||
Blockly.FieldImage.superClass_.constructor.call(
|
||||
this, src, null, opt_config);
|
||||
FieldImage.superClass_.constructor.call(this, src, null, opt_config);
|
||||
|
||||
if (!opt_config) { // If the config wasn't passed, do old configuration.
|
||||
this.flipRtl_ = !!opt_flipRtl;
|
||||
this.altText_ = Blockly.utils.replaceMessageReferences(opt_alt) || '';
|
||||
this.altText_ = replaceMessageReferences(opt_alt) || '';
|
||||
}
|
||||
|
||||
// Initialize other properties.
|
||||
/**
|
||||
* The size of the area rendered by the field.
|
||||
* @type {Blockly.utils.Size}
|
||||
* @type {Size}
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
this.size_ = new Blockly.utils.Size(imageWidth,
|
||||
imageHeight + Blockly.FieldImage.Y_PADDING);
|
||||
this.size_ = new Size(imageWidth, imageHeight + FieldImage.Y_PADDING);
|
||||
|
||||
/**
|
||||
* Store the image height, since it is different from the field height.
|
||||
@@ -97,7 +99,7 @@ Blockly.FieldImage = function(src, width, height,
|
||||
|
||||
/**
|
||||
* The function to be called when this field is clicked.
|
||||
* @type {?function(!Blockly.FieldImage)}
|
||||
* @type {?function(!FieldImage)}
|
||||
* @private
|
||||
*/
|
||||
this.clickHandler_ = null;
|
||||
@@ -113,29 +115,30 @@ Blockly.FieldImage = function(src, width, height,
|
||||
*/
|
||||
this.imageElement_ = null;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.FieldImage, Blockly.Field);
|
||||
inherits(FieldImage, Field);
|
||||
|
||||
/**
|
||||
* The default value for this field.
|
||||
* @type {*}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldImage.prototype.DEFAULT_VALUE = '';
|
||||
FieldImage.prototype.DEFAULT_VALUE = '';
|
||||
|
||||
/**
|
||||
* Construct a FieldImage from a JSON arg object,
|
||||
* dereferencing any string table references.
|
||||
* @param {!Object} options A JSON object with options (src, width, height,
|
||||
* alt, and flipRtl).
|
||||
* @return {!Blockly.FieldImage} The new field instance.
|
||||
* @return {!FieldImage} The new field instance.
|
||||
* @package
|
||||
* @nocollapse
|
||||
*/
|
||||
Blockly.FieldImage.fromJson = function(options) {
|
||||
FieldImage.fromJson = function(options) {
|
||||
// `this` might be a subclass of FieldImage if that class doesn't override
|
||||
// the static fromJson method.
|
||||
return new this(options['src'], options['width'], options['height'],
|
||||
undefined, undefined, undefined, options);
|
||||
return new this(
|
||||
options['src'], options['width'], options['height'], undefined, undefined,
|
||||
undefined, options);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -144,14 +147,14 @@ Blockly.FieldImage.fromJson = function(options) {
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldImage.Y_PADDING = 1;
|
||||
FieldImage.Y_PADDING = 1;
|
||||
|
||||
/**
|
||||
* Editable fields usually show some sort of UI indicating they are
|
||||
* editable. This field should not.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.FieldImage.prototype.EDITABLE = false;
|
||||
FieldImage.prototype.EDITABLE = false;
|
||||
|
||||
/**
|
||||
* Used to tell if the field needs to be rendered the next time the block is
|
||||
@@ -160,7 +163,7 @@ Blockly.FieldImage.prototype.EDITABLE = false;
|
||||
* @type {boolean}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldImage.prototype.isDirty_ = false;
|
||||
FieldImage.prototype.isDirty_ = false;
|
||||
|
||||
/**
|
||||
* Configure the field based on the given map of options.
|
||||
@@ -168,27 +171,26 @@ Blockly.FieldImage.prototype.isDirty_ = false;
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldImage.prototype.configure_ = function(config) {
|
||||
Blockly.FieldImage.superClass_.configure_.call(this, config);
|
||||
FieldImage.prototype.configure_ = function(config) {
|
||||
FieldImage.superClass_.configure_.call(this, config);
|
||||
this.flipRtl_ = !!config['flipRtl'];
|
||||
this.altText_ = Blockly.utils.replaceMessageReferences(config['alt']) || '';
|
||||
this.altText_ = replaceMessageReferences(config['alt']) || '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the block UI for this image.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldImage.prototype.initView = function() {
|
||||
this.imageElement_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.IMAGE,
|
||||
{
|
||||
FieldImage.prototype.initView = function() {
|
||||
this.imageElement_ = createSvgElement(
|
||||
Svg.IMAGE, {
|
||||
'height': this.imageHeight_ + 'px',
|
||||
'width': this.size_.width + 'px',
|
||||
'alt': this.altText_
|
||||
},
|
||||
this.fieldGroup_);
|
||||
this.imageElement_.setAttributeNS(Blockly.utils.dom.XLINK_NS,
|
||||
'xlink:href', /** @type {string} */ (this.value_));
|
||||
this.imageElement_.setAttributeNS(
|
||||
XLINK_NS, 'xlink:href', /** @type {string} */ (this.value_));
|
||||
|
||||
if (this.clickHandler_) {
|
||||
this.imageElement_.style.cursor = 'pointer';
|
||||
@@ -198,7 +200,7 @@ Blockly.FieldImage.prototype.initView = function() {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldImage.prototype.updateSize_ = function() {
|
||||
FieldImage.prototype.updateSize_ = function() {
|
||||
// NOP
|
||||
};
|
||||
|
||||
@@ -208,7 +210,7 @@ Blockly.FieldImage.prototype.updateSize_ = function() {
|
||||
* @return {?string} A string, or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldImage.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
FieldImage.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
if (typeof opt_newValue != 'string') {
|
||||
return null;
|
||||
}
|
||||
@@ -221,11 +223,11 @@ Blockly.FieldImage.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
* that this is a string.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldImage.prototype.doValueUpdate_ = function(newValue) {
|
||||
FieldImage.prototype.doValueUpdate_ = function(newValue) {
|
||||
this.value_ = newValue;
|
||||
if (this.imageElement_) {
|
||||
this.imageElement_.setAttributeNS(Blockly.utils.dom.XLINK_NS,
|
||||
'xlink:href', String(this.value_));
|
||||
this.imageElement_.setAttributeNS(
|
||||
XLINK_NS, 'xlink:href', String(this.value_));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -234,7 +236,7 @@ Blockly.FieldImage.prototype.doValueUpdate_ = function(newValue) {
|
||||
* @return {boolean} True if we should flip in RTL.
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldImage.prototype.getFlipRtl = function() {
|
||||
FieldImage.prototype.getFlipRtl = function() {
|
||||
return this.flipRtl_;
|
||||
};
|
||||
|
||||
@@ -243,7 +245,7 @@ Blockly.FieldImage.prototype.getFlipRtl = function() {
|
||||
* @param {?string} alt New alt text.
|
||||
* @public
|
||||
*/
|
||||
Blockly.FieldImage.prototype.setAlt = function(alt) {
|
||||
FieldImage.prototype.setAlt = function(alt) {
|
||||
if (alt == this.altText_) {
|
||||
return;
|
||||
}
|
||||
@@ -258,7 +260,7 @@ Blockly.FieldImage.prototype.setAlt = function(alt) {
|
||||
* call the handler.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldImage.prototype.showEditor_ = function() {
|
||||
FieldImage.prototype.showEditor_ = function() {
|
||||
if (this.clickHandler_) {
|
||||
this.clickHandler_(this);
|
||||
}
|
||||
@@ -266,10 +268,10 @@ Blockly.FieldImage.prototype.showEditor_ = function() {
|
||||
|
||||
/**
|
||||
* Set the function that is called when this image is clicked.
|
||||
* @param {?function(!Blockly.FieldImage)} func The function that is called
|
||||
* @param {?function(!FieldImage)} func The function that is called
|
||||
* when the image is clicked, or null to remove.
|
||||
*/
|
||||
Blockly.FieldImage.prototype.setOnClickHandler = function(func) {
|
||||
FieldImage.prototype.setOnClickHandler = function(func) {
|
||||
this.clickHandler_ = func;
|
||||
};
|
||||
|
||||
@@ -281,8 +283,10 @@ Blockly.FieldImage.prototype.setOnClickHandler = function(func) {
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldImage.prototype.getText_ = function() {
|
||||
FieldImage.prototype.getText_ = function() {
|
||||
return this.altText_;
|
||||
};
|
||||
|
||||
Blockly.fieldRegistry.register('field_image', Blockly.FieldImage);
|
||||
fieldRegistry.register('field_image', FieldImage);
|
||||
|
||||
exports = FieldImage;
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.FieldLabelSerializable');
|
||||
goog.module('Blockly.FieldLabelSerializable');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.FieldLabel');
|
||||
goog.require('Blockly.fieldRegistry');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.object');
|
||||
const FieldLabel = goog.require('Blockly.FieldLabel');
|
||||
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
const {replaceMessageReferences} = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
@@ -25,29 +26,29 @@ goog.require('Blockly.utils.object');
|
||||
* string. Defaults to an empty string if null or undefined.
|
||||
* @param {string=} opt_class Optional CSS class for the field's text.
|
||||
* @param {Object=} opt_config A map of options used to configure the field.
|
||||
* See the [field creation documentation]{@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/label-serializable#creation}
|
||||
* See the [field creation documentation]{@link
|
||||
* https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/label-serializable#creation}
|
||||
* for a list of properties this parameter supports.
|
||||
* @extends {Blockly.FieldLabel}
|
||||
* @extends {FieldLabel}
|
||||
* @constructor
|
||||
*
|
||||
*/
|
||||
Blockly.FieldLabelSerializable = function(opt_value, opt_class, opt_config) {
|
||||
Blockly.FieldLabelSerializable.superClass_.constructor.call(
|
||||
const FieldLabelSerializable = function(opt_value, opt_class, opt_config) {
|
||||
FieldLabelSerializable.superClass_.constructor.call(
|
||||
this, opt_value, opt_class, opt_config);
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.FieldLabelSerializable,
|
||||
Blockly.FieldLabel);
|
||||
inherits(FieldLabelSerializable, FieldLabel);
|
||||
|
||||
/**
|
||||
* Construct a FieldLabelSerializable from a JSON arg object,
|
||||
* dereferencing any string table references.
|
||||
* @param {!Object} options A JSON object with options (text, and class).
|
||||
* @return {!Blockly.FieldLabelSerializable} The new field instance.
|
||||
* @return {!FieldLabelSerializable} The new field instance.
|
||||
* @package
|
||||
* @nocollapse
|
||||
*/
|
||||
Blockly.FieldLabelSerializable.fromJson = function(options) {
|
||||
var text = Blockly.utils.replaceMessageReferences(options['text']);
|
||||
FieldLabelSerializable.fromJson = function(options) {
|
||||
const text = replaceMessageReferences(options['text']);
|
||||
// `this` might be a subclass of FieldLabelSerializable if that class doesn't
|
||||
// override the static fromJson method.
|
||||
return new this(text, undefined, options);
|
||||
@@ -58,14 +59,15 @@ Blockly.FieldLabelSerializable.fromJson = function(options) {
|
||||
* editable. This field should not.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.FieldLabelSerializable.prototype.EDITABLE = false;
|
||||
FieldLabelSerializable.prototype.EDITABLE = false;
|
||||
|
||||
/**
|
||||
* Serializable fields are saved by the XML renderer, non-serializable fields
|
||||
* are not. This field should be serialized, but only edited programmatically.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.FieldLabelSerializable.prototype.SERIALIZABLE = true;
|
||||
FieldLabelSerializable.prototype.SERIALIZABLE = true;
|
||||
|
||||
Blockly.fieldRegistry.register(
|
||||
'field_label_serializable', Blockly.FieldLabelSerializable);
|
||||
fieldRegistry.register('field_label_serializable', FieldLabelSerializable);
|
||||
|
||||
exports = FieldLabelSerializable;
|
||||
|
||||
@@ -12,20 +12,21 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.FieldMultilineInput');
|
||||
goog.module('Blockly.FieldMultilineInput');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Css');
|
||||
goog.require('Blockly.Field');
|
||||
goog.require('Blockly.fieldRegistry');
|
||||
goog.require('Blockly.FieldTextInput');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.aria');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.KeyCodes');
|
||||
goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
goog.require('Blockly.utils.userAgent');
|
||||
goog.require('Blockly.WidgetDiv');
|
||||
const Css = goog.require('Blockly.Css');
|
||||
const Field = goog.require('Blockly.Field');
|
||||
const FieldTextInput = goog.require('Blockly.FieldTextInput');
|
||||
const KeyCodes = goog.require('Blockly.utils.KeyCodes');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
const WidgetDiv = goog.require('Blockly.WidgetDiv');
|
||||
const aria = goog.require('Blockly.utils.aria');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
||||
const userAgent = goog.require('Blockly.utils.userAgent');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
const {replaceMessageReferences} = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
@@ -37,14 +38,15 @@ goog.require('Blockly.WidgetDiv');
|
||||
* text as an argument and returns either the accepted text, a replacement
|
||||
* text, or null to abort the change.
|
||||
* @param {Object=} opt_config A map of options used to configure the field.
|
||||
* See the [field creation documentation]{@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/multiline-text-input#creation}
|
||||
* See the [field creation documentation]{@link
|
||||
* https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/multiline-text-input#creation}
|
||||
* for a list of properties this parameter supports.
|
||||
* @extends {Blockly.FieldTextInput}
|
||||
* @extends {FieldTextInput}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldMultilineInput = function(opt_value, opt_validator, opt_config) {
|
||||
Blockly.FieldMultilineInput.superClass_.constructor.call(this,
|
||||
opt_value, opt_validator, opt_config);
|
||||
const FieldMultilineInput = function(opt_value, opt_validator, opt_config) {
|
||||
FieldMultilineInput.superClass_.constructor.call(
|
||||
this, opt_value, opt_validator, opt_config);
|
||||
|
||||
/**
|
||||
* The SVG group element that will contain a text element for each text row
|
||||
@@ -68,14 +70,13 @@ Blockly.FieldMultilineInput = function(opt_value, opt_validator, opt_config) {
|
||||
*/
|
||||
this.isOverflowedY_ = false;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.FieldMultilineInput,
|
||||
Blockly.FieldTextInput);
|
||||
inherits(FieldMultilineInput, FieldTextInput);
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.configure_ = function(config) {
|
||||
Blockly.FieldMultilineInput.superClass_.configure_.call(this, config);
|
||||
FieldMultilineInput.prototype.configure_ = function(config) {
|
||||
FieldMultilineInput.superClass_.configure_.call(this, config);
|
||||
config.maxLines && this.setMaxLines(config.maxLines);
|
||||
};
|
||||
|
||||
@@ -83,12 +84,12 @@ Blockly.FieldMultilineInput.prototype.configure_ = function(config) {
|
||||
* Construct a FieldMultilineInput from a JSON arg object,
|
||||
* dereferencing any string table references.
|
||||
* @param {!Object} options A JSON object with options (text, and spellcheck).
|
||||
* @return {!Blockly.FieldMultilineInput} The new field instance.
|
||||
* @return {!FieldMultilineInput} The new field instance.
|
||||
* @package
|
||||
* @nocollapse
|
||||
*/
|
||||
Blockly.FieldMultilineInput.fromJson = function(options) {
|
||||
var text = Blockly.utils.replaceMessageReferences(options['text']);
|
||||
FieldMultilineInput.fromJson = function(options) {
|
||||
const text = replaceMessageReferences(options['text']);
|
||||
// `this` might be a subclass of FieldMultilineInput if that class doesn't
|
||||
// override the static fromJson method.
|
||||
return new this(text, undefined, options);
|
||||
@@ -101,7 +102,7 @@ Blockly.FieldMultilineInput.fromJson = function(options) {
|
||||
* @return {!Element} The element containing info about the field's state.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.toXml = function(fieldElement) {
|
||||
FieldMultilineInput.prototype.toXml = function(fieldElement) {
|
||||
// Replace '\n' characters with HTML-escaped equivalent '
'. This is
|
||||
// needed so the plain-text representation of the XML produced by
|
||||
// `Blockly.Xml.domToText` will appear on a single line (this is a limitation
|
||||
@@ -117,7 +118,7 @@ Blockly.FieldMultilineInput.prototype.toXml = function(fieldElement) {
|
||||
* field's state.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.fromXml = function(fieldElement) {
|
||||
FieldMultilineInput.prototype.fromXml = function(fieldElement) {
|
||||
this.setValue(fieldElement.textContent.replace(/ /g, '\n'));
|
||||
};
|
||||
|
||||
@@ -125,12 +126,13 @@ Blockly.FieldMultilineInput.prototype.fromXml = function(fieldElement) {
|
||||
* Create the block UI for this field.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.initView = function() {
|
||||
FieldMultilineInput.prototype.initView = function() {
|
||||
this.createBorderRect_();
|
||||
this.textGroup_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.G, {
|
||||
this.textGroup_ = dom.createSvgElement(
|
||||
Svg.G, {
|
||||
'class': 'blocklyEditableText',
|
||||
}, this.fieldGroup_);
|
||||
},
|
||||
this.fieldGroup_);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -140,17 +142,18 @@ Blockly.FieldMultilineInput.prototype.initView = function() {
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.getDisplayText_ = function() {
|
||||
var textLines = this.getText();
|
||||
FieldMultilineInput.prototype.getDisplayText_ = function() {
|
||||
let textLines = this.getText();
|
||||
if (!textLines) {
|
||||
// Prevent the field from disappearing if empty.
|
||||
return Blockly.Field.NBSP;
|
||||
return Field.NBSP;
|
||||
}
|
||||
var lines = textLines.split('\n');
|
||||
const lines = textLines.split('\n');
|
||||
textLines = '';
|
||||
var displayLinesNumber = this.isOverflowedY_ ? this.maxLines_ : lines.length;
|
||||
for (var i = 0; i < displayLinesNumber; i++) {
|
||||
var text = lines[i];
|
||||
const displayLinesNumber =
|
||||
this.isOverflowedY_ ? this.maxLines_ : lines.length;
|
||||
for (let i = 0; i < displayLinesNumber; i++) {
|
||||
let text = lines[i];
|
||||
if (text.length > this.maxDisplayLength) {
|
||||
// Truncate displayed string and add an ellipsis ('...').
|
||||
text = text.substring(0, this.maxDisplayLength - 4) + '...';
|
||||
@@ -158,7 +161,7 @@ Blockly.FieldMultilineInput.prototype.getDisplayText_ = function() {
|
||||
text = text.substring(0, text.length - 3) + '...';
|
||||
}
|
||||
// Replace whitespace with non-breaking spaces so the text doesn't collapse.
|
||||
text = text.replace(/\s/g, Blockly.Field.NBSP);
|
||||
text = text.replace(/\s/g, Field.NBSP);
|
||||
|
||||
textLines += text;
|
||||
if (i !== displayLinesNumber - 1) {
|
||||
@@ -181,8 +184,8 @@ Blockly.FieldMultilineInput.prototype.getDisplayText_ = function() {
|
||||
* that this is a string.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.doValueUpdate_ = function(newValue) {
|
||||
Blockly.FieldMultilineInput.superClass_.doValueUpdate_.call(this, newValue);
|
||||
FieldMultilineInput.prototype.doValueUpdate_ = function(newValue) {
|
||||
FieldMultilineInput.superClass_.doValueUpdate_.call(this, newValue);
|
||||
this.isOverflowedY_ = this.value_.split('\n').length > this.maxLines_;
|
||||
};
|
||||
|
||||
@@ -190,36 +193,37 @@ Blockly.FieldMultilineInput.prototype.doValueUpdate_ = function(newValue) {
|
||||
* Updates the text of the textElement.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.render_ = function() {
|
||||
FieldMultilineInput.prototype.render_ = function() {
|
||||
// Remove all text group children.
|
||||
var currentChild;
|
||||
let currentChild;
|
||||
while ((currentChild = this.textGroup_.firstChild)) {
|
||||
this.textGroup_.removeChild(currentChild);
|
||||
}
|
||||
|
||||
// Add in text elements into the group.
|
||||
var lines = this.getDisplayText_().split('\n');
|
||||
var y = 0;
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var lineHeight = this.getConstants().FIELD_TEXT_HEIGHT +
|
||||
const lines = this.getDisplayText_().split('\n');
|
||||
let y = 0;
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const lineHeight = this.getConstants().FIELD_TEXT_HEIGHT +
|
||||
this.getConstants().FIELD_BORDER_RECT_Y_PADDING;
|
||||
var span = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.TEXT, {
|
||||
const span = dom.createSvgElement(
|
||||
Svg.TEXT, {
|
||||
'class': 'blocklyText blocklyMultilineText',
|
||||
x: this.getConstants().FIELD_BORDER_RECT_X_PADDING,
|
||||
y: y + this.getConstants().FIELD_BORDER_RECT_Y_PADDING,
|
||||
dy: this.getConstants().FIELD_TEXT_BASELINE
|
||||
}, this.textGroup_);
|
||||
},
|
||||
this.textGroup_);
|
||||
span.appendChild(document.createTextNode(lines[i]));
|
||||
y += lineHeight;
|
||||
}
|
||||
|
||||
if (this.isBeingEdited_) {
|
||||
var htmlInput = /** @type {!HTMLElement} */(this.htmlInput_);
|
||||
var htmlInput = /** @type {!HTMLElement} */ (this.htmlInput_);
|
||||
if (this.isOverflowedY_) {
|
||||
Blockly.utils.dom.addClass(htmlInput, 'blocklyHtmlTextAreaInputOverflowedY');
|
||||
dom.addClass(htmlInput, 'blocklyHtmlTextAreaInputOverflowedY');
|
||||
} else {
|
||||
Blockly.utils.dom.removeClass(htmlInput, 'blocklyHtmlTextAreaInputOverflowedY');
|
||||
dom.removeClass(htmlInput, 'blocklyHtmlTextAreaInputOverflowedY');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,15 +238,13 @@ Blockly.FieldMultilineInput.prototype.render_ = function() {
|
||||
} else {
|
||||
this.resizeEditor_();
|
||||
}
|
||||
var htmlInput = /** @type {!HTMLElement} */(this.htmlInput_);
|
||||
var htmlInput = /** @type {!HTMLElement} */ (this.htmlInput_);
|
||||
if (!this.isTextValid_) {
|
||||
Blockly.utils.dom.addClass(htmlInput, 'blocklyInvalidInput');
|
||||
Blockly.utils.aria.setState(htmlInput,
|
||||
Blockly.utils.aria.State.INVALID, true);
|
||||
dom.addClass(htmlInput, 'blocklyInvalidInput');
|
||||
aria.setState(htmlInput, aria.State.INVALID, true);
|
||||
} else {
|
||||
Blockly.utils.dom.removeClass(htmlInput, 'blocklyInvalidInput');
|
||||
Blockly.utils.aria.setState(htmlInput,
|
||||
Blockly.utils.aria.State.INVALID, false);
|
||||
dom.removeClass(htmlInput, 'blocklyInvalidInput');
|
||||
aria.setState(htmlInput, aria.State.INVALID, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -251,13 +253,13 @@ Blockly.FieldMultilineInput.prototype.render_ = function() {
|
||||
* Updates the size of the field based on the text.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.updateSize_ = function() {
|
||||
var nodes = this.textGroup_.childNodes;
|
||||
var totalWidth = 0;
|
||||
var totalHeight = 0;
|
||||
FieldMultilineInput.prototype.updateSize_ = function() {
|
||||
const nodes = this.textGroup_.childNodes;
|
||||
let totalWidth = 0;
|
||||
let totalHeight = 0;
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var tspan = /** @type {!Element} */ (nodes[i]);
|
||||
var textWidth = Blockly.utils.dom.getTextWidth(tspan);
|
||||
const tspan = /** @type {!Element} */ (nodes[i]);
|
||||
const textWidth = dom.getTextWidth(tspan);
|
||||
if (textWidth > totalWidth) {
|
||||
totalWidth = textWidth;
|
||||
}
|
||||
@@ -270,26 +272,28 @@ Blockly.FieldMultilineInput.prototype.updateSize_ = function() {
|
||||
// absolute longest line, even if it would be truncated after editing.
|
||||
// Otherwise we would get wrong editor width when there are more
|
||||
// lines than this.maxLines_.
|
||||
var actualEditorLines = this.value_.split('\n');
|
||||
var dummyTextElement = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.TEXT,{'class': 'blocklyText blocklyMultilineText'});
|
||||
var fontSize = this.getConstants().FIELD_TEXT_FONTSIZE;
|
||||
var fontWeight = this.getConstants().FIELD_TEXT_FONTWEIGHT;
|
||||
var fontFamily = this.getConstants().FIELD_TEXT_FONTFAMILY;
|
||||
const actualEditorLines = this.value_.split('\n');
|
||||
const dummyTextElement = dom.createSvgElement(
|
||||
Svg.TEXT, {'class': 'blocklyText blocklyMultilineText'});
|
||||
const fontSize = this.getConstants().FIELD_TEXT_FONTSIZE;
|
||||
const fontWeight = this.getConstants().FIELD_TEXT_FONTWEIGHT;
|
||||
const fontFamily = this.getConstants().FIELD_TEXT_FONTFAMILY;
|
||||
|
||||
for (var i = 0; i < actualEditorLines.length; i++) {
|
||||
if (actualEditorLines[i].length > this.maxDisplayLength) {
|
||||
actualEditorLines[i] = actualEditorLines[i].substring(0, this.maxDisplayLength);
|
||||
actualEditorLines[i] =
|
||||
actualEditorLines[i].substring(0, this.maxDisplayLength);
|
||||
}
|
||||
dummyTextElement.textContent = actualEditorLines[i];
|
||||
var lineWidth = Blockly.utils.dom.getFastTextWidth(
|
||||
const lineWidth = dom.getFastTextWidth(
|
||||
dummyTextElement, fontSize, fontWeight, fontFamily);
|
||||
if (lineWidth > totalWidth) {
|
||||
totalWidth = lineWidth;
|
||||
}
|
||||
}
|
||||
|
||||
var scrollbarWidth = this.htmlInput_.offsetWidth - this.htmlInput_.clientWidth;
|
||||
const scrollbarWidth =
|
||||
this.htmlInput_.offsetWidth - this.htmlInput_.clientWidth;
|
||||
totalWidth += scrollbarWidth;
|
||||
}
|
||||
if (this.borderRect_) {
|
||||
@@ -314,8 +318,9 @@ Blockly.FieldMultilineInput.prototype.updateSize_ = function() {
|
||||
* focus. Defaults to false.
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.showEditor_ = function(_opt_e, opt_quietInput) {
|
||||
Blockly.FieldMultilineInput.superClass_.showEditor_.call(this, _opt_e, opt_quietInput);
|
||||
FieldMultilineInput.prototype.showEditor_ = function(_opt_e, opt_quietInput) {
|
||||
FieldMultilineInput.superClass_.showEditor_.call(
|
||||
this, _opt_e, opt_quietInput);
|
||||
this.forceRerender();
|
||||
};
|
||||
|
||||
@@ -324,24 +329,24 @@ Blockly.FieldMultilineInput.prototype.showEditor_ = function(_opt_e, opt_quietIn
|
||||
* @return {!HTMLTextAreaElement} The newly created text input editor.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.widgetCreate_ = function() {
|
||||
var div = Blockly.WidgetDiv.DIV;
|
||||
var scale = this.workspace_.getScale();
|
||||
FieldMultilineInput.prototype.widgetCreate_ = function() {
|
||||
const div = WidgetDiv.DIV;
|
||||
const scale = this.workspace_.getScale();
|
||||
|
||||
var htmlInput =
|
||||
/** @type {HTMLTextAreaElement} */ (document.createElement('textarea'));
|
||||
const htmlInput =
|
||||
/** @type {HTMLTextAreaElement} */ (document.createElement('textarea'));
|
||||
htmlInput.className = 'blocklyHtmlInput blocklyHtmlTextAreaInput';
|
||||
htmlInput.setAttribute('spellcheck', this.spellcheck_);
|
||||
var fontSize = (this.getConstants().FIELD_TEXT_FONTSIZE * scale) + 'pt';
|
||||
const fontSize = (this.getConstants().FIELD_TEXT_FONTSIZE * scale) + 'pt';
|
||||
div.style.fontSize = fontSize;
|
||||
htmlInput.style.fontSize = fontSize;
|
||||
var borderRadius = (Blockly.FieldTextInput.BORDERRADIUS * scale) + 'px';
|
||||
const borderRadius = (FieldTextInput.BORDERRADIUS * scale) + 'px';
|
||||
htmlInput.style.borderRadius = borderRadius;
|
||||
var paddingX = this.getConstants().FIELD_BORDER_RECT_X_PADDING * scale;
|
||||
var paddingY = this.getConstants().FIELD_BORDER_RECT_Y_PADDING * scale / 2;
|
||||
htmlInput.style.padding = paddingY + 'px ' + paddingX + 'px ' + paddingY +
|
||||
'px ' + paddingX + 'px';
|
||||
var lineHeight = this.getConstants().FIELD_TEXT_HEIGHT +
|
||||
const paddingX = this.getConstants().FIELD_BORDER_RECT_X_PADDING * scale;
|
||||
const paddingY = this.getConstants().FIELD_BORDER_RECT_Y_PADDING * scale / 2;
|
||||
htmlInput.style.padding =
|
||||
paddingY + 'px ' + paddingX + 'px ' + paddingY + 'px ' + paddingX + 'px';
|
||||
const lineHeight = this.getConstants().FIELD_TEXT_HEIGHT +
|
||||
this.getConstants().FIELD_BORDER_RECT_Y_PADDING;
|
||||
htmlInput.style.lineHeight = (lineHeight * scale) + 'px';
|
||||
|
||||
@@ -350,7 +355,7 @@ Blockly.FieldMultilineInput.prototype.widgetCreate_ = function() {
|
||||
htmlInput.value = htmlInput.defaultValue = this.getEditorText_(this.value_);
|
||||
htmlInput.untypedDefaultValue_ = this.value_;
|
||||
htmlInput.oldValue_ = null;
|
||||
if (Blockly.utils.userAgent.GECKO) {
|
||||
if (userAgent.GECKO) {
|
||||
// In FF, ensure the browser reflows before resizing to avoid issue #2777.
|
||||
setTimeout(this.resizeEditor_.bind(this), 0);
|
||||
} else {
|
||||
@@ -367,8 +372,9 @@ Blockly.FieldMultilineInput.prototype.widgetCreate_ = function() {
|
||||
* @param {number} maxLines Defines the maximum number of lines allowed,
|
||||
* before scrolling functionality is enabled.
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.setMaxLines = function(maxLines) {
|
||||
if (typeof maxLines === 'number' && maxLines > 0 && maxLines !== this.maxLines_) {
|
||||
FieldMultilineInput.prototype.setMaxLines = function(maxLines) {
|
||||
if (typeof maxLines === 'number' && maxLines > 0 &&
|
||||
maxLines !== this.maxLines_) {
|
||||
this.maxLines_ = maxLines;
|
||||
this.forceRerender();
|
||||
}
|
||||
@@ -378,7 +384,7 @@ Blockly.FieldMultilineInput.prototype.setMaxLines = function(maxLines) {
|
||||
* Returns the maxLines config of this field.
|
||||
* @return {number} The maxLines config value.
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.getMaxLines = function() {
|
||||
FieldMultilineInput.prototype.getMaxLines = function() {
|
||||
return this.maxLines_;
|
||||
};
|
||||
|
||||
@@ -388,29 +394,29 @@ Blockly.FieldMultilineInput.prototype.getMaxLines = function() {
|
||||
* @param {!Event} e Keyboard event.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldMultilineInput.prototype.onHtmlInputKeyDown_ = function(e) {
|
||||
if (e.keyCode !== Blockly.utils.KeyCodes.ENTER) {
|
||||
Blockly.FieldMultilineInput.superClass_.onHtmlInputKeyDown_.call(this, e);
|
||||
FieldMultilineInput.prototype.onHtmlInputKeyDown_ = function(e) {
|
||||
if (e.keyCode !== KeyCodes.ENTER) {
|
||||
FieldMultilineInput.superClass_.onHtmlInputKeyDown_.call(this, e);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* CSS for multiline field. See css.js for use.
|
||||
*/
|
||||
Blockly.Css.register([
|
||||
/* eslint-disable indent */
|
||||
'.blocklyHtmlTextAreaInput {',
|
||||
'font-family: monospace;',
|
||||
'resize: none;',
|
||||
'overflow: hidden;',
|
||||
'height: 100%;',
|
||||
'text-align: left;',
|
||||
'}',
|
||||
'.blocklyHtmlTextAreaInputOverflowedY {',
|
||||
'overflow-y: scroll;',
|
||||
'}'
|
||||
/* eslint-enable indent */
|
||||
Css.register([
|
||||
`.blocklyHtmlTextAreaInput {
|
||||
font-family: monospace;
|
||||
resize: none;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
text-align: left;
|
||||
}`,
|
||||
`.blocklyHtmlTextAreaInputOverflowedY {
|
||||
overflow-y: scroll;
|
||||
}`
|
||||
]);
|
||||
|
||||
|
||||
Blockly.fieldRegistry.register('field_multilinetext', Blockly.FieldMultilineInput);
|
||||
fieldRegistry.register('field_multilinetext', FieldMultilineInput);
|
||||
|
||||
exports = FieldMultilineInput;
|
||||
|
||||
@@ -12,56 +12,62 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.fieldRegistry');
|
||||
goog.module('Blockly.fieldRegistry');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.registry');
|
||||
|
||||
goog.requireType('Blockly.Field');
|
||||
goog.requireType('Blockly.IRegistrableField');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Field = goog.requireType('Blockly.Field');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IRegistrableField = goog.requireType('Blockly.IRegistrableField');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
|
||||
|
||||
/**
|
||||
* Registers a field type.
|
||||
* Blockly.fieldRegistry.fromJson uses this registry to
|
||||
* fieldRegistry.fromJson uses this registry to
|
||||
* find the appropriate field type.
|
||||
* @param {string} type The field type name as used in the JSON definition.
|
||||
* @param {!Blockly.IRegistrableField} fieldClass The field class containing a
|
||||
* @param {!IRegistrableField} fieldClass The field class containing a
|
||||
* fromJson function that can construct an instance of the field.
|
||||
* @throws {Error} if the type name is empty, the field is already
|
||||
* registered, or the fieldClass is not an object containing a fromJson
|
||||
* function.
|
||||
*/
|
||||
Blockly.fieldRegistry.register = function(type, fieldClass) {
|
||||
Blockly.registry.register(Blockly.registry.Type.FIELD, type, fieldClass);
|
||||
const register = function(type, fieldClass) {
|
||||
registry.register(registry.Type.FIELD, type, fieldClass);
|
||||
};
|
||||
exports.register = register;
|
||||
|
||||
/**
|
||||
* Unregisters the field registered with the given type.
|
||||
* @param {string} type The field type name as used in the JSON definition.
|
||||
*/
|
||||
Blockly.fieldRegistry.unregister = function(type) {
|
||||
Blockly.registry.unregister(Blockly.registry.Type.FIELD, type);
|
||||
const unregister = function(type) {
|
||||
registry.unregister(registry.Type.FIELD, type);
|
||||
};
|
||||
exports.unregister = unregister;
|
||||
|
||||
/**
|
||||
* Construct a Field from a JSON arg object.
|
||||
* Finds the appropriate registered field by the type name as registered using
|
||||
* Blockly.fieldRegistry.register.
|
||||
* fieldRegistry.register.
|
||||
* @param {!Object} options A JSON object with a type and options specific
|
||||
* to the field type.
|
||||
* @return {?Blockly.Field} The new field instance or null if a field wasn't
|
||||
* @return {?Field} The new field instance or null if a field wasn't
|
||||
* found with the given type name
|
||||
* @package
|
||||
*/
|
||||
Blockly.fieldRegistry.fromJson = function(options) {
|
||||
var fieldObject = /** @type {?Blockly.IRegistrableField} */ (
|
||||
Blockly.registry.getObject(Blockly.registry.Type.FIELD, options['type']));
|
||||
const fromJson = function(options) {
|
||||
const fieldObject = /** @type {?IRegistrableField} */ (
|
||||
registry.getObject(registry.Type.FIELD, options['type']));
|
||||
if (!fieldObject) {
|
||||
console.warn('Blockly could not create a field of type ' + options['type'] +
|
||||
'. The field is probably not being registered. This could be because' +
|
||||
' the file is not loaded, the field does not register itself (Issue' +
|
||||
' #1584), or the registration is not being reached.');
|
||||
console.warn(
|
||||
'Blockly could not create a field of type ' + options['type'] +
|
||||
'. The field is probably not being registered. This could be because' +
|
||||
' the file is not loaded, the field does not register itself (Issue' +
|
||||
' #1584), or the registration is not being reached.');
|
||||
return null;
|
||||
}
|
||||
return fieldObject.fromJson(options);
|
||||
};
|
||||
/** @package */
|
||||
exports.fromJson = fromJson;
|
||||
|
||||
@@ -10,24 +10,24 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.FieldVariable');
|
||||
goog.module('Blockly.FieldVariable');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
const FieldDropdown = goog.require('Blockly.FieldDropdown');
|
||||
const Menu = goog.requireType('Blockly.Menu');
|
||||
const MenuItem = goog.requireType('Blockly.MenuItem');
|
||||
const Msg = goog.require('Blockly.Msg');
|
||||
const Size = goog.require('Blockly.utils.Size');
|
||||
const VariableModel = goog.require('Blockly.VariableModel');
|
||||
const Variables = goog.require('Blockly.Variables');
|
||||
const Xml = goog.require('Blockly.Xml');
|
||||
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
||||
const internalConstants = goog.require('Blockly.internalConstants');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
const {replaceMessageReferences} = goog.require('Blockly.utils');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Events.BlockChange');
|
||||
goog.require('Blockly.FieldDropdown');
|
||||
goog.require('Blockly.fieldRegistry');
|
||||
goog.require('Blockly.internalConstants');
|
||||
goog.require('Blockly.Msg');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.utils.Size');
|
||||
goog.require('Blockly.VariableModel');
|
||||
goog.require('Blockly.Variables');
|
||||
goog.require('Blockly.Xml');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
goog.requireType('Blockly.Menu');
|
||||
goog.requireType('Blockly.MenuItem');
|
||||
|
||||
|
||||
/**
|
||||
@@ -42,13 +42,14 @@ goog.requireType('Blockly.MenuItem');
|
||||
* @param {string=} opt_defaultType The type of variable to create if this
|
||||
* field's value is not explicitly set. Defaults to ''.
|
||||
* @param {Object=} opt_config A map of options used to configure the field.
|
||||
* See the [field creation documentation]{@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/variable#creation}
|
||||
* See the [field creation documentation]{@link
|
||||
* https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/variable#creation}
|
||||
* for a list of properties this parameter supports.
|
||||
* @extends {Blockly.FieldDropdown}
|
||||
* @extends {FieldDropdown}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldVariable = function(varName, opt_validator, opt_variableTypes,
|
||||
opt_defaultType, opt_config) {
|
||||
const FieldVariable = function(
|
||||
varName, opt_validator, opt_variableTypes, opt_defaultType, opt_config) {
|
||||
// The FieldDropdown constructor expects the field's initial value to be
|
||||
// the first entry in the menu generator, which it may or may not be.
|
||||
// Just do the relevant parts of the constructor.
|
||||
@@ -57,10 +58,10 @@ Blockly.FieldVariable = function(varName, opt_validator, opt_variableTypes,
|
||||
* An array of options for a dropdown list,
|
||||
* or a function which generates these options.
|
||||
* @type {(!Array<!Array>|
|
||||
* !function(this:Blockly.FieldDropdown): !Array<!Array>)}
|
||||
* !function(this:FieldDropdown): !Array<!Array>)}
|
||||
* @protected
|
||||
*/
|
||||
this.menuGenerator_ = Blockly.FieldVariable.dropdownCreate;
|
||||
this.menuGenerator_ = FieldVariable.dropdownCreate;
|
||||
|
||||
/**
|
||||
* The initial variable name passed to this field's constructor, or an
|
||||
@@ -72,11 +73,11 @@ Blockly.FieldVariable = function(varName, opt_validator, opt_variableTypes,
|
||||
|
||||
/**
|
||||
* The size of the area rendered by the field.
|
||||
* @type {Blockly.utils.Size}
|
||||
* @type {Size}
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
this.size_ = new Blockly.utils.Size(0, 0);
|
||||
this.size_ = new Size(0, 0);
|
||||
|
||||
opt_config && this.configure_(opt_config);
|
||||
opt_validator && this.setValidator(opt_validator);
|
||||
@@ -85,19 +86,19 @@ Blockly.FieldVariable = function(varName, opt_validator, opt_variableTypes,
|
||||
this.setTypes_(opt_variableTypes, opt_defaultType);
|
||||
}
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.FieldVariable, Blockly.FieldDropdown);
|
||||
inherits(FieldVariable, FieldDropdown);
|
||||
|
||||
/**
|
||||
* Construct a FieldVariable from a JSON arg object,
|
||||
* dereferencing any string table references.
|
||||
* @param {!Object} options A JSON object with options (variable,
|
||||
* variableTypes, and defaultType).
|
||||
* @return {!Blockly.FieldVariable} The new field instance.
|
||||
* @return {!FieldVariable} The new field instance.
|
||||
* @package
|
||||
* @nocollapse
|
||||
*/
|
||||
Blockly.FieldVariable.fromJson = function(options) {
|
||||
var varName = Blockly.utils.replaceMessageReferences(options['variable']);
|
||||
FieldVariable.fromJson = function(options) {
|
||||
const varName = replaceMessageReferences(options['variable']);
|
||||
// `this` might be a subclass of FieldVariable if that class doesn't override
|
||||
// the static fromJson method.
|
||||
return new this(varName, undefined, undefined, undefined, options);
|
||||
@@ -108,15 +109,15 @@ Blockly.FieldVariable.fromJson = function(options) {
|
||||
* are not. Editable fields should also be serializable.
|
||||
* @type {boolean}
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.SERIALIZABLE = true;
|
||||
FieldVariable.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Configure the field based on the given map of options.
|
||||
* @param {!Object} config A map of options to configure the field based on.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.configure_ = function(config) {
|
||||
Blockly.FieldVariable.superClass_.configure_.call(this, config);
|
||||
FieldVariable.prototype.configure_ = function(config) {
|
||||
FieldVariable.superClass_.configure_.call(this, config);
|
||||
this.setTypes_(config['variableTypes'], config['defaultType']);
|
||||
};
|
||||
|
||||
@@ -126,13 +127,13 @@ Blockly.FieldVariable.prototype.configure_ = function(config) {
|
||||
* variable rather than let the value be invalid.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.initModel = function() {
|
||||
FieldVariable.prototype.initModel = function() {
|
||||
if (this.variable_) {
|
||||
return; // Initialization already happened.
|
||||
}
|
||||
var variable = Blockly.Variables.getOrCreateVariablePackage(
|
||||
this.sourceBlock_.workspace, null,
|
||||
this.defaultVariableName, this.defaultType_);
|
||||
const variable = Variables.getOrCreateVariablePackage(
|
||||
this.sourceBlock_.workspace, null, this.defaultVariableName,
|
||||
this.defaultType_);
|
||||
|
||||
// Don't call setValue because we don't want to cause a rerender.
|
||||
this.doValueUpdate_(variable.getId());
|
||||
@@ -141,10 +142,10 @@ Blockly.FieldVariable.prototype.initModel = function() {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.shouldAddBorderRect_ = function() {
|
||||
return Blockly.FieldVariable.superClass_.shouldAddBorderRect_.call(this) &&
|
||||
(!this.getConstants().FIELD_DROPDOWN_NO_BORDER_RECT_SHADOW ||
|
||||
this.sourceBlock_.type != 'variables_get');
|
||||
FieldVariable.prototype.shouldAddBorderRect_ = function() {
|
||||
return FieldVariable.superClass_.shouldAddBorderRect_.call(this) &&
|
||||
(!this.getConstants().FIELD_DROPDOWN_NO_BORDER_RECT_SHADOW ||
|
||||
this.sourceBlock_.type != 'variables_get');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -152,23 +153,24 @@ Blockly.FieldVariable.prototype.shouldAddBorderRect_ = function() {
|
||||
* @param {!Element} fieldElement The element containing information about the
|
||||
* variable field's state.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.fromXml = function(fieldElement) {
|
||||
var id = fieldElement.getAttribute('id');
|
||||
var variableName = fieldElement.textContent;
|
||||
FieldVariable.prototype.fromXml = function(fieldElement) {
|
||||
const id = fieldElement.getAttribute('id');
|
||||
const variableName = fieldElement.textContent;
|
||||
// 'variabletype' should be lowercase, but until July 2019 it was sometimes
|
||||
// recorded as 'variableType'. Thus we need to check for both.
|
||||
var variableType = fieldElement.getAttribute('variabletype') ||
|
||||
const variableType = fieldElement.getAttribute('variabletype') ||
|
||||
fieldElement.getAttribute('variableType') || '';
|
||||
|
||||
var variable = Blockly.Variables.getOrCreateVariablePackage(
|
||||
const variable = Variables.getOrCreateVariablePackage(
|
||||
this.sourceBlock_.workspace, id, variableName, variableType);
|
||||
|
||||
// This should never happen :)
|
||||
if (variableType != null && variableType !== variable.type) {
|
||||
throw Error('Serialized variable type with id \'' +
|
||||
variable.getId() + '\' had type ' + variable.type + ', and ' +
|
||||
'does not match variable field that references it: ' +
|
||||
Blockly.Xml.domToText(fieldElement) + '.');
|
||||
throw Error(
|
||||
'Serialized variable type with id \'' + variable.getId() +
|
||||
'\' had type ' + variable.type + ', and ' +
|
||||
'does not match variable field that references it: ' +
|
||||
Xml.domToText(fieldElement) + '.');
|
||||
}
|
||||
|
||||
this.setValue(variable.getId());
|
||||
@@ -180,7 +182,7 @@ Blockly.FieldVariable.prototype.fromXml = function(fieldElement) {
|
||||
* field's state.
|
||||
* @return {!Element} The element containing info about the field's state.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.toXml = function(fieldElement) {
|
||||
FieldVariable.prototype.toXml = function(fieldElement) {
|
||||
// Make sure the variable is initialized.
|
||||
this.initModel();
|
||||
|
||||
@@ -194,20 +196,20 @@ Blockly.FieldVariable.prototype.toXml = function(fieldElement) {
|
||||
|
||||
/**
|
||||
* Attach this field to a block.
|
||||
* @param {!Blockly.Block} block The block containing this field.
|
||||
* @param {!Block} block The block containing this field.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.setSourceBlock = function(block) {
|
||||
FieldVariable.prototype.setSourceBlock = function(block) {
|
||||
if (block.isShadow()) {
|
||||
throw Error('Variable fields are not allowed to exist on shadow blocks.');
|
||||
}
|
||||
Blockly.FieldVariable.superClass_.setSourceBlock.call(this, block);
|
||||
FieldVariable.superClass_.setSourceBlock.call(this, block);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the variable's ID.
|
||||
* @return {string} Current variable's ID.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.getValue = function() {
|
||||
FieldVariable.prototype.getValue = function() {
|
||||
return this.variable_ ? this.variable_.getId() : null;
|
||||
};
|
||||
|
||||
@@ -216,7 +218,7 @@ Blockly.FieldVariable.prototype.getValue = function() {
|
||||
* @return {string} The selected variable's name, or the empty string if no
|
||||
* variable is selected.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.getText = function() {
|
||||
FieldVariable.prototype.getText = function() {
|
||||
return this.variable_ ? this.variable_.name : '';
|
||||
};
|
||||
|
||||
@@ -224,11 +226,11 @@ Blockly.FieldVariable.prototype.getText = function() {
|
||||
* Get the variable model for the selected variable.
|
||||
* Not guaranteed to be in the variable map on the workspace (e.g. if accessed
|
||||
* after the variable has been deleted).
|
||||
* @return {?Blockly.VariableModel} The selected variable, or null if none was
|
||||
* @return {?VariableModel} The selected variable, or null if none was
|
||||
* selected.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.getVariable = function() {
|
||||
FieldVariable.prototype.getVariable = function() {
|
||||
return this.variable_;
|
||||
};
|
||||
|
||||
@@ -239,7 +241,7 @@ Blockly.FieldVariable.prototype.getVariable = function() {
|
||||
* a block and workspace at that point.
|
||||
* @return {?Function} Validation function, or null.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.getValidator = function() {
|
||||
FieldVariable.prototype.getValidator = function() {
|
||||
// Validators shouldn't operate on the initial setValue call.
|
||||
// Normally this is achieved by calling setValidator after setValue, but
|
||||
// this is not a possibility with variable fields.
|
||||
@@ -255,20 +257,20 @@ Blockly.FieldVariable.prototype.getValidator = function() {
|
||||
* @return {?string} The validated ID, or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
FieldVariable.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
if (opt_newValue === null) {
|
||||
return null;
|
||||
}
|
||||
var newId = /** @type {string} */ (opt_newValue);
|
||||
var variable = Blockly.Variables.getVariable(
|
||||
this.sourceBlock_.workspace, newId);
|
||||
const newId = /** @type {string} */ (opt_newValue);
|
||||
const variable = Variables.getVariable(this.sourceBlock_.workspace, newId);
|
||||
if (!variable) {
|
||||
console.warn('Variable id doesn\'t point to a real variable! ' +
|
||||
console.warn(
|
||||
'Variable id doesn\'t point to a real variable! ' +
|
||||
'ID was ' + newId);
|
||||
return null;
|
||||
}
|
||||
// Type Checks.
|
||||
var type = variable.type;
|
||||
const type = variable.type;
|
||||
if (!this.typeIsAllowed_(type)) {
|
||||
console.warn('Variable type doesn\'t match this field! Type was ' + type);
|
||||
return null;
|
||||
@@ -284,10 +286,10 @@ Blockly.FieldVariable.prototype.doClassValidation_ = function(opt_newValue) {
|
||||
* @param {*} newId The value to be saved.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.doValueUpdate_ = function(newId) {
|
||||
this.variable_ = Blockly.Variables.getVariable(
|
||||
FieldVariable.prototype.doValueUpdate_ = function(newId) {
|
||||
this.variable_ = Variables.getVariable(
|
||||
this.sourceBlock_.workspace, /** @type {string} */ (newId));
|
||||
Blockly.FieldVariable.superClass_.doValueUpdate_.call(this, newId);
|
||||
FieldVariable.superClass_.doValueUpdate_.call(this, newId);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -296,12 +298,12 @@ Blockly.FieldVariable.prototype.doValueUpdate_ = function(newId) {
|
||||
* @return {boolean} True if the type is in the list of allowed types.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.typeIsAllowed_ = function(type) {
|
||||
var typeList = this.getVariableTypes_();
|
||||
FieldVariable.prototype.typeIsAllowed_ = function(type) {
|
||||
const typeList = this.getVariableTypes_();
|
||||
if (!typeList) {
|
||||
return true; // If it's null, all types are valid.
|
||||
}
|
||||
for (var i = 0; i < typeList.length; i++) {
|
||||
for (let i = 0; i < typeList.length; i++) {
|
||||
if (type == typeList[i]) {
|
||||
return true;
|
||||
}
|
||||
@@ -315,9 +317,9 @@ Blockly.FieldVariable.prototype.typeIsAllowed_ = function(type) {
|
||||
* @throws {Error} if variableTypes is an empty array.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.getVariableTypes_ = function() {
|
||||
FieldVariable.prototype.getVariableTypes_ = function() {
|
||||
// TODO (#1513): Try to avoid calling this every time the field is edited.
|
||||
var variableTypes = this.variableTypes;
|
||||
let variableTypes = this.variableTypes;
|
||||
if (variableTypes === null) {
|
||||
// If variableTypes is null, return all variable types.
|
||||
if (this.sourceBlock_ && this.sourceBlock_.workspace) {
|
||||
@@ -327,9 +329,9 @@ Blockly.FieldVariable.prototype.getVariableTypes_ = function() {
|
||||
variableTypes = variableTypes || [''];
|
||||
if (variableTypes.length == 0) {
|
||||
// Throw an error if variableTypes is an empty list.
|
||||
var name = this.getText();
|
||||
throw Error('\'variableTypes\' of field variable ' +
|
||||
name + ' was an empty list');
|
||||
const name = this.getText();
|
||||
throw Error(
|
||||
'\'variableTypes\' of field variable ' + name + ' was an empty list');
|
||||
}
|
||||
return variableTypes;
|
||||
};
|
||||
@@ -344,29 +346,32 @@ Blockly.FieldVariable.prototype.getVariableTypes_ = function() {
|
||||
* field's value is not explicitly set. Defaults to ''.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.setTypes_ = function(opt_variableTypes,
|
||||
opt_defaultType) {
|
||||
FieldVariable.prototype.setTypes_ = function(
|
||||
opt_variableTypes, opt_defaultType) {
|
||||
// If you expected that the default type would be the same as the only entry
|
||||
// in the variable types array, tell the Blockly team by commenting on #1499.
|
||||
var defaultType = opt_defaultType || '';
|
||||
const defaultType = opt_defaultType || '';
|
||||
let variableTypes;
|
||||
// Set the allowable variable types. Null means all types on the workspace.
|
||||
if (opt_variableTypes == null || opt_variableTypes == undefined) {
|
||||
var variableTypes = null;
|
||||
variableTypes = null;
|
||||
} else if (Array.isArray(opt_variableTypes)) {
|
||||
var variableTypes = opt_variableTypes;
|
||||
variableTypes = opt_variableTypes;
|
||||
// Make sure the default type is valid.
|
||||
var isInArray = false;
|
||||
for (var i = 0; i < variableTypes.length; i++) {
|
||||
let isInArray = false;
|
||||
for (let i = 0; i < variableTypes.length; i++) {
|
||||
if (variableTypes[i] == defaultType) {
|
||||
isInArray = true;
|
||||
}
|
||||
}
|
||||
if (!isInArray) {
|
||||
throw Error('Invalid default type \'' + defaultType + '\' in ' +
|
||||
throw Error(
|
||||
'Invalid default type \'' + defaultType + '\' in ' +
|
||||
'the definition of a FieldVariable');
|
||||
}
|
||||
} else {
|
||||
throw Error('\'variableTypes\' was not an array in the definition of ' +
|
||||
throw Error(
|
||||
'\'variableTypes\' was not an array in the definition of ' +
|
||||
'a FieldVariable');
|
||||
}
|
||||
// Only update the field once all checks pass.
|
||||
@@ -380,7 +385,7 @@ Blockly.FieldVariable.prototype.setTypes_ = function(opt_variableTypes,
|
||||
* be called by the block.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.refreshVariableName = function() {
|
||||
FieldVariable.prototype.refreshVariableName = function() {
|
||||
this.forceRerender();
|
||||
};
|
||||
|
||||
@@ -388,40 +393,39 @@ Blockly.FieldVariable.prototype.refreshVariableName = function() {
|
||||
* Return a sorted list of variable names for variable dropdown menus.
|
||||
* Include a special option at the end for creating a new variable name.
|
||||
* @return {!Array<!Array>} Array of variable names/id tuples.
|
||||
* @this {Blockly.FieldVariable}
|
||||
* @this {FieldVariable}
|
||||
*/
|
||||
Blockly.FieldVariable.dropdownCreate = function() {
|
||||
FieldVariable.dropdownCreate = function() {
|
||||
if (!this.variable_) {
|
||||
throw Error('Tried to call dropdownCreate on a variable field with no' +
|
||||
throw Error(
|
||||
'Tried to call dropdownCreate on a variable field with no' +
|
||||
' variable selected.');
|
||||
}
|
||||
var name = this.getText();
|
||||
var variableModelList = [];
|
||||
const name = this.getText();
|
||||
let variableModelList = [];
|
||||
if (this.sourceBlock_ && this.sourceBlock_.workspace) {
|
||||
var variableTypes = this.getVariableTypes_();
|
||||
const variableTypes = this.getVariableTypes_();
|
||||
// Get a copy of the list, so that adding rename and new variable options
|
||||
// doesn't modify the workspace's list.
|
||||
for (var i = 0; i < variableTypes.length; i++) {
|
||||
var variableType = variableTypes[i];
|
||||
var variables =
|
||||
this.sourceBlock_.workspace.getVariablesOfType(variableType);
|
||||
for (let i = 0; i < variableTypes.length; i++) {
|
||||
const variableType = variableTypes[i];
|
||||
const variables =
|
||||
this.sourceBlock_.workspace.getVariablesOfType(variableType);
|
||||
variableModelList = variableModelList.concat(variables);
|
||||
}
|
||||
}
|
||||
variableModelList.sort(Blockly.VariableModel.compareByName);
|
||||
variableModelList.sort(VariableModel.compareByName);
|
||||
|
||||
var options = [];
|
||||
for (var i = 0; i < variableModelList.length; i++) {
|
||||
const options = [];
|
||||
for (let i = 0; i < variableModelList.length; i++) {
|
||||
// Set the UUID as the internal representation of the variable.
|
||||
options[i] = [variableModelList[i].name, variableModelList[i].getId()];
|
||||
}
|
||||
options.push([
|
||||
Blockly.Msg['RENAME_VARIABLE'], Blockly.internalConstants.RENAME_VARIABLE_ID
|
||||
]);
|
||||
if (Blockly.Msg['DELETE_VARIABLE']) {
|
||||
options.push([Msg['RENAME_VARIABLE'], internalConstants.RENAME_VARIABLE_ID]);
|
||||
if (Msg['DELETE_VARIABLE']) {
|
||||
options.push([
|
||||
Blockly.Msg['DELETE_VARIABLE'].replace('%1', name),
|
||||
Blockly.internalConstants.DELETE_VARIABLE_ID
|
||||
Msg['DELETE_VARIABLE'].replace('%1', name),
|
||||
internalConstants.DELETE_VARIABLE_ID
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -432,20 +436,19 @@ Blockly.FieldVariable.dropdownCreate = function() {
|
||||
* Handle the selection of an item in the variable dropdown menu.
|
||||
* Special case the 'Rename variable...' and 'Delete variable...' options.
|
||||
* In the rename case, prompt the user for a new name.
|
||||
* @param {!Blockly.Menu} menu The Menu component clicked.
|
||||
* @param {!Blockly.MenuItem} menuItem The MenuItem selected within menu.
|
||||
* @param {!Menu} menu The Menu component clicked.
|
||||
* @param {!MenuItem} menuItem The MenuItem selected within menu.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.onItemSelected_ = function(menu, menuItem) {
|
||||
var id = menuItem.getValue();
|
||||
FieldVariable.prototype.onItemSelected_ = function(menu, menuItem) {
|
||||
const id = menuItem.getValue();
|
||||
// Handle special cases.
|
||||
if (this.sourceBlock_ && this.sourceBlock_.workspace) {
|
||||
if (id == Blockly.internalConstants.RENAME_VARIABLE_ID) {
|
||||
if (id == internalConstants.RENAME_VARIABLE_ID) {
|
||||
// Rename variable.
|
||||
Blockly.Variables.renameVariable(
|
||||
this.sourceBlock_.workspace, this.variable_);
|
||||
Variables.renameVariable(this.sourceBlock_.workspace, this.variable_);
|
||||
return;
|
||||
} else if (id == Blockly.internalConstants.DELETE_VARIABLE_ID) {
|
||||
} else if (id == internalConstants.DELETE_VARIABLE_ID) {
|
||||
// Delete variable.
|
||||
this.sourceBlock_.workspace.deleteVariableById(this.variable_.getId());
|
||||
return;
|
||||
@@ -461,8 +464,10 @@ Blockly.FieldVariable.prototype.onItemSelected_ = function(menu, menuItem) {
|
||||
* @package
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.referencesVariables = function() {
|
||||
FieldVariable.prototype.referencesVariables = function() {
|
||||
return true;
|
||||
};
|
||||
|
||||
Blockly.fieldRegistry.register('field_variable', Blockly.FieldVariable);
|
||||
fieldRegistry.register('field_variable', FieldVariable);
|
||||
|
||||
exports = FieldVariable;
|
||||
|
||||
@@ -10,36 +10,36 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.HorizontalFlyout');
|
||||
goog.module('Blockly.HorizontalFlyout');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.Block');
|
||||
goog.require('Blockly.DropDownDiv');
|
||||
goog.require('Blockly.Flyout');
|
||||
goog.require('Blockly.registry');
|
||||
goog.require('Blockly.Scrollbar');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.object');
|
||||
goog.require('Blockly.utils.Rect');
|
||||
goog.require('Blockly.utils.toolbox');
|
||||
goog.require('Blockly.WidgetDiv');
|
||||
|
||||
goog.requireType('Blockly.Options');
|
||||
goog.requireType('Blockly.utils.Coordinate');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Coordinate = goog.requireType('Blockly.utils.Coordinate');
|
||||
const DropDownDiv = goog.require('Blockly.DropDownDiv');
|
||||
const Flyout = goog.require('Blockly.Flyout');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Options = goog.requireType('Blockly.Options');
|
||||
const Rect = goog.require('Blockly.utils.Rect');
|
||||
const Scrollbar = goog.require('Blockly.Scrollbar');
|
||||
const WidgetDiv = goog.require('Blockly.WidgetDiv');
|
||||
const registry = goog.require('Blockly.registry');
|
||||
const {Position} = goog.require('Blockly.utils.toolbox');
|
||||
const {getScrollDeltaPixels} = goog.require('Blockly.utils');
|
||||
const {inherits} = goog.require('Blockly.utils.object');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a flyout.
|
||||
* @param {!Blockly.Options} workspaceOptions Dictionary of options for the
|
||||
* @param {!Options} workspaceOptions Dictionary of options for the
|
||||
* workspace.
|
||||
* @extends {Blockly.Flyout}
|
||||
* @extends {Flyout}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.HorizontalFlyout = function(workspaceOptions) {
|
||||
Blockly.HorizontalFlyout.superClass_.constructor.call(this, workspaceOptions);
|
||||
const HorizontalFlyout = function(workspaceOptions) {
|
||||
HorizontalFlyout.superClass_.constructor.call(this, workspaceOptions);
|
||||
this.horizontalLayout = true;
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.HorizontalFlyout, Blockly.Flyout);
|
||||
inherits(HorizontalFlyout, Flyout);
|
||||
|
||||
/**
|
||||
* Sets the translation of the flyout to match the scrollbars.
|
||||
@@ -48,23 +48,24 @@ Blockly.utils.object.inherits(Blockly.HorizontalFlyout, Blockly.Flyout);
|
||||
* similar x property.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.setMetrics_ = function(xyRatio) {
|
||||
HorizontalFlyout.prototype.setMetrics_ = function(xyRatio) {
|
||||
if (!this.isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var metricsManager = this.workspace_.getMetricsManager();
|
||||
var scrollMetrics = metricsManager.getScrollMetrics();
|
||||
var viewMetrics = metricsManager.getViewMetrics();
|
||||
var absoluteMetrics = metricsManager.getAbsoluteMetrics();
|
||||
const metricsManager = this.workspace_.getMetricsManager();
|
||||
const scrollMetrics = metricsManager.getScrollMetrics();
|
||||
const viewMetrics = metricsManager.getViewMetrics();
|
||||
const absoluteMetrics = metricsManager.getAbsoluteMetrics();
|
||||
|
||||
if (typeof xyRatio.x == 'number') {
|
||||
this.workspace_.scrollX =
|
||||
-(scrollMetrics.left +
|
||||
(scrollMetrics.width - viewMetrics.width) * xyRatio.x);
|
||||
(scrollMetrics.width - viewMetrics.width) * xyRatio.x);
|
||||
}
|
||||
|
||||
this.workspace_.translate(this.workspace_.scrollX + absoluteMetrics.left,
|
||||
this.workspace_.translate(
|
||||
this.workspace_.scrollX + absoluteMetrics.left,
|
||||
this.workspace_.scrollY + absoluteMetrics.top);
|
||||
};
|
||||
|
||||
@@ -72,7 +73,7 @@ Blockly.HorizontalFlyout.prototype.setMetrics_ = function(xyRatio) {
|
||||
* Calculates the x coordinate for the flyout position.
|
||||
* @return {number} X coordinate.
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.getX = function() {
|
||||
HorizontalFlyout.prototype.getX = function() {
|
||||
// X is always 0 since this is a horizontal flyout.
|
||||
return 0;
|
||||
};
|
||||
@@ -81,17 +82,17 @@ Blockly.HorizontalFlyout.prototype.getX = function() {
|
||||
* Calculates the y coordinate for the flyout position.
|
||||
* @return {number} Y coordinate.
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.getY = function() {
|
||||
HorizontalFlyout.prototype.getY = function() {
|
||||
if (!this.isVisible()) {
|
||||
return 0;
|
||||
}
|
||||
var metricsManager = this.targetWorkspace.getMetricsManager();
|
||||
var absoluteMetrics = metricsManager.getAbsoluteMetrics();
|
||||
var viewMetrics = metricsManager.getViewMetrics();
|
||||
var toolboxMetrics = metricsManager.getToolboxMetrics();
|
||||
const metricsManager = this.targetWorkspace.getMetricsManager();
|
||||
const absoluteMetrics = metricsManager.getAbsoluteMetrics();
|
||||
const viewMetrics = metricsManager.getViewMetrics();
|
||||
const toolboxMetrics = metricsManager.getToolboxMetrics();
|
||||
|
||||
var y = 0;
|
||||
var atTop = this.toolboxPosition_ == Blockly.utils.toolbox.Position.TOP;
|
||||
let y = 0;
|
||||
const atTop = this.toolboxPosition_ == Position.TOP;
|
||||
// If this flyout is not the trashcan flyout (e.g. toolbox or mutator).
|
||||
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_) {
|
||||
// If there is a category toolbox.
|
||||
@@ -129,22 +130,22 @@ Blockly.HorizontalFlyout.prototype.getY = function() {
|
||||
/**
|
||||
* Move the flyout to the edge of the workspace.
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.position = function() {
|
||||
HorizontalFlyout.prototype.position = function() {
|
||||
if (!this.isVisible() || !this.targetWorkspace.isVisible()) {
|
||||
return;
|
||||
}
|
||||
var metricsManager = this.targetWorkspace.getMetricsManager();
|
||||
var targetWorkspaceViewMetrics = metricsManager.getViewMetrics();
|
||||
const metricsManager = this.targetWorkspace.getMetricsManager();
|
||||
const targetWorkspaceViewMetrics = metricsManager.getViewMetrics();
|
||||
|
||||
// Record the width for workspace metrics.
|
||||
this.width_ = targetWorkspaceViewMetrics.width;
|
||||
|
||||
var edgeWidth = targetWorkspaceViewMetrics.width - 2 * this.CORNER_RADIUS;
|
||||
var edgeHeight = this.height_ - this.CORNER_RADIUS;
|
||||
const edgeWidth = targetWorkspaceViewMetrics.width - 2 * this.CORNER_RADIUS;
|
||||
const edgeHeight = this.height_ - this.CORNER_RADIUS;
|
||||
this.setBackgroundPath_(edgeWidth, edgeHeight);
|
||||
|
||||
var x = this.getX();
|
||||
var y = this.getY();
|
||||
const x = this.getX();
|
||||
const y = this.getY();
|
||||
|
||||
this.positionAt_(this.width_, this.height_, x, y);
|
||||
};
|
||||
@@ -157,11 +158,10 @@ Blockly.HorizontalFlyout.prototype.position = function() {
|
||||
* rounded corners.
|
||||
* @private
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.setBackgroundPath_ = function(
|
||||
width, height) {
|
||||
var atTop = this.toolboxPosition_ == Blockly.utils.toolbox.Position.TOP;
|
||||
HorizontalFlyout.prototype.setBackgroundPath_ = function(width, height) {
|
||||
const atTop = this.toolboxPosition_ == Position.TOP;
|
||||
// Start at top left.
|
||||
var path = ['M 0,' + (atTop ? 0 : this.CORNER_RADIUS)];
|
||||
const path = ['M 0,' + (atTop ? 0 : this.CORNER_RADIUS)];
|
||||
|
||||
if (atTop) {
|
||||
// Top.
|
||||
@@ -169,20 +169,24 @@ Blockly.HorizontalFlyout.prototype.setBackgroundPath_ = function(
|
||||
// Right.
|
||||
path.push('v', height);
|
||||
// Bottom.
|
||||
path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
|
||||
path.push(
|
||||
'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
|
||||
-this.CORNER_RADIUS, this.CORNER_RADIUS);
|
||||
path.push('h', -width);
|
||||
// Left.
|
||||
path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
|
||||
path.push(
|
||||
'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
|
||||
-this.CORNER_RADIUS, -this.CORNER_RADIUS);
|
||||
path.push('z');
|
||||
} else {
|
||||
// Top.
|
||||
path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
|
||||
path.push(
|
||||
'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
|
||||
this.CORNER_RADIUS, -this.CORNER_RADIUS);
|
||||
path.push('h', width);
|
||||
// Right.
|
||||
path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
|
||||
path.push(
|
||||
'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
|
||||
this.CORNER_RADIUS, this.CORNER_RADIUS);
|
||||
path.push('v', height);
|
||||
// Bottom.
|
||||
@@ -196,7 +200,7 @@ Blockly.HorizontalFlyout.prototype.setBackgroundPath_ = function(
|
||||
/**
|
||||
* Scroll the flyout to the top.
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.scrollToStart = function() {
|
||||
HorizontalFlyout.prototype.scrollToStart = function() {
|
||||
this.workspace_.scrollbar.setX(this.RTL ? Infinity : 0);
|
||||
};
|
||||
|
||||
@@ -205,20 +209,20 @@ Blockly.HorizontalFlyout.prototype.scrollToStart = function() {
|
||||
* @param {!Event} e Mouse wheel scroll event.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.wheel_ = function(e) {
|
||||
var scrollDelta = Blockly.utils.getScrollDeltaPixels(e);
|
||||
var delta = scrollDelta.x || scrollDelta.y;
|
||||
HorizontalFlyout.prototype.wheel_ = function(e) {
|
||||
const scrollDelta = getScrollDeltaPixels(e);
|
||||
const delta = scrollDelta.x || scrollDelta.y;
|
||||
|
||||
if (delta) {
|
||||
var metricsManager = this.workspace_.getMetricsManager();
|
||||
var scrollMetrics = metricsManager.getScrollMetrics();
|
||||
var viewMetrics = metricsManager.getViewMetrics();
|
||||
const metricsManager = this.workspace_.getMetricsManager();
|
||||
const scrollMetrics = metricsManager.getScrollMetrics();
|
||||
const viewMetrics = metricsManager.getViewMetrics();
|
||||
|
||||
var pos = (viewMetrics.left - scrollMetrics.left) + delta;
|
||||
const pos = (viewMetrics.left - scrollMetrics.left) + delta;
|
||||
this.workspace_.scrollbar.setX(pos);
|
||||
// When the flyout moves from a wheel event, hide WidgetDiv and DropDownDiv.
|
||||
Blockly.WidgetDiv.hide();
|
||||
Blockly.DropDownDiv.hideWithoutAnimation();
|
||||
WidgetDiv.hide();
|
||||
DropDownDiv.hideWithoutAnimation();
|
||||
}
|
||||
|
||||
// Don't scroll the page.
|
||||
@@ -233,39 +237,40 @@ Blockly.HorizontalFlyout.prototype.wheel_ = function(e) {
|
||||
* @param {!Array<number>} gaps The visible gaps between blocks.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.layout_ = function(contents, gaps) {
|
||||
HorizontalFlyout.prototype.layout_ = function(contents, gaps) {
|
||||
this.workspace_.scale = this.targetWorkspace.scale;
|
||||
var margin = this.MARGIN;
|
||||
var cursorX = margin + this.tabWidth_;
|
||||
var cursorY = margin;
|
||||
const margin = this.MARGIN;
|
||||
let cursorX = margin + this.tabWidth_;
|
||||
const cursorY = margin;
|
||||
if (this.RTL) {
|
||||
contents = contents.reverse();
|
||||
}
|
||||
|
||||
for (var i = 0, item; (item = contents[i]); i++) {
|
||||
for (let i = 0, item; (item = contents[i]); i++) {
|
||||
if (item.type == 'block') {
|
||||
var block = item.block;
|
||||
var allBlocks = block.getDescendants(false);
|
||||
for (var j = 0, child; (child = allBlocks[j]); j++) {
|
||||
const block = item.block;
|
||||
const allBlocks = block.getDescendants(false);
|
||||
for (let j = 0, child; (child = allBlocks[j]); j++) {
|
||||
// Mark blocks as being inside a flyout. This is used to detect and
|
||||
// prevent the closure of the flyout if the user right-clicks on such a
|
||||
// block.
|
||||
child.isInFlyout = true;
|
||||
}
|
||||
block.render();
|
||||
var root = block.getSvgRoot();
|
||||
var blockHW = block.getHeightWidth();
|
||||
const root = block.getSvgRoot();
|
||||
const blockHW = block.getHeightWidth();
|
||||
|
||||
// Figure out where to place the block.
|
||||
var tab = block.outputConnection ? this.tabWidth_ : 0;
|
||||
const tab = block.outputConnection ? this.tabWidth_ : 0;
|
||||
let moveX;
|
||||
if (this.RTL) {
|
||||
var moveX = cursorX + blockHW.width;
|
||||
moveX = cursorX + blockHW.width;
|
||||
} else {
|
||||
var moveX = cursorX - tab;
|
||||
moveX = cursorX - tab;
|
||||
}
|
||||
block.moveBy(moveX, cursorY);
|
||||
|
||||
var rect = this.createRect_(block, moveX, cursorY, blockHW, i);
|
||||
const rect = this.createRect_(block, moveX, cursorY, blockHW, i);
|
||||
cursorX += (blockHW.width + gaps[i]);
|
||||
|
||||
this.addBlockListeners_(root, block, rect);
|
||||
@@ -280,19 +285,19 @@ Blockly.HorizontalFlyout.prototype.layout_ = function(contents, gaps) {
|
||||
* Determine if a drag delta is toward the workspace, based on the position
|
||||
* and orientation of the flyout. This is used in determineDragIntention_ to
|
||||
* determine if a new block should be created or if the flyout should scroll.
|
||||
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* @param {!Coordinate} currentDragDeltaXY How far the pointer has
|
||||
* moved from the position at mouse down, in pixel units.
|
||||
* @return {boolean} True if the drag is toward the workspace.
|
||||
* @package
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.isDragTowardWorkspace = function(
|
||||
HorizontalFlyout.prototype.isDragTowardWorkspace = function(
|
||||
currentDragDeltaXY) {
|
||||
var dx = currentDragDeltaXY.x;
|
||||
var dy = currentDragDeltaXY.y;
|
||||
const dx = currentDragDeltaXY.x;
|
||||
const dy = currentDragDeltaXY.y;
|
||||
// Direction goes from -180 to 180, with 0 toward the right and 90 on top.
|
||||
var dragDirection = Math.atan2(dy, dx) / Math.PI * 180;
|
||||
const dragDirection = Math.atan2(dy, dx) / Math.PI * 180;
|
||||
|
||||
var range = this.dragAngleRange_;
|
||||
const range = this.dragAngleRange_;
|
||||
// Check for up or down dragging.
|
||||
if ((dragDirection < 90 + range && dragDirection > 90 - range) ||
|
||||
(dragDirection > -90 - range && dragDirection < -90 + range)) {
|
||||
@@ -304,28 +309,28 @@ Blockly.HorizontalFlyout.prototype.isDragTowardWorkspace = function(
|
||||
/**
|
||||
* Returns the bounding rectangle of the drag target area in pixel units
|
||||
* relative to viewport.
|
||||
* @return {?Blockly.utils.Rect} The component's bounding box. Null if drag
|
||||
* @return {?Rect} The component's bounding box. Null if drag
|
||||
* target area should be ignored.
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.getClientRect = function() {
|
||||
HorizontalFlyout.prototype.getClientRect = function() {
|
||||
if (!this.svgGroup_ || this.autoClose || !this.isVisible()) {
|
||||
// The bounding rectangle won't compute correctly if the flyout is closed
|
||||
// and auto-close flyouts aren't valid drag targets (or delete areas).
|
||||
return null;
|
||||
}
|
||||
|
||||
var flyoutRect = this.svgGroup_.getBoundingClientRect();
|
||||
const flyoutRect = this.svgGroup_.getBoundingClientRect();
|
||||
// BIG_NUM is offscreen padding so that blocks dragged beyond the shown flyout
|
||||
// area are still deleted. Must be larger than the largest screen size,
|
||||
// but be smaller than half Number.MAX_SAFE_INTEGER (not available on IE).
|
||||
var BIG_NUM = 1000000000;
|
||||
var top = flyoutRect.top;
|
||||
const BIG_NUM = 1000000000;
|
||||
const top = flyoutRect.top;
|
||||
|
||||
if (this.toolboxPosition_ == Blockly.utils.toolbox.Position.TOP) {
|
||||
var height = flyoutRect.height;
|
||||
return new Blockly.utils.Rect(-BIG_NUM, top + height, -BIG_NUM, BIG_NUM);
|
||||
if (this.toolboxPosition_ == Position.TOP) {
|
||||
const height = flyoutRect.height;
|
||||
return new Rect(-BIG_NUM, top + height, -BIG_NUM, BIG_NUM);
|
||||
} else { // Bottom.
|
||||
return new Blockly.utils.Rect(top, BIG_NUM, -BIG_NUM, BIG_NUM);
|
||||
return new Rect(top, BIG_NUM, -BIG_NUM, BIG_NUM);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -334,36 +339,37 @@ Blockly.HorizontalFlyout.prototype.getClientRect = function() {
|
||||
* For RTL: Lay out the blocks right-aligned.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.HorizontalFlyout.prototype.reflowInternal_ = function() {
|
||||
HorizontalFlyout.prototype.reflowInternal_ = function() {
|
||||
this.workspace_.scale = this.getFlyoutScale();
|
||||
var flyoutHeight = 0;
|
||||
var blocks = this.workspace_.getTopBlocks(false);
|
||||
for (var i = 0, block; (block = blocks[i]); i++) {
|
||||
let flyoutHeight = 0;
|
||||
const blocks = this.workspace_.getTopBlocks(false);
|
||||
for (let i = 0, block; (block = blocks[i]); i++) {
|
||||
flyoutHeight = Math.max(flyoutHeight, block.getHeightWidth().height);
|
||||
}
|
||||
var buttons = this.buttons_;
|
||||
for (var i = 0, button; (button = buttons[i]); i++) {
|
||||
const buttons = this.buttons_;
|
||||
for (let i = 0, button; (button = buttons[i]); i++) {
|
||||
flyoutHeight = Math.max(flyoutHeight, button.height);
|
||||
}
|
||||
flyoutHeight += this.MARGIN * 1.5;
|
||||
flyoutHeight *= this.workspace_.scale;
|
||||
flyoutHeight += Blockly.Scrollbar.scrollbarThickness;
|
||||
flyoutHeight += Scrollbar.scrollbarThickness;
|
||||
|
||||
if (this.height_ != flyoutHeight) {
|
||||
for (var i = 0, block; (block = blocks[i]); i++) {
|
||||
for (let i = 0, block; (block = blocks[i]); i++) {
|
||||
if (block.flyoutRect_) {
|
||||
this.moveRectToBlock_(block.flyoutRect_, block);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_ &&
|
||||
this.toolboxPosition_ == Blockly.utils.toolbox.Position.TOP &&
|
||||
this.toolboxPosition_ == Position.TOP &&
|
||||
!this.targetWorkspace.getToolbox()) {
|
||||
// This flyout is a simple toolbox. Reposition the workspace so that (0,0)
|
||||
// is in the correct position relative to the new absolute edge (ie
|
||||
// toolbox edge).
|
||||
this.targetWorkspace.translate(
|
||||
this.targetWorkspace.scrollX, this.targetWorkspace.scrollY + flyoutHeight);
|
||||
this.targetWorkspace.scrollX,
|
||||
this.targetWorkspace.scrollY + flyoutHeight);
|
||||
}
|
||||
|
||||
// Record the height for workspace metrics and .position.
|
||||
@@ -373,5 +379,8 @@ Blockly.HorizontalFlyout.prototype.reflowInternal_ = function() {
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.registry.register(Blockly.registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX,
|
||||
Blockly.registry.DEFAULT, Blockly.HorizontalFlyout);
|
||||
registry.register(
|
||||
registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX, registry.DEFAULT,
|
||||
HorizontalFlyout);
|
||||
|
||||
exports = HorizontalFlyout;
|
||||
|
||||
@@ -11,14 +11,18 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Generator');
|
||||
goog.module('Blockly.Generator');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Block');
|
||||
goog.require('Blockly.internalConstants');
|
||||
goog.require('Blockly.utils.deprecation');
|
||||
|
||||
goog.requireType('Blockly.Names');
|
||||
goog.requireType('Blockly.Workspace');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Names = goog.requireType('Blockly.Names');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Workspace = goog.requireType('Blockly.Workspace');
|
||||
const internalConstants = goog.require('Blockly.internalConstants');
|
||||
const deprecation = goog.require('Blockly.utils.deprecation');
|
||||
const {getMainWorkspace} = goog.require('Blockly');
|
||||
|
||||
|
||||
/**
|
||||
@@ -26,7 +30,7 @@ goog.requireType('Blockly.Workspace');
|
||||
* @param {string} name Language name of this generator.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Generator = function(name) {
|
||||
const Generator = function(name) {
|
||||
this.name_ = name;
|
||||
this.FUNCTION_NAME_PLACEHOLDER_REGEXP_ =
|
||||
new RegExp(this.FUNCTION_NAME_PLACEHOLDER_, 'g');
|
||||
@@ -38,7 +42,7 @@ Blockly.Generator = function(name) {
|
||||
* E.g. ' checkTimeout(%1);\n'
|
||||
* @type {?string}
|
||||
*/
|
||||
Blockly.Generator.prototype.INFINITE_LOOP_TRAP = null;
|
||||
Generator.prototype.INFINITE_LOOP_TRAP = null;
|
||||
|
||||
/**
|
||||
* Arbitrary code to inject before every statement.
|
||||
@@ -46,7 +50,7 @@ Blockly.Generator.prototype.INFINITE_LOOP_TRAP = null;
|
||||
* E.g. 'highlight(%1);\n'
|
||||
* @type {?string}
|
||||
*/
|
||||
Blockly.Generator.prototype.STATEMENT_PREFIX = null;
|
||||
Generator.prototype.STATEMENT_PREFIX = null;
|
||||
|
||||
/**
|
||||
* Arbitrary code to inject after every statement.
|
||||
@@ -54,27 +58,27 @@ Blockly.Generator.prototype.STATEMENT_PREFIX = null;
|
||||
* E.g. 'highlight(%1);\n'
|
||||
* @type {?string}
|
||||
*/
|
||||
Blockly.Generator.prototype.STATEMENT_SUFFIX = null;
|
||||
Generator.prototype.STATEMENT_SUFFIX = null;
|
||||
|
||||
/**
|
||||
* The method of indenting. Defaults to two spaces, but language generators
|
||||
* may override this to increase indent or change to tabs.
|
||||
* @type {string}
|
||||
*/
|
||||
Blockly.Generator.prototype.INDENT = ' ';
|
||||
Generator.prototype.INDENT = ' ';
|
||||
|
||||
/**
|
||||
* Maximum length for a comment before wrapping. Does not account for
|
||||
* indenting level.
|
||||
* @type {number}
|
||||
*/
|
||||
Blockly.Generator.prototype.COMMENT_WRAP = 60;
|
||||
Generator.prototype.COMMENT_WRAP = 60;
|
||||
|
||||
/**
|
||||
* List of outer-inner pairings that do NOT require parentheses.
|
||||
* @type {!Array<!Array<number>>}
|
||||
*/
|
||||
Blockly.Generator.prototype.ORDER_OVERRIDES = [];
|
||||
Generator.prototype.ORDER_OVERRIDES = [];
|
||||
|
||||
/**
|
||||
* Whether the init method has been called.
|
||||
@@ -83,24 +87,24 @@ Blockly.Generator.prototype.ORDER_OVERRIDES = [];
|
||||
* initialized. If this flag is untouched, it will have no effect.
|
||||
* @type {?boolean}
|
||||
*/
|
||||
Blockly.Generator.prototype.isInitialized = null;
|
||||
Generator.prototype.isInitialized = null;
|
||||
|
||||
/**
|
||||
* Generate code for all blocks in the workspace to the specified language.
|
||||
* @param {!Blockly.Workspace=} workspace Workspace to generate code from.
|
||||
* @param {!Workspace=} workspace Workspace to generate code from.
|
||||
* @return {string} Generated code.
|
||||
*/
|
||||
Blockly.Generator.prototype.workspaceToCode = function(workspace) {
|
||||
Generator.prototype.workspaceToCode = function(workspace) {
|
||||
if (!workspace) {
|
||||
// Backwards compatibility from before there could be multiple workspaces.
|
||||
console.warn('No workspace specified in workspaceToCode call. Guessing.');
|
||||
workspace = Blockly.getMainWorkspace();
|
||||
workspace = getMainWorkspace();
|
||||
}
|
||||
var code = [];
|
||||
let code = [];
|
||||
this.init(workspace);
|
||||
var blocks = workspace.getTopBlocks(true);
|
||||
for (var i = 0, block; (block = blocks[i]); i++) {
|
||||
var line = this.blockToCode(block);
|
||||
const blocks = workspace.getTopBlocks(true);
|
||||
for (let i = 0, block; (block = blocks[i]); i++) {
|
||||
let line = this.blockToCode(block);
|
||||
if (Array.isArray(line)) {
|
||||
// Value blocks return tuples of code and operator order.
|
||||
// Top-level blocks don't care about operator order.
|
||||
@@ -140,20 +144,20 @@ Blockly.Generator.prototype.workspaceToCode = function(workspace) {
|
||||
* @param {string} prefix The common prefix.
|
||||
* @return {string} The prefixed lines of code.
|
||||
*/
|
||||
Blockly.Generator.prototype.prefixLines = function(text, prefix) {
|
||||
Generator.prototype.prefixLines = function(text, prefix) {
|
||||
return prefix + text.replace(/(?!\n$)\n/g, '\n' + prefix);
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively spider a tree of blocks, returning all their comments.
|
||||
* @param {!Blockly.Block} block The block from which to start spidering.
|
||||
* @param {!Block} block The block from which to start spidering.
|
||||
* @return {string} Concatenated list of comments.
|
||||
*/
|
||||
Blockly.Generator.prototype.allNestedComments = function(block) {
|
||||
var comments = [];
|
||||
var blocks = block.getDescendants(true);
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
var comment = blocks[i].getCommentText();
|
||||
Generator.prototype.allNestedComments = function(block) {
|
||||
const comments = [];
|
||||
const blocks = block.getDescendants(true);
|
||||
for (let i = 0; i < blocks.length; i++) {
|
||||
const comment = blocks[i].getCommentText();
|
||||
if (comment) {
|
||||
comments.push(comment);
|
||||
}
|
||||
@@ -168,13 +172,13 @@ Blockly.Generator.prototype.allNestedComments = function(block) {
|
||||
/**
|
||||
* Generate code for the specified block (and attached blocks).
|
||||
* The generator must be initialized before calling this function.
|
||||
* @param {Blockly.Block} block The block to generate code for.
|
||||
* @param {Block} block The block to generate code for.
|
||||
* @param {boolean=} opt_thisOnly True to generate code for only this statement.
|
||||
* @return {string|!Array} For statement blocks, the generated code.
|
||||
* For value blocks, an array containing the generated code and an
|
||||
* operator order value. Returns '' if block is null.
|
||||
*/
|
||||
Blockly.Generator.prototype.blockToCode = function(block, opt_thisOnly) {
|
||||
Generator.prototype.blockToCode = function(block, opt_thisOnly) {
|
||||
if (this.isInitialized === false) {
|
||||
console.warn(
|
||||
'Generator init was not called before blockToCode was called.');
|
||||
@@ -191,16 +195,17 @@ Blockly.Generator.prototype.blockToCode = function(block, opt_thisOnly) {
|
||||
return opt_thisOnly ? '' : this.blockToCode(block.getChildren(false)[0]);
|
||||
}
|
||||
|
||||
var func = this[block.type];
|
||||
const func = this[block.type];
|
||||
if (typeof func != 'function') {
|
||||
throw Error('Language "' + this.name_ + '" does not know how to generate ' +
|
||||
throw Error(
|
||||
'Language "' + this.name_ + '" does not know how to generate ' +
|
||||
'code for block type "' + block.type + '".');
|
||||
}
|
||||
// First argument to func.call is the value of 'this' in the generator.
|
||||
// Prior to 24 September 2013 'this' was the only way to access the block.
|
||||
// The current preferred method of accessing the block is through the second
|
||||
// argument to func.call, which becomes the first parameter to the generator.
|
||||
var code = func.call(block, block);
|
||||
let code = func.call(block, block);
|
||||
if (Array.isArray(code)) {
|
||||
// Value blocks return tuples of code and operator order.
|
||||
if (!block.outputConnection) {
|
||||
@@ -224,22 +229,22 @@ Blockly.Generator.prototype.blockToCode = function(block, opt_thisOnly) {
|
||||
|
||||
/**
|
||||
* Generate code representing the specified value input.
|
||||
* @param {!Blockly.Block} block The block containing the input.
|
||||
* @param {!Block} block The block containing the input.
|
||||
* @param {string} name The name of the input.
|
||||
* @param {number} outerOrder The maximum binding strength (minimum order value)
|
||||
* of any operators adjacent to "block".
|
||||
* @return {string} Generated code or '' if no blocks are connected or the
|
||||
* specified input does not exist.
|
||||
*/
|
||||
Blockly.Generator.prototype.valueToCode = function(block, name, outerOrder) {
|
||||
Generator.prototype.valueToCode = function(block, name, outerOrder) {
|
||||
if (isNaN(outerOrder)) {
|
||||
throw TypeError('Expecting valid order from block: ' + block.type);
|
||||
}
|
||||
var targetBlock = block.getInputTargetBlock(name);
|
||||
const targetBlock = block.getInputTargetBlock(name);
|
||||
if (!targetBlock) {
|
||||
return '';
|
||||
}
|
||||
var tuple = this.blockToCode(targetBlock);
|
||||
const tuple = this.blockToCode(targetBlock);
|
||||
if (tuple === '') {
|
||||
// Disabled block.
|
||||
return '';
|
||||
@@ -249,20 +254,20 @@ Blockly.Generator.prototype.valueToCode = function(block, name, outerOrder) {
|
||||
if (!Array.isArray(tuple)) {
|
||||
throw TypeError('Expecting tuple from value block: ' + targetBlock.type);
|
||||
}
|
||||
var code = tuple[0];
|
||||
var innerOrder = tuple[1];
|
||||
let code = tuple[0];
|
||||
const innerOrder = tuple[1];
|
||||
if (isNaN(innerOrder)) {
|
||||
throw TypeError('Expecting valid order from value block: ' +
|
||||
targetBlock.type);
|
||||
throw TypeError(
|
||||
'Expecting valid order from value block: ' + targetBlock.type);
|
||||
}
|
||||
if (!code) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Add parentheses if needed.
|
||||
var parensNeeded = false;
|
||||
var outerOrderClass = Math.floor(outerOrder);
|
||||
var innerOrderClass = Math.floor(innerOrder);
|
||||
let parensNeeded = false;
|
||||
const outerOrderClass = Math.floor(outerOrder);
|
||||
const innerOrderClass = Math.floor(innerOrder);
|
||||
if (outerOrderClass <= innerOrderClass) {
|
||||
if (outerOrderClass == innerOrderClass &&
|
||||
(outerOrderClass == 0 || outerOrderClass == 99)) {
|
||||
@@ -276,7 +281,7 @@ Blockly.Generator.prototype.valueToCode = function(block, name, outerOrder) {
|
||||
// wrap the code in parentheses.
|
||||
parensNeeded = true;
|
||||
// Check for special exceptions.
|
||||
for (var i = 0; i < this.ORDER_OVERRIDES.length; i++) {
|
||||
for (let i = 0; i < this.ORDER_OVERRIDES.length; i++) {
|
||||
if (this.ORDER_OVERRIDES[i][0] == outerOrder &&
|
||||
this.ORDER_OVERRIDES[i][1] == innerOrder) {
|
||||
parensNeeded = false;
|
||||
@@ -298,17 +303,18 @@ Blockly.Generator.prototype.valueToCode = function(block, name, outerOrder) {
|
||||
* statement input. Indent the code.
|
||||
* This is mainly used in generators. When trying to generate code to evaluate
|
||||
* look at using workspaceToCode or blockToCode.
|
||||
* @param {!Blockly.Block} block The block containing the input.
|
||||
* @param {!Block} block The block containing the input.
|
||||
* @param {string} name The name of the input.
|
||||
* @return {string} Generated code or '' if no blocks are connected.
|
||||
*/
|
||||
Blockly.Generator.prototype.statementToCode = function(block, name) {
|
||||
var targetBlock = block.getInputTargetBlock(name);
|
||||
var code = this.blockToCode(targetBlock);
|
||||
Generator.prototype.statementToCode = function(block, name) {
|
||||
const targetBlock = block.getInputTargetBlock(name);
|
||||
let code = this.blockToCode(targetBlock);
|
||||
// Value blocks must return code and order of operations info.
|
||||
// Statement blocks must only return code.
|
||||
if (typeof code != 'string') {
|
||||
throw TypeError('Expecting code from statement block: ' +
|
||||
throw TypeError(
|
||||
'Expecting code from statement block: ' +
|
||||
(targetBlock && targetBlock.type));
|
||||
}
|
||||
if (code) {
|
||||
@@ -323,21 +329,24 @@ Blockly.Generator.prototype.statementToCode = function(block, name) {
|
||||
* statement executes), and a statement prefix to the end of the loop block
|
||||
* (right before the loop statement executes).
|
||||
* @param {string} branch Code for loop contents.
|
||||
* @param {!Blockly.Block} block Enclosing block.
|
||||
* @param {!Block} block Enclosing block.
|
||||
* @return {string} Loop contents, with infinite loop trap added.
|
||||
*/
|
||||
Blockly.Generator.prototype.addLoopTrap = function(branch, block) {
|
||||
Generator.prototype.addLoopTrap = function(branch, block) {
|
||||
if (this.INFINITE_LOOP_TRAP) {
|
||||
branch = this.prefixLines(this.injectId(this.INFINITE_LOOP_TRAP, block),
|
||||
this.INDENT) + branch;
|
||||
branch = this.prefixLines(
|
||||
this.injectId(this.INFINITE_LOOP_TRAP, block), this.INDENT) +
|
||||
branch;
|
||||
}
|
||||
if (this.STATEMENT_SUFFIX && !block.suppressPrefixSuffix) {
|
||||
branch = this.prefixLines(this.injectId(this.STATEMENT_SUFFIX, block),
|
||||
this.INDENT) + branch;
|
||||
branch = this.prefixLines(
|
||||
this.injectId(this.STATEMENT_SUFFIX, block), this.INDENT) +
|
||||
branch;
|
||||
}
|
||||
if (this.STATEMENT_PREFIX && !block.suppressPrefixSuffix) {
|
||||
branch = branch + this.prefixLines(this.injectId(this.STATEMENT_PREFIX,
|
||||
block), this.INDENT);
|
||||
branch = branch +
|
||||
this.prefixLines(
|
||||
this.injectId(this.STATEMENT_PREFIX, block), this.INDENT);
|
||||
}
|
||||
return branch;
|
||||
};
|
||||
@@ -346,11 +355,11 @@ Blockly.Generator.prototype.addLoopTrap = function(branch, block) {
|
||||
* Inject a block ID into a message to replace '%1'.
|
||||
* Used for STATEMENT_PREFIX, STATEMENT_SUFFIX, and INFINITE_LOOP_TRAP.
|
||||
* @param {string} msg Code snippet with '%1'.
|
||||
* @param {!Blockly.Block} block Block which has an ID.
|
||||
* @param {!Block} block Block which has an ID.
|
||||
* @return {string} Code snippet with ID.
|
||||
*/
|
||||
Blockly.Generator.prototype.injectId = function(msg, block) {
|
||||
var id = block.id.replace(/\$/g, '$$$$'); // Issue 251.
|
||||
Generator.prototype.injectId = function(msg, block) {
|
||||
const id = block.id.replace(/\$/g, '$$$$'); // Issue 251.
|
||||
return msg.replace(/%1/g, '\'' + id + '\'');
|
||||
};
|
||||
|
||||
@@ -359,33 +368,33 @@ Blockly.Generator.prototype.injectId = function(msg, block) {
|
||||
* @type {string}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Generator.prototype.RESERVED_WORDS_ = '';
|
||||
Generator.prototype.RESERVED_WORDS_ = '';
|
||||
|
||||
/**
|
||||
* Add one or more words to the list of reserved words for this language.
|
||||
* @param {string} words Comma-separated list of words to add to the list.
|
||||
* No spaces. Duplicates are ok.
|
||||
*/
|
||||
Blockly.Generator.prototype.addReservedWords = function(words) {
|
||||
Generator.prototype.addReservedWords = function(words) {
|
||||
this.RESERVED_WORDS_ += words + ',';
|
||||
};
|
||||
|
||||
/**
|
||||
* This is used as a placeholder in functions defined using
|
||||
* Blockly.Generator.provideFunction_. It must not be legal code that could
|
||||
* Generator.provideFunction_. It must not be legal code that could
|
||||
* legitimately appear in a function definition (or comment), and it must
|
||||
* not confuse the regular expression parser.
|
||||
* @type {string}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Generator.prototype.FUNCTION_NAME_PLACEHOLDER_ = '{leCUI8hutHZI4480Dc}';
|
||||
Generator.prototype.FUNCTION_NAME_PLACEHOLDER_ = '{leCUI8hutHZI4480Dc}';
|
||||
|
||||
/**
|
||||
* A dictionary of definitions to be printed before the code.
|
||||
* @type {!Object|undefined}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Generator.prototype.definitions_;
|
||||
Generator.prototype.definitions_;
|
||||
|
||||
/**
|
||||
* A dictionary mapping desired function names in definitions_ to actual
|
||||
@@ -393,36 +402,34 @@ Blockly.Generator.prototype.definitions_;
|
||||
* @type {!Object|undefined}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Generator.prototype.functionNames_;
|
||||
Generator.prototype.functionNames_;
|
||||
|
||||
/**
|
||||
* A database of variable and procedure names.
|
||||
* @type {!Blockly.Names|undefined}
|
||||
* @type {!Names|undefined}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Generator.prototype.nameDB_;
|
||||
Generator.prototype.nameDB_;
|
||||
|
||||
Object.defineProperty(Blockly.Generator.prototype, 'variableDB_', {
|
||||
Object.defineProperty(Generator.prototype, 'variableDB_', {
|
||||
/**
|
||||
* Getter.
|
||||
* @deprecated 'variableDB_' was renamed to 'nameDB_' (May 2021).
|
||||
* @this {Blockly.Generator}
|
||||
* @return {!Blockly.Names|undefined} Name database.
|
||||
* @this {Generator}
|
||||
* @return {!Names|undefined} Name database.
|
||||
*/
|
||||
get: function() {
|
||||
Blockly.utils.deprecation.warn(
|
||||
'variableDB_', 'May 2021', 'May 2026', 'nameDB_');
|
||||
deprecation.warn('variableDB_', 'May 2021', 'May 2026', 'nameDB_');
|
||||
return this.nameDB_;
|
||||
},
|
||||
/**
|
||||
* Setter.
|
||||
* @deprecated 'variableDB_' was renamed to 'nameDB_' (May 2021).
|
||||
* @this {Blockly.Generator}
|
||||
* @param {!Blockly.Names|undefined} nameDb New name database.
|
||||
* @this {Generator}
|
||||
* @param {!Names|undefined} nameDb New name database.
|
||||
*/
|
||||
set: function(nameDb) {
|
||||
Blockly.utils.deprecation.warn(
|
||||
'variableDB_', 'May 2021', 'May 2026', 'nameDB_');
|
||||
deprecation.warn('variableDB_', 'May 2021', 'May 2026', 'nameDB_');
|
||||
this.nameDB_ = nameDb;
|
||||
}
|
||||
});
|
||||
@@ -439,7 +446,7 @@ Object.defineProperty(Blockly.Generator.prototype, 'variableDB_', {
|
||||
* "listRandom", not "random"). There is no danger of colliding with reserved
|
||||
* words, or user-defined variable or procedure names.
|
||||
*
|
||||
* The code gets output when Blockly.Generator.finish() is called.
|
||||
* The code gets output when Generator.finish() is called.
|
||||
*
|
||||
* @param {string} desiredName The desired name of the function
|
||||
* (e.g. mathIsPrime).
|
||||
@@ -448,18 +455,18 @@ Object.defineProperty(Blockly.Generator.prototype, 'variableDB_', {
|
||||
* from desiredName if the former has already been taken by the user.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Generator.prototype.provideFunction_ = function(desiredName, code) {
|
||||
Generator.prototype.provideFunction_ = function(desiredName, code) {
|
||||
if (!this.definitions_[desiredName]) {
|
||||
var functionName = this.nameDB_.getDistinctName(
|
||||
desiredName, Blockly.internalConstants.PROCEDURE_CATEGORY_NAME);
|
||||
const functionName = this.nameDB_.getDistinctName(
|
||||
desiredName, internalConstants.PROCEDURE_CATEGORY_NAME);
|
||||
this.functionNames_[desiredName] = functionName;
|
||||
var codeText = code.join('\n').replace(
|
||||
let codeText = code.join('\n').replace(
|
||||
this.FUNCTION_NAME_PLACEHOLDER_REGEXP_, functionName);
|
||||
// Change all ' ' indents into the desired indent.
|
||||
// To avoid an infinite loop of replacements, change all indents to '\0'
|
||||
// character first, then replace them all with the indent.
|
||||
// We are assuming that no provided functions contain a literal null char.
|
||||
var oldCodeText;
|
||||
let oldCodeText;
|
||||
while (oldCodeText != codeText) {
|
||||
oldCodeText = codeText;
|
||||
codeText = codeText.replace(/^(( {2})*) {2}/gm, '$1\0');
|
||||
@@ -474,9 +481,9 @@ Blockly.Generator.prototype.provideFunction_ = function(desiredName, code) {
|
||||
* Hook for code to run before code generation starts.
|
||||
* Subclasses may override this, e.g. to initialise the database of variable
|
||||
* names.
|
||||
* @param {!Blockly.Workspace} _workspace Workspace to generate code from.
|
||||
* @param {!Workspace} _workspace Workspace to generate code from.
|
||||
*/
|
||||
Blockly.Generator.prototype.init = function(_workspace) {
|
||||
Generator.prototype.init = function(_workspace) {
|
||||
// Optionally override
|
||||
// Create a dictionary of definitions to be printed before the code.
|
||||
this.definitions_ = Object.create(null);
|
||||
@@ -492,14 +499,14 @@ Blockly.Generator.prototype.init = function(_workspace) {
|
||||
* Subclasses may override this, e.g. to generate code for statements following
|
||||
* the block, or to handle comments for the specified block and any connected
|
||||
* value blocks.
|
||||
* @param {!Blockly.Block} _block The current block.
|
||||
* @param {!Block} _block The current block.
|
||||
* @param {string} code The code created for this block.
|
||||
* @param {boolean=} _opt_thisOnly True to generate code for only this
|
||||
* statement.
|
||||
* @return {string} Code with comments and subsequent blocks added.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Generator.prototype.scrub_ = function(_block, code, _opt_thisOnly) {
|
||||
Generator.prototype.scrub_ = function(_block, code, _opt_thisOnly) {
|
||||
// Optionally override
|
||||
return code;
|
||||
};
|
||||
@@ -511,7 +518,7 @@ Blockly.Generator.prototype.scrub_ = function(_block, code, _opt_thisOnly) {
|
||||
* @param {string} code Generated code.
|
||||
* @return {string} Completed code.
|
||||
*/
|
||||
Blockly.Generator.prototype.finish = function(code) {
|
||||
Generator.prototype.finish = function(code) {
|
||||
// Optionally override
|
||||
// Clean up temporary data.
|
||||
delete this.definitions_;
|
||||
@@ -527,7 +534,9 @@ Blockly.Generator.prototype.finish = function(code) {
|
||||
* @param {string} line Line of generated code.
|
||||
* @return {string} Legal line of code.
|
||||
*/
|
||||
Blockly.Generator.prototype.scrubNakedValue = function(line) {
|
||||
Generator.prototype.scrubNakedValue = function(line) {
|
||||
// Optionally override
|
||||
return line;
|
||||
};
|
||||
|
||||
exports = Generator;
|
||||
|
||||
69
core/grid.js
69
core/grid.js
@@ -11,11 +11,12 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Grid');
|
||||
goog.module('Blockly.Grid');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
goog.require('Blockly.utils.userAgent');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const userAgent = goog.require('Blockly.utils.userAgent');
|
||||
|
||||
|
||||
/**
|
||||
@@ -27,7 +28,7 @@ goog.require('Blockly.utils.userAgent');
|
||||
* https://developers.google.com/blockly/guides/configure/web/grid
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Grid = function(pattern, options) {
|
||||
const Grid = function(pattern, options) {
|
||||
/**
|
||||
* The grid's SVG pattern, created during injection.
|
||||
* @type {!SVGElement}
|
||||
@@ -61,8 +62,8 @@ Blockly.Grid = function(pattern, options) {
|
||||
* @type {SVGElement}
|
||||
* @private
|
||||
*/
|
||||
this.line2_ = this.line1_ &&
|
||||
(/** @type {SVGElement} */ (this.line1_.nextSibling));
|
||||
this.line2_ =
|
||||
this.line1_ && (/** @type {SVGElement} */ (this.line1_.nextSibling));
|
||||
|
||||
/**
|
||||
* Whether blocks should snap to the grid.
|
||||
@@ -78,14 +79,14 @@ Blockly.Grid = function(pattern, options) {
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
Blockly.Grid.prototype.scale_ = 1;
|
||||
Grid.prototype.scale_ = 1;
|
||||
|
||||
/**
|
||||
* Dispose of this grid and unlink from the DOM.
|
||||
* @package
|
||||
* @suppress {checkTypes}
|
||||
*/
|
||||
Blockly.Grid.prototype.dispose = function() {
|
||||
Grid.prototype.dispose = function() {
|
||||
this.gridPattern_ = null;
|
||||
};
|
||||
|
||||
@@ -94,7 +95,7 @@ Blockly.Grid.prototype.dispose = function() {
|
||||
* @return {boolean} True if blocks should snap, false otherwise.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Grid.prototype.shouldSnap = function() {
|
||||
Grid.prototype.shouldSnap = function() {
|
||||
return this.snapToGrid_;
|
||||
};
|
||||
|
||||
@@ -103,7 +104,7 @@ Blockly.Grid.prototype.shouldSnap = function() {
|
||||
* @return {number} The spacing of the grid points.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Grid.prototype.getSpacing = function() {
|
||||
Grid.prototype.getSpacing = function() {
|
||||
return this.spacing_;
|
||||
};
|
||||
|
||||
@@ -113,7 +114,7 @@ Blockly.Grid.prototype.getSpacing = function() {
|
||||
* @return {string} The pattern ID.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Grid.prototype.getPatternId = function() {
|
||||
Grid.prototype.getPatternId = function() {
|
||||
return this.gridPattern_.id;
|
||||
};
|
||||
|
||||
@@ -122,17 +123,17 @@ Blockly.Grid.prototype.getPatternId = function() {
|
||||
* @param {number} scale The new workspace scale.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Grid.prototype.update = function(scale) {
|
||||
Grid.prototype.update = function(scale) {
|
||||
this.scale_ = scale;
|
||||
// MSIE freaks if it sees a 0x0 pattern, so set empty patterns to 100x100.
|
||||
var safeSpacing = (this.spacing_ * scale) || 100;
|
||||
const safeSpacing = (this.spacing_ * scale) || 100;
|
||||
|
||||
this.gridPattern_.setAttribute('width', safeSpacing);
|
||||
this.gridPattern_.setAttribute('height', safeSpacing);
|
||||
|
||||
var half = Math.floor(this.spacing_ / 2) + 0.5;
|
||||
var start = half - this.length_ / 2;
|
||||
var end = half + this.length_ / 2;
|
||||
let half = Math.floor(this.spacing_ / 2) + 0.5;
|
||||
let start = half - this.length_ / 2;
|
||||
let end = half + this.length_ / 2;
|
||||
|
||||
half *= scale;
|
||||
start *= scale;
|
||||
@@ -153,8 +154,7 @@ Blockly.Grid.prototype.update = function(scale) {
|
||||
* @param {number} y2 The new y end position of the line (in px).
|
||||
* @private
|
||||
*/
|
||||
Blockly.Grid.prototype.setLineAttributes_ = function(line, width,
|
||||
x1, x2, y1, y2) {
|
||||
Grid.prototype.setLineAttributes_ = function(line, width, x1, x2, y1, y2) {
|
||||
if (line) {
|
||||
line.setAttribute('stroke-width', width);
|
||||
line.setAttribute('x1', x1);
|
||||
@@ -171,11 +171,11 @@ Blockly.Grid.prototype.setLineAttributes_ = function(line, width,
|
||||
* @param {number} y The new y position of the grid (in px).
|
||||
* @package
|
||||
*/
|
||||
Blockly.Grid.prototype.moveTo = function(x, y) {
|
||||
Grid.prototype.moveTo = function(x, y) {
|
||||
this.gridPattern_.setAttribute('x', x);
|
||||
this.gridPattern_.setAttribute('y', y);
|
||||
|
||||
if (Blockly.utils.userAgent.IE || Blockly.utils.userAgent.EDGE) {
|
||||
if (userAgent.IE || userAgent.EDGE) {
|
||||
// IE/Edge doesn't notice that the x/y offsets have changed.
|
||||
// Force an update.
|
||||
this.update(this.scale_);
|
||||
@@ -190,33 +190,30 @@ Blockly.Grid.prototype.moveTo = function(x, y) {
|
||||
* @return {!SVGElement} The SVG element for the grid pattern.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Grid.createDom = function(rnd, gridOptions, defs) {
|
||||
Grid.createDom = function(rnd, gridOptions, defs) {
|
||||
/*
|
||||
<pattern id="blocklyGridPattern837493" patternUnits="userSpaceOnUse">
|
||||
<rect stroke="#888" />
|
||||
<rect stroke="#888" />
|
||||
</pattern>
|
||||
*/
|
||||
var gridPattern = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.PATTERN,
|
||||
{
|
||||
'id': 'blocklyGridPattern' + rnd,
|
||||
'patternUnits': 'userSpaceOnUse'
|
||||
}, defs);
|
||||
const gridPattern = dom.createSvgElement(
|
||||
Svg.PATTERN,
|
||||
{'id': 'blocklyGridPattern' + rnd, 'patternUnits': 'userSpaceOnUse'},
|
||||
defs);
|
||||
if (gridOptions['length'] > 0 && gridOptions['spacing'] > 0) {
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.LINE,
|
||||
{'stroke': gridOptions['colour']}, gridPattern);
|
||||
dom.createSvgElement(
|
||||
Svg.LINE, {'stroke': gridOptions['colour']}, gridPattern);
|
||||
if (gridOptions['length'] > 1) {
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.LINE,
|
||||
{'stroke': gridOptions['colour']}, gridPattern);
|
||||
dom.createSvgElement(
|
||||
Svg.LINE, {'stroke': gridOptions['colour']}, gridPattern);
|
||||
}
|
||||
// x1, y1, x1, x2 properties will be set later in update.
|
||||
} else {
|
||||
// Edge 16 doesn't handle empty patterns
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.LINE, {}, gridPattern);
|
||||
dom.createSvgElement(Svg.LINE, {}, gridPattern);
|
||||
}
|
||||
return gridPattern;
|
||||
};
|
||||
|
||||
exports = Grid;
|
||||
|
||||
97
core/icon.js
97
core/icon.js
@@ -10,29 +10,31 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Icon');
|
||||
goog.module('Blockly.Icon');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.browserEvents');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.Size');
|
||||
goog.require('Blockly.utils.Svg');
|
||||
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.Bubble');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Bubble = goog.requireType('Blockly.Bubble');
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
const Size = goog.require('Blockly.utils.Size');
|
||||
const Svg = goog.require('Blockly.utils.Svg');
|
||||
const browserEvents = goog.require('Blockly.browserEvents');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const {getRelativeXY, isRightButton} = goog.require('Blockly.utils');
|
||||
|
||||
|
||||
/**
|
||||
* Class for an icon.
|
||||
* @param {Blockly.BlockSvg} block The block associated with this icon.
|
||||
* @param {BlockSvg} block The block associated with this icon.
|
||||
* @constructor
|
||||
* @abstract
|
||||
*/
|
||||
Blockly.Icon = function(block) {
|
||||
const Icon = function(block) {
|
||||
/**
|
||||
* The block this icon is attached to.
|
||||
* @type {Blockly.BlockSvg}
|
||||
* @type {BlockSvg}
|
||||
* @protected
|
||||
*/
|
||||
this.block_ = block;
|
||||
@@ -47,31 +49,32 @@ Blockly.Icon = function(block) {
|
||||
/**
|
||||
* Does this icon get hidden when the block is collapsed.
|
||||
*/
|
||||
Blockly.Icon.prototype.collapseHidden = true;
|
||||
Icon.prototype.collapseHidden = true;
|
||||
|
||||
/**
|
||||
* Height and width of icons.
|
||||
* @const
|
||||
*/
|
||||
Blockly.Icon.prototype.SIZE = 17;
|
||||
Icon.prototype.SIZE = 17;
|
||||
|
||||
/**
|
||||
* Bubble UI (if visible).
|
||||
* @type {?Blockly.Bubble}
|
||||
* @type {?Bubble}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Icon.prototype.bubble_ = null;
|
||||
Icon.prototype.bubble_ = null;
|
||||
|
||||
/**
|
||||
* Absolute coordinate of icon's center.
|
||||
* @type {?Blockly.utils.Coordinate}
|
||||
* @type {?Coordinate}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Icon.prototype.iconXY_ = null;
|
||||
Icon.prototype.iconXY_ = null;
|
||||
|
||||
/**
|
||||
* Create the icon on the block.
|
||||
*/
|
||||
Blockly.Icon.prototype.createIcon = function() {
|
||||
Icon.prototype.createIcon = function() {
|
||||
if (this.iconGroup_) {
|
||||
// Icon already exists.
|
||||
return;
|
||||
@@ -81,17 +84,16 @@ Blockly.Icon.prototype.createIcon = function() {
|
||||
...
|
||||
</g>
|
||||
*/
|
||||
this.iconGroup_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.Svg.G,
|
||||
{'class': 'blocklyIconGroup'}, null);
|
||||
this.iconGroup_ =
|
||||
dom.createSvgElement(Svg.G, {'class': 'blocklyIconGroup'}, null);
|
||||
if (this.block_.isInFlyout) {
|
||||
Blockly.utils.dom.addClass(
|
||||
dom.addClass(
|
||||
/** @type {!Element} */ (this.iconGroup_), 'blocklyIconGroupReadonly');
|
||||
}
|
||||
this.drawIcon_(this.iconGroup_);
|
||||
|
||||
this.block_.getSvgRoot().appendChild(this.iconGroup_);
|
||||
Blockly.browserEvents.conditionalBind(
|
||||
browserEvents.conditionalBind(
|
||||
this.iconGroup_, 'mouseup', this, this.iconClick_);
|
||||
this.updateEditable();
|
||||
};
|
||||
@@ -99,9 +101,9 @@ Blockly.Icon.prototype.createIcon = function() {
|
||||
/**
|
||||
* Dispose of this icon.
|
||||
*/
|
||||
Blockly.Icon.prototype.dispose = function() {
|
||||
Icon.prototype.dispose = function() {
|
||||
// Dispose of and unlink the icon.
|
||||
Blockly.utils.dom.removeNode(this.iconGroup_);
|
||||
dom.removeNode(this.iconGroup_);
|
||||
this.iconGroup_ = null;
|
||||
// Dispose of and unlink the bubble.
|
||||
this.setVisible(false);
|
||||
@@ -111,7 +113,7 @@ Blockly.Icon.prototype.dispose = function() {
|
||||
/**
|
||||
* Add or remove the UI indicating if this icon may be clicked or not.
|
||||
*/
|
||||
Blockly.Icon.prototype.updateEditable = function() {
|
||||
Icon.prototype.updateEditable = function() {
|
||||
// No-op on the base class.
|
||||
};
|
||||
|
||||
@@ -119,7 +121,7 @@ Blockly.Icon.prototype.updateEditable = function() {
|
||||
* Is the associated bubble visible?
|
||||
* @return {boolean} True if the bubble is visible.
|
||||
*/
|
||||
Blockly.Icon.prototype.isVisible = function() {
|
||||
Icon.prototype.isVisible = function() {
|
||||
return !!this.bubble_;
|
||||
};
|
||||
|
||||
@@ -128,12 +130,12 @@ Blockly.Icon.prototype.isVisible = function() {
|
||||
* @param {!Event} e Mouse click event.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Icon.prototype.iconClick_ = function(e) {
|
||||
Icon.prototype.iconClick_ = function(e) {
|
||||
if (this.block_.workspace.isDragging()) {
|
||||
// Drag operation is concluding. Don't open the editor.
|
||||
return;
|
||||
}
|
||||
if (!this.block_.isInFlyout && !Blockly.utils.isRightButton(e)) {
|
||||
if (!this.block_.isInFlyout && !isRightButton(e)) {
|
||||
this.setVisible(!this.isVisible());
|
||||
}
|
||||
};
|
||||
@@ -141,7 +143,7 @@ Blockly.Icon.prototype.iconClick_ = function(e) {
|
||||
/**
|
||||
* Change the colour of the associated bubble to match its block.
|
||||
*/
|
||||
Blockly.Icon.prototype.applyColour = function() {
|
||||
Icon.prototype.applyColour = function() {
|
||||
if (this.isVisible()) {
|
||||
this.bubble_.setColour(this.block_.style.colourPrimary);
|
||||
}
|
||||
@@ -149,9 +151,9 @@ Blockly.Icon.prototype.applyColour = function() {
|
||||
|
||||
/**
|
||||
* Notification that the icon has moved. Update the arrow accordingly.
|
||||
* @param {!Blockly.utils.Coordinate} xy Absolute location in workspace coordinates.
|
||||
* @param {!Coordinate} xy Absolute location in workspace coordinates.
|
||||
*/
|
||||
Blockly.Icon.prototype.setIconLocation = function(xy) {
|
||||
Icon.prototype.setIconLocation = function(xy) {
|
||||
this.iconXY_ = xy;
|
||||
if (this.isVisible()) {
|
||||
this.bubble_.setAnchorLocation(xy);
|
||||
@@ -162,25 +164,25 @@ Blockly.Icon.prototype.setIconLocation = function(xy) {
|
||||
* Notification that the icon has moved, but we don't really know where.
|
||||
* Recompute the icon's location from scratch.
|
||||
*/
|
||||
Blockly.Icon.prototype.computeIconLocation = function() {
|
||||
Icon.prototype.computeIconLocation = function() {
|
||||
// Find coordinates for the centre of the icon and update the arrow.
|
||||
var blockXY = this.block_.getRelativeToSurfaceXY();
|
||||
var iconXY = Blockly.utils.getRelativeXY(
|
||||
const blockXY = this.block_.getRelativeToSurfaceXY();
|
||||
const iconXY = getRelativeXY(
|
||||
/** @type {!SVGElement} */ (this.iconGroup_));
|
||||
var newXY = new Blockly.utils.Coordinate(
|
||||
const newXY = new Coordinate(
|
||||
blockXY.x + iconXY.x + this.SIZE / 2,
|
||||
blockXY.y + iconXY.y + this.SIZE / 2);
|
||||
if (!Blockly.utils.Coordinate.equals(this.getIconLocation(), newXY)) {
|
||||
if (!Coordinate.equals(this.getIconLocation(), newXY)) {
|
||||
this.setIconLocation(newXY);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the center of the block's icon relative to the surface.
|
||||
* @return {?Blockly.utils.Coordinate} Object with x and y properties in
|
||||
* @return {?Coordinate} Object with x and y properties in
|
||||
* workspace coordinates.
|
||||
*/
|
||||
Blockly.Icon.prototype.getIconLocation = function() {
|
||||
Icon.prototype.getIconLocation = function() {
|
||||
return this.iconXY_;
|
||||
};
|
||||
|
||||
@@ -188,12 +190,11 @@ Blockly.Icon.prototype.getIconLocation = function() {
|
||||
* Get the size of the icon as used for rendering.
|
||||
* This differs from the actual size of the icon, because it bulges slightly
|
||||
* out of its row rather than increasing the height of its row.
|
||||
* @return {!Blockly.utils.Size} Height and width.
|
||||
* @return {!Size} Height and width.
|
||||
*/
|
||||
// TODO (#2562): Remove getCorrectedSize.
|
||||
Blockly.Icon.prototype.getCorrectedSize = function() {
|
||||
return new Blockly.utils.Size(
|
||||
Blockly.Icon.prototype.SIZE, Blockly.Icon.prototype.SIZE - 2);
|
||||
Icon.prototype.getCorrectedSize = function() {
|
||||
return new Size(Icon.prototype.SIZE, Icon.prototype.SIZE - 2);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -201,10 +202,12 @@ Blockly.Icon.prototype.getCorrectedSize = function() {
|
||||
* @param {!Element} group The icon group.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Icon.prototype.drawIcon_;
|
||||
Icon.prototype.drawIcon_;
|
||||
|
||||
/**
|
||||
* Show or hide the icon.
|
||||
* @param {boolean} visible True if the icon should be visible.
|
||||
*/
|
||||
Blockly.Icon.prototype.setVisible;
|
||||
Icon.prototype.setVisible;
|
||||
|
||||
exports = Icon;
|
||||
|
||||
113
core/input.js
113
core/input.js
@@ -10,31 +10,36 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Input');
|
||||
goog.module('Blockly.Input');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.Connection');
|
||||
goog.require('Blockly.fieldRegistry');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Block = goog.requireType('Blockly.Block');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Connection = goog.require('Blockly.Connection');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Field = goog.requireType('Blockly.Field');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const RenderedConnection = goog.requireType('Blockly.RenderedConnection');
|
||||
const constants = goog.require('Blockly.constants');
|
||||
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
||||
const inputTypes = goog.require('Blockly.inputTypes');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('Blockly.FieldLabel');
|
||||
goog.require('Blockly.inputTypes');
|
||||
|
||||
goog.requireType('Blockly.Block');
|
||||
goog.requireType('Blockly.BlockSvg');
|
||||
goog.requireType('Blockly.Field');
|
||||
goog.requireType('Blockly.RenderedConnection');
|
||||
|
||||
|
||||
/**
|
||||
* Class for an input with an optional field.
|
||||
* @param {number} type The type of the input.
|
||||
* @param {string} name Language-neutral identifier which may used to find this
|
||||
* input again.
|
||||
* @param {!Blockly.Block} block The block containing this input.
|
||||
* @param {Blockly.Connection} connection Optional connection for this input.
|
||||
* @param {!Block} block The block containing this input.
|
||||
* @param {Connection} connection Optional connection for this input.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Input = function(type, name, block, connection) {
|
||||
if (type != Blockly.inputTypes.DUMMY && !name) {
|
||||
const Input = function(type, name, block, connection) {
|
||||
if (type != inputTypes.DUMMY && !name) {
|
||||
throw Error('Value inputs and statement inputs must have non-empty name.');
|
||||
}
|
||||
/** @type {number} */
|
||||
@@ -42,13 +47,13 @@ Blockly.Input = function(type, name, block, connection) {
|
||||
/** @type {string} */
|
||||
this.name = name;
|
||||
/**
|
||||
* @type {!Blockly.Block}
|
||||
* @type {!Block}
|
||||
* @private
|
||||
*/
|
||||
this.sourceBlock_ = block;
|
||||
/** @type {Blockly.Connection} */
|
||||
/** @type {Connection} */
|
||||
this.connection = connection;
|
||||
/** @type {!Array<!Blockly.Field>} */
|
||||
/** @type {!Array<!Field>} */
|
||||
this.fieldRow = [];
|
||||
};
|
||||
|
||||
@@ -56,32 +61,32 @@ Blockly.Input = function(type, name, block, connection) {
|
||||
* Alignment of input's fields (left, right or centre).
|
||||
* @type {number}
|
||||
*/
|
||||
Blockly.Input.prototype.align = Blockly.constants.ALIGN.LEFT;
|
||||
Input.prototype.align = constants.ALIGN.LEFT;
|
||||
|
||||
/**
|
||||
* Is the input visible?
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
Blockly.Input.prototype.visible_ = true;
|
||||
Input.prototype.visible_ = true;
|
||||
|
||||
/**
|
||||
* Get the source block for this input.
|
||||
* @return {?Blockly.Block} The source block, or null if there is none.
|
||||
* @return {?Block} The source block, or null if there is none.
|
||||
*/
|
||||
Blockly.Input.prototype.getSourceBlock = function() {
|
||||
Input.prototype.getSourceBlock = function() {
|
||||
return this.sourceBlock_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a field (or label from string), and all prefix and suffix fields, to the
|
||||
* end of the input's field row.
|
||||
* @param {string|!Blockly.Field} field Something to add as a field.
|
||||
* @param {string|!Field} field Something to add as a field.
|
||||
* @param {string=} opt_name Language-neutral identifier which may used to find
|
||||
* this field again. Should be unique to the host block.
|
||||
* @return {!Blockly.Input} The input being append to (to allow chaining).
|
||||
* @return {!Input} The input being append to (to allow chaining).
|
||||
*/
|
||||
Blockly.Input.prototype.appendField = function(field, opt_name) {
|
||||
Input.prototype.appendField = function(field, opt_name) {
|
||||
this.insertFieldAt(this.fieldRow.length, field, opt_name);
|
||||
return this;
|
||||
};
|
||||
@@ -90,12 +95,12 @@ Blockly.Input.prototype.appendField = function(field, opt_name) {
|
||||
* Inserts a field (or label from string), and all prefix and suffix fields, at
|
||||
* the location of the input's field row.
|
||||
* @param {number} index The index at which to insert field.
|
||||
* @param {string|!Blockly.Field} field Something to add as a field.
|
||||
* @param {string|!Field} field Something to add as a field.
|
||||
* @param {string=} opt_name Language-neutral identifier which may used to find
|
||||
* this field again. Should be unique to the host block.
|
||||
* @return {number} The index following the last inserted field.
|
||||
*/
|
||||
Blockly.Input.prototype.insertFieldAt = function(index, field, opt_name) {
|
||||
Input.prototype.insertFieldAt = function(index, field, opt_name) {
|
||||
if (index < 0 || index > this.fieldRow.length) {
|
||||
throw Error('index ' + index + ' out of bounds.');
|
||||
}
|
||||
@@ -107,7 +112,7 @@ Blockly.Input.prototype.insertFieldAt = function(index, field, opt_name) {
|
||||
|
||||
// Generate a FieldLabel when given a plain text field.
|
||||
if (typeof field == 'string') {
|
||||
field = /** @type {!Blockly.Field} **/ (Blockly.fieldRegistry.fromJson({
|
||||
field = /** @type {!Field} **/ (fieldRegistry.fromJson({
|
||||
'type': 'field_label',
|
||||
'text': field,
|
||||
}));
|
||||
@@ -134,7 +139,7 @@ Blockly.Input.prototype.insertFieldAt = function(index, field, opt_name) {
|
||||
}
|
||||
|
||||
if (this.sourceBlock_.rendered) {
|
||||
this.sourceBlock_ = /** @type {!Blockly.BlockSvg} */ (this.sourceBlock_);
|
||||
this.sourceBlock_ = /** @type {!BlockSvg} */ (this.sourceBlock_);
|
||||
this.sourceBlock_.render();
|
||||
// Adding a field will cause the block to change shape.
|
||||
this.sourceBlock_.bumpNeighbours();
|
||||
@@ -150,13 +155,13 @@ Blockly.Input.prototype.insertFieldAt = function(index, field, opt_name) {
|
||||
* and opt_quiet is true.
|
||||
* @throws {Error} if the field is not present and opt_quiet is false.
|
||||
*/
|
||||
Blockly.Input.prototype.removeField = function(name, opt_quiet) {
|
||||
for (var i = 0, field; (field = this.fieldRow[i]); i++) {
|
||||
Input.prototype.removeField = function(name, opt_quiet) {
|
||||
for (let i = 0, field; (field = this.fieldRow[i]); i++) {
|
||||
if (field.name === name) {
|
||||
field.dispose();
|
||||
this.fieldRow.splice(i, 1);
|
||||
if (this.sourceBlock_.rendered) {
|
||||
this.sourceBlock_ = /** @type {!Blockly.BlockSvg} */ (this.sourceBlock_);
|
||||
this.sourceBlock_ = /** @type {!BlockSvg} */ (this.sourceBlock_);
|
||||
this.sourceBlock_.render();
|
||||
// Removing a field will cause the block to change shape.
|
||||
this.sourceBlock_.bumpNeighbours();
|
||||
@@ -174,7 +179,7 @@ Blockly.Input.prototype.removeField = function(name, opt_quiet) {
|
||||
* Gets whether this input is visible or not.
|
||||
* @return {boolean} True if visible.
|
||||
*/
|
||||
Blockly.Input.prototype.isVisible = function() {
|
||||
Input.prototype.isVisible = function() {
|
||||
return this.visible_;
|
||||
};
|
||||
|
||||
@@ -182,32 +187,32 @@ Blockly.Input.prototype.isVisible = function() {
|
||||
* Sets whether this input is visible or not.
|
||||
* Should only be used to collapse/uncollapse a block.
|
||||
* @param {boolean} visible True if visible.
|
||||
* @return {!Array<!Blockly.BlockSvg>} List of blocks to render.
|
||||
* @return {!Array<!BlockSvg>} List of blocks to render.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Input.prototype.setVisible = function(visible) {
|
||||
Input.prototype.setVisible = function(visible) {
|
||||
// Note: Currently there are only unit tests for block.setCollapsed()
|
||||
// because this function is package. If this function goes back to being a
|
||||
// public API tests (lots of tests) should be added.
|
||||
var renderList = [];
|
||||
let renderList = [];
|
||||
if (this.visible_ == visible) {
|
||||
return renderList;
|
||||
}
|
||||
this.visible_ = visible;
|
||||
|
||||
for (var y = 0, field; (field = this.fieldRow[y]); y++) {
|
||||
for (let y = 0, field; (field = this.fieldRow[y]); y++) {
|
||||
field.setVisible(visible);
|
||||
}
|
||||
if (this.connection) {
|
||||
this.connection =
|
||||
/** @type {!Blockly.RenderedConnection} */ (this.connection);
|
||||
/** @type {!RenderedConnection} */ (this.connection);
|
||||
// Has a connection.
|
||||
if (visible) {
|
||||
renderList = this.connection.startTrackingAll();
|
||||
} else {
|
||||
this.connection.stopTrackingAll();
|
||||
}
|
||||
var child = this.connection.targetBlock();
|
||||
const child = this.connection.targetBlock();
|
||||
if (child) {
|
||||
child.getSvgRoot().style.display = visible ? 'block' : 'none';
|
||||
}
|
||||
@@ -219,8 +224,8 @@ Blockly.Input.prototype.setVisible = function(visible) {
|
||||
* Mark all fields on this input as dirty.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Input.prototype.markDirty = function() {
|
||||
for (var y = 0, field; (field = this.fieldRow[y]); y++) {
|
||||
Input.prototype.markDirty = function() {
|
||||
for (let y = 0, field; (field = this.fieldRow[y]); y++) {
|
||||
field.markDirty();
|
||||
}
|
||||
};
|
||||
@@ -229,9 +234,9 @@ Blockly.Input.prototype.markDirty = function() {
|
||||
* Change a connection's compatibility.
|
||||
* @param {string|Array<string>|null} check Compatible value type or
|
||||
* list of value types. Null if all types are compatible.
|
||||
* @return {!Blockly.Input} The input being modified (to allow chaining).
|
||||
* @return {!Input} The input being modified (to allow chaining).
|
||||
*/
|
||||
Blockly.Input.prototype.setCheck = function(check) {
|
||||
Input.prototype.setCheck = function(check) {
|
||||
if (!this.connection) {
|
||||
throw Error('This input does not have a connection.');
|
||||
}
|
||||
@@ -241,14 +246,14 @@ Blockly.Input.prototype.setCheck = function(check) {
|
||||
|
||||
/**
|
||||
* Change the alignment of the connection's field(s).
|
||||
* @param {number} align One of the values of Blockly.constants.ALIGN.
|
||||
* @param {number} align One of the values of constants.ALIGN.
|
||||
* In RTL mode directions are reversed, and ALIGN.RIGHT aligns to the left.
|
||||
* @return {!Blockly.Input} The input being modified (to allow chaining).
|
||||
* @return {!Input} The input being modified (to allow chaining).
|
||||
*/
|
||||
Blockly.Input.prototype.setAlign = function(align) {
|
||||
Input.prototype.setAlign = function(align) {
|
||||
this.align = align;
|
||||
if (this.sourceBlock_.rendered) {
|
||||
this.sourceBlock_ = /** @type {!Blockly.BlockSvg} */ (this.sourceBlock_);
|
||||
this.sourceBlock_ = /** @type {!BlockSvg} */ (this.sourceBlock_);
|
||||
this.sourceBlock_.render();
|
||||
}
|
||||
return this;
|
||||
@@ -257,9 +262,9 @@ Blockly.Input.prototype.setAlign = function(align) {
|
||||
/**
|
||||
* Changes the connection's shadow block.
|
||||
* @param {?Element} shadow DOM representation of a block or null.
|
||||
* @return {!Blockly.Input} The input being modified (to allow chaining).
|
||||
* @return {!Input} The input being modified (to allow chaining).
|
||||
*/
|
||||
Blockly.Input.prototype.setShadowDom = function(shadow) {
|
||||
Input.prototype.setShadowDom = function(shadow) {
|
||||
if (!this.connection) {
|
||||
throw Error('This input does not have a connection.');
|
||||
}
|
||||
@@ -271,7 +276,7 @@ Blockly.Input.prototype.setShadowDom = function(shadow) {
|
||||
* Returns the XML representation of the connection's shadow block.
|
||||
* @return {?Element} Shadow DOM representation of a block or null.
|
||||
*/
|
||||
Blockly.Input.prototype.getShadowDom = function() {
|
||||
Input.prototype.getShadowDom = function() {
|
||||
if (!this.connection) {
|
||||
throw Error('This input does not have a connection.');
|
||||
}
|
||||
@@ -281,11 +286,11 @@ Blockly.Input.prototype.getShadowDom = function() {
|
||||
/**
|
||||
* Initialize the fields on this input.
|
||||
*/
|
||||
Blockly.Input.prototype.init = function() {
|
||||
Input.prototype.init = function() {
|
||||
if (!this.sourceBlock_.workspace.rendered) {
|
||||
return; // Headless blocks don't need fields initialized.
|
||||
}
|
||||
for (var i = 0; i < this.fieldRow.length; i++) {
|
||||
for (let i = 0; i < this.fieldRow.length; i++) {
|
||||
this.fieldRow[i].init();
|
||||
}
|
||||
};
|
||||
@@ -294,8 +299,8 @@ Blockly.Input.prototype.init = function() {
|
||||
* Sever all links to this input.
|
||||
* @suppress {checkTypes}
|
||||
*/
|
||||
Blockly.Input.prototype.dispose = function() {
|
||||
for (var i = 0, field; (field = this.fieldRow[i]); i++) {
|
||||
Input.prototype.dispose = function() {
|
||||
for (let i = 0, field; (field = this.fieldRow[i]); i++) {
|
||||
field.dispose();
|
||||
}
|
||||
if (this.connection) {
|
||||
@@ -303,3 +308,5 @@ Blockly.Input.prototype.dispose = function() {
|
||||
}
|
||||
this.sourceBlock_ = null;
|
||||
};
|
||||
|
||||
exports = Input;
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
goog.module('Blockly.ICollapsibleToolboxItem');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const ISelectableToolboxItem = goog.require('Blockly.ISelectableToolboxItem');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IToolboxItem = goog.requireType('Blockly.IToolboxItem');
|
||||
|
||||
|
||||
|
||||
@@ -11,92 +11,96 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IMetricsManager');
|
||||
goog.module('Blockly.IMetricsManager');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.requireType('Blockly.MetricsManager');
|
||||
goog.requireType('Blockly.utils.Metrics');
|
||||
goog.requireType('Blockly.utils.Size');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Metrics = goog.requireType('Blockly.utils.Metrics');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Size = goog.requireType('Blockly.utils.Size');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const {AbsoluteMetrics, ContainerRegion, ToolboxMetrics} = goog.requireType('Blockly.MetricsManager');
|
||||
|
||||
|
||||
/**
|
||||
* Interface for a metrics manager.
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IMetricsManager = function() {};
|
||||
const IMetricsManager = function() {};
|
||||
|
||||
/**
|
||||
* Returns whether the scroll area has fixed edges.
|
||||
* @return {boolean} Whether the scroll area has fixed edges.
|
||||
* @package
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.hasFixedEdges;
|
||||
IMetricsManager.prototype.hasFixedEdges;
|
||||
|
||||
/**
|
||||
* Returns the metrics for the scroll area of the workspace.
|
||||
* @param {boolean=} opt_getWorkspaceCoordinates True to get the scroll metrics
|
||||
* in workspace coordinates, false to get them in pixel coordinates.
|
||||
* @param {!Blockly.MetricsManager.ContainerRegion=} opt_viewMetrics The view
|
||||
* @param {!ContainerRegion=} opt_viewMetrics The view
|
||||
* metrics if they have been previously computed. Passing in null may cause
|
||||
* the view metrics to be computed again, if it is needed.
|
||||
* @param {!Blockly.MetricsManager.ContainerRegion=} opt_contentMetrics The
|
||||
* @param {!ContainerRegion=} opt_contentMetrics The
|
||||
* content metrics if they have been previously computed. Passing in null
|
||||
* may cause the content metrics to be computed again, if it is needed.
|
||||
* @return {!Blockly.MetricsManager.ContainerRegion} The metrics for the scroll
|
||||
* @return {!ContainerRegion} The metrics for the scroll
|
||||
* container
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.getScrollMetrics;
|
||||
IMetricsManager.prototype.getScrollMetrics;
|
||||
|
||||
/**
|
||||
* Gets the width and the height of the flyout on the workspace in pixel
|
||||
* coordinates. Returns 0 for the width and height if the workspace has a
|
||||
* category toolbox instead of a simple toolbox.
|
||||
* @param {boolean=} opt_own Whether to only return the workspace's own flyout.
|
||||
* @return {!Blockly.MetricsManager.ToolboxMetrics} The width and height of the
|
||||
* @return {!ToolboxMetrics} The width and height of the
|
||||
* flyout.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.getFlyoutMetrics;
|
||||
IMetricsManager.prototype.getFlyoutMetrics;
|
||||
|
||||
/**
|
||||
* Gets the width, height and position of the toolbox on the workspace in pixel
|
||||
* coordinates. Returns 0 for the width and height if the workspace has a simple
|
||||
* toolbox instead of a category toolbox. To get the width and height of a
|
||||
* simple toolbox @see {@link getFlyoutMetrics}.
|
||||
* @return {!Blockly.MetricsManager.ToolboxMetrics} The object with the width,
|
||||
* @return {!ToolboxMetrics} The object with the width,
|
||||
* height and position of the toolbox.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.getToolboxMetrics;
|
||||
IMetricsManager.prototype.getToolboxMetrics;
|
||||
|
||||
/**
|
||||
* Gets the width and height of the workspace's parent SVG element in pixel
|
||||
* coordinates. This area includes the toolbox and the visible workspace area.
|
||||
* @return {!Blockly.utils.Size} The width and height of the workspace's parent
|
||||
* @return {!Size} The width and height of the workspace's parent
|
||||
* SVG element.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.getSvgMetrics;
|
||||
IMetricsManager.prototype.getSvgMetrics;
|
||||
|
||||
/**
|
||||
* Gets the absolute left and absolute top in pixel coordinates.
|
||||
* This is where the visible workspace starts in relation to the SVG container.
|
||||
* @return {!Blockly.MetricsManager.AbsoluteMetrics} The absolute metrics for
|
||||
* @return {!AbsoluteMetrics} The absolute metrics for
|
||||
* the workspace.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.getAbsoluteMetrics;
|
||||
IMetricsManager.prototype.getAbsoluteMetrics;
|
||||
|
||||
/**
|
||||
* Gets the metrics for the visible workspace in either pixel or workspace
|
||||
* coordinates. The visible workspace does not include the toolbox or flyout.
|
||||
* @param {boolean=} opt_getWorkspaceCoordinates True to get the view metrics in
|
||||
* workspace coordinates, false to get them in pixel coordinates.
|
||||
* @return {!Blockly.MetricsManager.ContainerRegion} The width, height, top and
|
||||
* @return {!ContainerRegion} The width, height, top and
|
||||
* left of the viewport in either workspace coordinates or pixel
|
||||
* coordinates.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.getViewMetrics;
|
||||
IMetricsManager.prototype.getViewMetrics;
|
||||
|
||||
/**
|
||||
* Gets content metrics in either pixel or workspace coordinates.
|
||||
@@ -104,11 +108,11 @@ Blockly.IMetricsManager.prototype.getViewMetrics;
|
||||
* workspace (workspace comments and blocks).
|
||||
* @param {boolean=} opt_getWorkspaceCoordinates True to get the content metrics
|
||||
* in workspace coordinates, false to get them in pixel coordinates.
|
||||
* @return {!Blockly.MetricsManager.ContainerRegion} The
|
||||
* @return {!ContainerRegion} The
|
||||
* metrics for the content container.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.getContentMetrics;
|
||||
IMetricsManager.prototype.getContentMetrics;
|
||||
|
||||
/**
|
||||
* Returns an object with all the metrics required to size scrollbars for a
|
||||
@@ -138,8 +142,10 @@ Blockly.IMetricsManager.prototype.getContentMetrics;
|
||||
* .flyoutHeight: Height of the flyout if it is always open. Otherwise zero.
|
||||
* .toolboxPosition: Top, bottom, left or right. Use TOOLBOX_AT constants to
|
||||
* compare.
|
||||
* @return {!Blockly.utils.Metrics} Contains size and position metrics of a top
|
||||
* @return {!Metrics} Contains size and position metrics of a top
|
||||
* level workspace.
|
||||
* @public
|
||||
*/
|
||||
Blockly.IMetricsManager.prototype.getMetrics;
|
||||
IMetricsManager.prototype.getMetrics;
|
||||
|
||||
exports = IMetricsManager;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
goog.module('Blockly.IRegistrableField');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Field = goog.requireType('Blockly.Field');
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
goog.module('Blockly.ISelectableToolboxItem');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const IToolboxItem = goog.require('Blockly.IToolboxItem');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const {FlyoutItemInfoArray} = goog.requireType('Blockly.utils.toolbox');
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ goog.module.declareLegacyNamespace();
|
||||
|
||||
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');
|
||||
|
||||
|
||||
195
core/menu.js
195
core/menu.js
@@ -10,29 +10,31 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Menu');
|
||||
goog.module('Blockly.Menu');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
goog.require('Blockly.browserEvents');
|
||||
goog.require('Blockly.utils.aria');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.utils.dom');
|
||||
goog.require('Blockly.utils.KeyCodes');
|
||||
goog.require('Blockly.utils.style');
|
||||
|
||||
goog.requireType('Blockly.MenuItem');
|
||||
goog.requireType('Blockly.utils.Size');
|
||||
const Coordinate = goog.require('Blockly.utils.Coordinate');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const MenuItem = goog.requireType('Blockly.MenuItem');
|
||||
const KeyCodes = goog.require('Blockly.utils.KeyCodes');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Size = goog.requireType('Blockly.utils.Size');
|
||||
const aria = goog.require('Blockly.utils.aria');
|
||||
const browserEvents = goog.require('Blockly.browserEvents');
|
||||
const dom = goog.require('Blockly.utils.dom');
|
||||
const style = goog.require('Blockly.utils.style');
|
||||
|
||||
|
||||
/**
|
||||
* A basic menu class.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Menu = function() {
|
||||
const Menu = function() {
|
||||
/**
|
||||
* Array of menu items.
|
||||
* (Nulls are never in the array, but typing the array as nullable prevents
|
||||
* the compiler from objecting to .indexOf(null))
|
||||
* @type {!Array<Blockly.MenuItem>}
|
||||
* @type {!Array<MenuItem>}
|
||||
* @private
|
||||
*/
|
||||
this.menuItems_ = [];
|
||||
@@ -41,7 +43,7 @@ Blockly.Menu = function() {
|
||||
* Coordinates of the mousedown event that caused this menu to open. Used to
|
||||
* prevent the consequent mouseup event due to a simple click from activating
|
||||
* a menu item immediately.
|
||||
* @type {?Blockly.utils.Coordinate}
|
||||
* @type {?Coordinate}
|
||||
* @package
|
||||
*/
|
||||
this.openingCoords = null;
|
||||
@@ -49,42 +51,42 @@ Blockly.Menu = function() {
|
||||
/**
|
||||
* This is the element that we will listen to the real focus events on.
|
||||
* A value of null means no menu item is highlighted.
|
||||
* @type {?Blockly.MenuItem}
|
||||
* @type {?MenuItem}
|
||||
* @private
|
||||
*/
|
||||
this.highlightedItem_ = null;
|
||||
|
||||
/**
|
||||
* Mouse over event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.mouseOverHandler_ = null;
|
||||
|
||||
/**
|
||||
* Click event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.clickHandler_ = null;
|
||||
|
||||
/**
|
||||
* Mouse enter event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.mouseEnterHandler_ = null;
|
||||
|
||||
/**
|
||||
* Mouse leave event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.mouseLeaveHandler_ = null;
|
||||
|
||||
/**
|
||||
* Key down event data.
|
||||
* @type {?Blockly.browserEvents.Data}
|
||||
* @type {?browserEvents.Data}
|
||||
* @private
|
||||
*/
|
||||
this.onKeyDownHandler_ = null;
|
||||
@@ -98,7 +100,7 @@ Blockly.Menu = function() {
|
||||
|
||||
/**
|
||||
* ARIA name for this menu.
|
||||
* @type {?Blockly.utils.aria.Role}
|
||||
* @type {?aria.Role}
|
||||
* @private
|
||||
*/
|
||||
this.roleName_ = null;
|
||||
@@ -107,9 +109,9 @@ Blockly.Menu = function() {
|
||||
|
||||
/**
|
||||
* Add a new menu item to the bottom of this menu.
|
||||
* @param {!Blockly.MenuItem} menuItem Menu item to append.
|
||||
* @param {!MenuItem} menuItem Menu item to append.
|
||||
*/
|
||||
Blockly.Menu.prototype.addChild = function(menuItem) {
|
||||
Menu.prototype.addChild = function(menuItem) {
|
||||
this.menuItems_.push(menuItem);
|
||||
};
|
||||
|
||||
@@ -117,32 +119,33 @@ Blockly.Menu.prototype.addChild = function(menuItem) {
|
||||
* Creates the menu DOM.
|
||||
* @param {!Element} container Element upon which to append this menu.
|
||||
*/
|
||||
Blockly.Menu.prototype.render = function(container) {
|
||||
var element = /** @type {!HTMLDivElement} */ (document.createElement('div'));
|
||||
Menu.prototype.render = function(container) {
|
||||
const element =
|
||||
/** @type {!HTMLDivElement} */ (document.createElement('div'));
|
||||
// goog-menu is deprecated, use blocklyMenu. May 2020.
|
||||
element.className = 'blocklyMenu goog-menu blocklyNonSelectable';
|
||||
element.tabIndex = 0;
|
||||
if (this.roleName_) {
|
||||
Blockly.utils.aria.setRole(element, this.roleName_);
|
||||
aria.setRole(element, this.roleName_);
|
||||
}
|
||||
this.element_ = element;
|
||||
|
||||
// Add menu items.
|
||||
for (var i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
|
||||
for (let i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
|
||||
element.appendChild(menuItem.createDom());
|
||||
}
|
||||
|
||||
// Add event handlers.
|
||||
this.mouseOverHandler_ = Blockly.browserEvents.conditionalBind(
|
||||
element, 'mouseover', this, this.handleMouseOver_, true);
|
||||
this.clickHandler_ = Blockly.browserEvents.conditionalBind(
|
||||
element, 'click', this, this.handleClick_, true);
|
||||
this.mouseEnterHandler_ = Blockly.browserEvents.conditionalBind(
|
||||
this.mouseOverHandler_ =
|
||||
browserEvents.conditionalBind(element, 'mouseover', this, this.handleMouseOver_, true);
|
||||
this.clickHandler_ =
|
||||
browserEvents.conditionalBind(element, 'click', this, this.handleClick_, true);
|
||||
this.mouseEnterHandler_ = browserEvents.conditionalBind(
|
||||
element, 'mouseenter', this, this.handleMouseEnter_, true);
|
||||
this.mouseLeaveHandler_ = Blockly.browserEvents.conditionalBind(
|
||||
this.mouseLeaveHandler_ = browserEvents.conditionalBind(
|
||||
element, 'mouseleave', this, this.handleMouseLeave_, true);
|
||||
this.onKeyDownHandler_ = Blockly.browserEvents.conditionalBind(
|
||||
element, 'keydown', this, this.handleKeyEvent_);
|
||||
this.onKeyDownHandler_ =
|
||||
browserEvents.conditionalBind(element, 'keydown', this, this.handleKeyEvent_);
|
||||
|
||||
container.appendChild(element);
|
||||
};
|
||||
@@ -152,7 +155,7 @@ Blockly.Menu.prototype.render = function(container) {
|
||||
* @return {?Element} The DOM element.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Menu.prototype.getElement = function() {
|
||||
Menu.prototype.getElement = function() {
|
||||
return this.element_;
|
||||
};
|
||||
|
||||
@@ -160,11 +163,11 @@ Blockly.Menu.prototype.getElement = function() {
|
||||
* Focus the menu element.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Menu.prototype.focus = function() {
|
||||
var el = this.getElement();
|
||||
Menu.prototype.focus = function() {
|
||||
const el = this.getElement();
|
||||
if (el) {
|
||||
el.focus({preventScroll:true});
|
||||
Blockly.utils.dom.addClass(el, 'blocklyFocused');
|
||||
el.focus({preventScroll: true});
|
||||
dom.addClass(el, 'blocklyFocused');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -172,51 +175,51 @@ Blockly.Menu.prototype.focus = function() {
|
||||
* Blur the menu element.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.blur_ = function() {
|
||||
var el = this.getElement();
|
||||
Menu.prototype.blur_ = function() {
|
||||
const el = this.getElement();
|
||||
if (el) {
|
||||
el.blur();
|
||||
Blockly.utils.dom.removeClass(el, 'blocklyFocused');
|
||||
dom.removeClass(el, 'blocklyFocused');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the menu accessibility role.
|
||||
* @param {!Blockly.utils.aria.Role} roleName role name.
|
||||
* @param {!aria.Role} roleName role name.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Menu.prototype.setRole = function(roleName) {
|
||||
Menu.prototype.setRole = function(roleName) {
|
||||
this.roleName_ = roleName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispose of this menu.
|
||||
*/
|
||||
Blockly.Menu.prototype.dispose = function() {
|
||||
Menu.prototype.dispose = function() {
|
||||
// Remove event handlers.
|
||||
if (this.mouseOverHandler_) {
|
||||
Blockly.browserEvents.unbind(this.mouseOverHandler_);
|
||||
browserEvents.unbind(this.mouseOverHandler_);
|
||||
this.mouseOverHandler_ = null;
|
||||
}
|
||||
if (this.clickHandler_) {
|
||||
Blockly.browserEvents.unbind(this.clickHandler_);
|
||||
browserEvents.unbind(this.clickHandler_);
|
||||
this.clickHandler_ = null;
|
||||
}
|
||||
if (this.mouseEnterHandler_) {
|
||||
Blockly.browserEvents.unbind(this.mouseEnterHandler_);
|
||||
browserEvents.unbind(this.mouseEnterHandler_);
|
||||
this.mouseEnterHandler_ = null;
|
||||
}
|
||||
if (this.mouseLeaveHandler_) {
|
||||
Blockly.browserEvents.unbind(this.mouseLeaveHandler_);
|
||||
browserEvents.unbind(this.mouseLeaveHandler_);
|
||||
this.mouseLeaveHandler_ = null;
|
||||
}
|
||||
if (this.onKeyDownHandler_) {
|
||||
Blockly.browserEvents.unbind(this.onKeyDownHandler_);
|
||||
browserEvents.unbind(this.onKeyDownHandler_);
|
||||
this.onKeyDownHandler_ = null;
|
||||
}
|
||||
|
||||
// Remove menu items.
|
||||
for (var i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
|
||||
for (let i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
|
||||
menuItem.dispose();
|
||||
}
|
||||
this.element_ = null;
|
||||
@@ -228,19 +231,19 @@ Blockly.Menu.prototype.dispose = function() {
|
||||
* Returns the child menu item that owns the given DOM element,
|
||||
* or null if no such menu item is found.
|
||||
* @param {Element} elem DOM element whose owner is to be returned.
|
||||
* @return {?Blockly.MenuItem} Menu item for which the DOM element belongs to.
|
||||
* @return {?MenuItem} Menu item for which the DOM element belongs to.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.getMenuItem_ = function(elem) {
|
||||
var menuElem = this.getElement();
|
||||
Menu.prototype.getMenuItem_ = function(elem) {
|
||||
const menuElem = this.getElement();
|
||||
// Node might be the menu border (resulting in no associated menu item), or
|
||||
// a menu item's div, or some element within the menu item.
|
||||
// Walk up parents until one meets either the menu's root element, or
|
||||
// a menu item's div.
|
||||
while (elem && elem != menuElem) {
|
||||
if (Blockly.utils.dom.hasClass(elem, 'blocklyMenuItem')) {
|
||||
if (dom.hasClass(elem, 'blocklyMenuItem')) {
|
||||
// Having found a menu item's div, locate that menu item in this menu.
|
||||
for (var i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
|
||||
for (let i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
|
||||
if (menuItem.getElement() == elem) {
|
||||
return menuItem;
|
||||
}
|
||||
@@ -255,11 +258,11 @@ Blockly.Menu.prototype.getMenuItem_ = function(elem) {
|
||||
|
||||
/**
|
||||
* Highlights the given menu item, or clears highlighting if null.
|
||||
* @param {?Blockly.MenuItem} item Item to highlight, or null.
|
||||
* @param {?MenuItem} item Item to highlight, or null.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Menu.prototype.setHighlighted = function(item) {
|
||||
var currentHighlighted = this.highlightedItem_;
|
||||
Menu.prototype.setHighlighted = function(item) {
|
||||
const currentHighlighted = this.highlightedItem_;
|
||||
if (currentHighlighted) {
|
||||
currentHighlighted.setHighlighted(false);
|
||||
this.highlightedItem_ = null;
|
||||
@@ -269,12 +272,11 @@ Blockly.Menu.prototype.setHighlighted = function(item) {
|
||||
this.highlightedItem_ = item;
|
||||
// Bring the highlighted item into view. This has no effect if the menu is
|
||||
// not scrollable.
|
||||
var el = /** @type {!Element} */ (this.getElement());
|
||||
Blockly.utils.style.scrollIntoContainerView(
|
||||
const el = /** @type {!Element} */ (this.getElement());
|
||||
style.scrollIntoContainerView(
|
||||
/** @type {!Element} */ (item.getElement()), el);
|
||||
|
||||
Blockly.utils.aria.setState(el, Blockly.utils.aria.State.ACTIVEDESCENDANT,
|
||||
item.getId());
|
||||
aria.setState(el, aria.State.ACTIVEDESCENDANT, item.getId());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -283,8 +285,8 @@ Blockly.Menu.prototype.setHighlighted = function(item) {
|
||||
* highlighted).
|
||||
* @package
|
||||
*/
|
||||
Blockly.Menu.prototype.highlightNext = function() {
|
||||
var index = this.menuItems_.indexOf(this.highlightedItem_);
|
||||
Menu.prototype.highlightNext = function() {
|
||||
const index = this.menuItems_.indexOf(this.highlightedItem_);
|
||||
this.highlightHelper_(index, 1);
|
||||
};
|
||||
|
||||
@@ -293,8 +295,8 @@ Blockly.Menu.prototype.highlightNext = function() {
|
||||
* currently highlighted).
|
||||
* @package
|
||||
*/
|
||||
Blockly.Menu.prototype.highlightPrevious = function() {
|
||||
var index = this.menuItems_.indexOf(this.highlightedItem_);
|
||||
Menu.prototype.highlightPrevious = function() {
|
||||
const index = this.menuItems_.indexOf(this.highlightedItem_);
|
||||
this.highlightHelper_(index < 0 ? this.menuItems_.length : index, -1);
|
||||
};
|
||||
|
||||
@@ -302,7 +304,7 @@ Blockly.Menu.prototype.highlightPrevious = function() {
|
||||
* Highlights the first highlightable item.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.highlightFirst_ = function() {
|
||||
Menu.prototype.highlightFirst_ = function() {
|
||||
this.highlightHelper_(-1, 1);
|
||||
};
|
||||
|
||||
@@ -310,7 +312,7 @@ Blockly.Menu.prototype.highlightFirst_ = function() {
|
||||
* Highlights the last highlightable item.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.highlightLast_ = function() {
|
||||
Menu.prototype.highlightLast_ = function() {
|
||||
this.highlightHelper_(this.menuItems_.length, -1);
|
||||
};
|
||||
|
||||
@@ -321,9 +323,9 @@ Blockly.Menu.prototype.highlightLast_ = function() {
|
||||
* @param {number} delta Step direction: 1 to go down, -1 to go up.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.highlightHelper_ = function(startIndex, delta) {
|
||||
var index = startIndex + delta;
|
||||
var menuItem;
|
||||
Menu.prototype.highlightHelper_ = function(startIndex, delta) {
|
||||
let index = startIndex + delta;
|
||||
let menuItem;
|
||||
while ((menuItem = this.menuItems_[index])) {
|
||||
if (menuItem.isEnabled()) {
|
||||
this.setHighlighted(menuItem);
|
||||
@@ -340,8 +342,8 @@ Blockly.Menu.prototype.highlightHelper_ = function(startIndex, delta) {
|
||||
* @param {!Event} e Mouse event to handle.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.handleMouseOver_ = function(e) {
|
||||
var menuItem = this.getMenuItem_(/** @type {Element} */ (e.target));
|
||||
Menu.prototype.handleMouseOver_ = function(e) {
|
||||
const menuItem = this.getMenuItem_(/** @type {Element} */ (e.target));
|
||||
|
||||
if (menuItem) {
|
||||
if (menuItem.isEnabled()) {
|
||||
@@ -359,13 +361,13 @@ Blockly.Menu.prototype.handleMouseOver_ = function(e) {
|
||||
* @param {!Event} e Click event to handle.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.handleClick_ = function(e) {
|
||||
var oldCoords = this.openingCoords;
|
||||
Menu.prototype.handleClick_ = function(e) {
|
||||
const oldCoords = this.openingCoords;
|
||||
// Clear out the saved opening coords immediately so they're not used twice.
|
||||
this.openingCoords = null;
|
||||
if (oldCoords && typeof e.clientX == 'number') {
|
||||
var newCoords = new Blockly.utils.Coordinate(e.clientX, e.clientY);
|
||||
if (Blockly.utils.Coordinate.distance(oldCoords, newCoords) < 1) {
|
||||
const newCoords = new Coordinate(e.clientX, e.clientY);
|
||||
if (Coordinate.distance(oldCoords, newCoords) < 1) {
|
||||
// This menu was opened by a mousedown and we're handling the consequent
|
||||
// click event. The coords haven't changed, meaning this was the same
|
||||
// opening event. Don't do the usual behavior because the menu just popped
|
||||
@@ -374,7 +376,7 @@ Blockly.Menu.prototype.handleClick_ = function(e) {
|
||||
}
|
||||
}
|
||||
|
||||
var menuItem = this.getMenuItem_(/** @type {Element} */ (e.target));
|
||||
const menuItem = this.getMenuItem_(/** @type {Element} */ (e.target));
|
||||
if (menuItem) {
|
||||
menuItem.performAction();
|
||||
}
|
||||
@@ -385,7 +387,7 @@ Blockly.Menu.prototype.handleClick_ = function(e) {
|
||||
* @param {!Event} _e Mouse event to handle.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.handleMouseEnter_ = function(_e) {
|
||||
Menu.prototype.handleMouseEnter_ = function(_e) {
|
||||
this.focus();
|
||||
};
|
||||
|
||||
@@ -394,7 +396,7 @@ Blockly.Menu.prototype.handleMouseEnter_ = function(_e) {
|
||||
* @param {!Event} _e Mouse event to handle.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.handleMouseLeave_ = function(_e) {
|
||||
Menu.prototype.handleMouseLeave_ = function(_e) {
|
||||
if (this.getElement()) {
|
||||
this.blur_();
|
||||
this.setHighlighted(null);
|
||||
@@ -409,7 +411,7 @@ Blockly.Menu.prototype.handleMouseLeave_ = function(_e) {
|
||||
* @param {!Event} e Key event to handle.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Menu.prototype.handleKeyEvent_ = function(e) {
|
||||
Menu.prototype.handleKeyEvent_ = function(e) {
|
||||
if (!this.menuItems_.length) {
|
||||
// Empty menu.
|
||||
return;
|
||||
@@ -419,30 +421,30 @@ Blockly.Menu.prototype.handleKeyEvent_ = function(e) {
|
||||
return;
|
||||
}
|
||||
|
||||
var highlighted = this.highlightedItem_;
|
||||
const highlighted = this.highlightedItem_;
|
||||
switch (e.keyCode) {
|
||||
case Blockly.utils.KeyCodes.ENTER:
|
||||
case Blockly.utils.KeyCodes.SPACE:
|
||||
case KeyCodes.ENTER:
|
||||
case KeyCodes.SPACE:
|
||||
if (highlighted) {
|
||||
highlighted.performAction();
|
||||
}
|
||||
break;
|
||||
|
||||
case Blockly.utils.KeyCodes.UP:
|
||||
case KeyCodes.UP:
|
||||
this.highlightPrevious();
|
||||
break;
|
||||
|
||||
case Blockly.utils.KeyCodes.DOWN:
|
||||
case KeyCodes.DOWN:
|
||||
this.highlightNext();
|
||||
break;
|
||||
|
||||
case Blockly.utils.KeyCodes.PAGE_UP:
|
||||
case Blockly.utils.KeyCodes.HOME:
|
||||
case KeyCodes.PAGE_UP:
|
||||
case KeyCodes.HOME:
|
||||
this.highlightFirst_();
|
||||
break;
|
||||
|
||||
case Blockly.utils.KeyCodes.PAGE_DOWN:
|
||||
case Blockly.utils.KeyCodes.END:
|
||||
case KeyCodes.PAGE_DOWN:
|
||||
case KeyCodes.END:
|
||||
this.highlightLast_();
|
||||
break;
|
||||
|
||||
@@ -457,13 +459,16 @@ Blockly.Menu.prototype.handleKeyEvent_ = function(e) {
|
||||
|
||||
/**
|
||||
* Get the size of a rendered menu.
|
||||
* @return {!Blockly.utils.Size} Object with width and height properties.
|
||||
* @return {!Size} Object with width and height properties.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Menu.prototype.getSize = function() {
|
||||
var menuDom = this.getElement();
|
||||
var menuSize = Blockly.utils.style.getSize(/** @type {!Element} */ (menuDom));
|
||||
Menu.prototype.getSize = function() {
|
||||
const menuDom = this.getElement();
|
||||
const menuSize = style.getSize(/** @type {!Element} */
|
||||
(menuDom));
|
||||
// Recalculate height for the total content, not only box height.
|
||||
menuSize.height = menuDom.scrollHeight;
|
||||
return menuSize;
|
||||
};
|
||||
|
||||
exports = Menu;
|
||||
|
||||
@@ -13,25 +13,33 @@
|
||||
goog.module('Blockly.blockRendering.RenderInfo');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const BlockSvg = goog.requireType('Blockly.BlockSvg');
|
||||
const BottomRow = goog.require('Blockly.blockRendering.BottomRow');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const ConstantProvider = goog.requireType('Blockly.blockRendering.ConstantProvider');
|
||||
const ExternalValueInput = goog.require('Blockly.blockRendering.ExternalValueInput');
|
||||
const Field = goog.require('Blockly.blockRendering.Field');
|
||||
const Hat = goog.require('Blockly.blockRendering.Hat');
|
||||
const Icon = goog.require('Blockly.blockRendering.Icon');
|
||||
const InlineInput = goog.require('Blockly.blockRendering.InlineInput');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Input = goog.requireType('Blockly.Input');
|
||||
const InputRow = goog.require('Blockly.blockRendering.InputRow');
|
||||
const InRowSpacer = goog.require('Blockly.blockRendering.InRowSpacer');
|
||||
const JaggedEdge = goog.require('Blockly.blockRendering.JaggedEdge');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Measurable = goog.require('Blockly.blockRendering.Measurable');
|
||||
const NextConnection = goog.require('Blockly.blockRendering.NextConnection');
|
||||
const OutputConnection = goog.require('Blockly.blockRendering.OutputConnection');
|
||||
const PreviousConnection = goog.require('Blockly.blockRendering.PreviousConnection');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const RenderedConnection = goog.requireType('Blockly.RenderedConnection');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Renderer = goog.requireType('Blockly.blockRendering.Renderer');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const RoundCorner = goog.require('Blockly.blockRendering.RoundCorner');
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
const Row = goog.require('Blockly.blockRendering.Row');
|
||||
const SpacerRow = goog.require('Blockly.blockRendering.SpacerRow');
|
||||
const SquareCorner = goog.require('Blockly.blockRendering.SquareCorner');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
#######################################
|
||||
# Logging functions
|
||||
# Logging functions.
|
||||
#######################################
|
||||
COLOR_NONE="\033[0m"
|
||||
GREEN="\033[0;32m"
|
||||
@@ -20,17 +20,27 @@ warn() {
|
||||
err() {
|
||||
echo -e "${RED}[ERROR]:${COLOR_NONE} $*" >&2
|
||||
}
|
||||
reenter_instructions() {
|
||||
echo -e "${ORANGE}$*${COLOR_NONE}" >&2
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Checks whether the provided filepath exists.
|
||||
# Arguments:
|
||||
# The filepath to check for existence.
|
||||
# Optional: Whether to log an error.
|
||||
#######################################
|
||||
verify-filepath() {
|
||||
if [[ ! -f "$1" ]]; then
|
||||
err "File $1 does not exist"
|
||||
local filepath="$1"
|
||||
local no_log="$2"
|
||||
if [[ ! -f "${filepath}" ]]; then
|
||||
if [[ -z "${no_log}" || "${no_log}" == 'true' ]]; then
|
||||
err "File ${filepath} does not exist"
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Creates a commit with a message based on the specified step and file.
|
||||
# Arguments:
|
||||
@@ -40,11 +50,11 @@ verify-filepath() {
|
||||
commit-step() {
|
||||
local step="$1"
|
||||
local filepath="$2"
|
||||
if [ -z "${step}" ]; then
|
||||
if [[ -z "${step}" ]]; then
|
||||
err "Missing argument (1-4)"
|
||||
return 1
|
||||
fi
|
||||
if [ -z "${filepath}" ]; then
|
||||
if [[ -z "${filepath}" ]]; then
|
||||
err "Missing argument filepath"
|
||||
return 1
|
||||
fi
|
||||
@@ -78,6 +88,7 @@ commit-step() {
|
||||
git commit -m "${message}"
|
||||
success "created commit with message: \"${message}\""
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Runs step 2 of the automated conversion.
|
||||
# Arguments:
|
||||
@@ -85,25 +96,10 @@ commit-step() {
|
||||
#######################################
|
||||
step2 () {
|
||||
local filepath="$1"
|
||||
if [ -z "${filepath}" ]; then
|
||||
err "Missing argument filepath"
|
||||
return 1
|
||||
fi
|
||||
|
||||
inf "Verifying single goog.provide declarations..."
|
||||
local provide_count=$(grep -o 'goog.provide' ${filepath} | wc -l)
|
||||
if [[ "${provide_count}" -gt "1" ]]; then
|
||||
err "Cannot convert file with multiple provides. Please split the file first."
|
||||
return 1
|
||||
elif [[ "${provide_count}" -eq "0" ]]; then
|
||||
err "Cannot convert file without a provide."
|
||||
return 1
|
||||
fi
|
||||
|
||||
inf "Updating goog.provide declaration..."
|
||||
perl -pi -e 's/^goog\.provide(\([^\)]+\)\;)/goog\.module\1\ngoog.module.declareLegacyNamespace\(\)\;/g' "${filepath}"
|
||||
|
||||
|
||||
inf "Extracting module name..."
|
||||
local module_name=$(perl -nle'print $& while m{(?<=^goog\.module\('\'')([^'\'')]+)}g' "${filepath}")
|
||||
if [[ -z "${module_name}" ]]; then
|
||||
@@ -117,11 +113,9 @@ step2 () {
|
||||
inf "Found class \"${class_name}\" in file."
|
||||
inf "Updating class declaration..."
|
||||
perl -pi -e 's/^('"${module_name}"') =/const '"${class_name}"' =/g' "${filepath}"
|
||||
inf 'Updating class properties...'
|
||||
perl -pi -e 's/^'"${module_name}"'((\.\w+)+) =/'"${class_name}"'\1 =/g' "${filepath}"
|
||||
|
||||
inf "Updating local references to class..."
|
||||
perl -pi -e 's/'"${module_name}"'([^'\''])/'"${class_name}"'\1/g' "${filepath}"
|
||||
perl -pi -e 's/'"${module_name}"'(?!['\''\w])/'"${class_name}"'/g' "${filepath}"
|
||||
|
||||
inf "Appending class export to end of file..."
|
||||
echo "" >> "${filepath}"
|
||||
@@ -140,20 +134,15 @@ step2 () {
|
||||
perl -pi -e 's/'"${module_name}"'\.([^ ]+)/\1/g' "${filepath}"
|
||||
|
||||
npm run build:deps
|
||||
success "Completed automation for step 3. Please manually review and add exports for non-private top-level functions."
|
||||
success "Completed automation for step 2. Please manually review and add exports for non-private top-level functions."
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Runs step 3 of the automated conversion.
|
||||
# Arguments:
|
||||
# The filepath of the file being converted.
|
||||
#######################################
|
||||
step3() {
|
||||
local filepath="$1"
|
||||
if [ -z "${filepath}" ]; then
|
||||
err "Missing argument filepath"
|
||||
return 1
|
||||
fi
|
||||
|
||||
inf "Extracting module name..."
|
||||
local module_name=$(perl -nle'print $& while m{(?<=^goog\.module\('\'')([^'\'')]+)}g' "${filepath}")
|
||||
if [[ -z "${module_name}" ]]; then
|
||||
@@ -162,10 +151,10 @@ step3() {
|
||||
fi
|
||||
inf "Extracted module name \"${module_name}\""
|
||||
|
||||
local requires=$(perl -nle'print $& while m{^goog.require(|Type)\('\''(.*)'\''\)}g' "${filepath}" | perl -pe 's/goog.require(|Type)\('\''(.*)'\''\)/\2/g')
|
||||
local requires=$(perl -nle'print $& while m{(?:(?<=^goog.require\('\'')|(?<=^goog.requireType\('\''))[^'\'']+}g' "${filepath}")
|
||||
|
||||
# Process each require
|
||||
echo "${requires}" | while read -r require ; do
|
||||
echo "${requires}" | while read -r require; do
|
||||
inf "Processing require \"${require}\""
|
||||
local usages=$(perl -nle'print $& while m{'"${require}"'(?!'\'')}g' "${filepath}" | wc -l)
|
||||
|
||||
@@ -174,67 +163,62 @@ step3() {
|
||||
continue
|
||||
fi
|
||||
|
||||
local require_name=$(echo "${require}" | perl -pe 's/(\w+\.)+(\w+)/\2/g')
|
||||
inf "Updating require declaration for ${require}..."
|
||||
perl -pi -e 's/^(goog\.(require|requireType)\('\'"${require}"\''\);)/const '"${require_name}"' = \1/' "${filepath}"
|
||||
|
||||
# Parse property access of module
|
||||
local direct_access_count=$(perl -nle'print $& while m{'"${require}"'[^\.'\'']}g' "${filepath}" | wc -l)
|
||||
local properties_accessed=$(perl -nle'print $& while m{(?<='"${require}"'\.)(?!prototype)\w+}g' "${filepath}" | tr ' ' '\n' | sort -u)
|
||||
# Detect requires overlap
|
||||
# (ex: Blockly.utils require and Blockly.utils.dom also in requires)
|
||||
local requires_overlap=$(echo "${requires}" | perl -nle'print $& while m{(?<='"${require}"'\.)\w+}g')
|
||||
if [[ ! -z "${requires_overlap}" ]]; then
|
||||
while read -r requires_overlap_prop ; do
|
||||
if [[ -n "${requires_overlap}" ]]; then
|
||||
while read -r requires_overlap_prop; do
|
||||
properties_accessed=$(echo "${properties_accessed}" | perl -pe 's/'"${requires_overlap_prop}"'//g')
|
||||
done <<<"${requires_overlap}"
|
||||
fi
|
||||
# Detect module name overlap
|
||||
# (ex: Blockly require and Blockly.ContextMenuItems module being converted)
|
||||
local module_overlap=$(echo "${module_name}" | perl -nle'print $& while m{(?<='"${require}"'\.)\w+}g')
|
||||
if [[ ! -z "${module_overlap}" ]]; then
|
||||
if [[ -n "${module_overlap}" ]]; then
|
||||
properties_accessed=$(echo "${properties_accessed}" | perl -pe 's/'"${module_overlap}"'//g')
|
||||
fi
|
||||
properties_accessed=$(echo "${properties_accessed}" | perl -pe 's/\s+/ /g' | xargs)
|
||||
|
||||
if [[ "${direct_access_count}" -eq "0" && ! -z "${properties_accessed}" ]]; then
|
||||
local deconstructed_comma=$(echo "${properties_accessed}" | perl -pe 's/\s+/, /g' | perl -pe 's/, $//')
|
||||
inf "Deconstructing ${require} into \"{${deconstructed_comma}}\""
|
||||
if [[ -n "${properties_accessed}" ]]; then
|
||||
local comma_properties=$(echo "${properties_accessed}" | perl -pe 's/\s+/, /g' | perl -pe 's/, $//')
|
||||
inf "Detected references of ${require}: ${comma_properties}"
|
||||
|
||||
inf "Updating require declaration for ${require}..."
|
||||
perl -pi -e 's/^(goog\.(require|requireType)\('\'"${require}"\''\);)/const \{'"${deconstructed_comma}"'\} = \1/' "${filepath}"
|
||||
|
||||
for require_prop in $(echo "${properties_accessed}"); do
|
||||
inf "Updating references of ${require}.${require_prop} to ${require_prop}..."
|
||||
perl -pi -e 's/'"${require}"'\.'"${require_prop}"'([^'\''\w])/'"${require_prop}"'\1/g' "${filepath}"
|
||||
for require_prop in echo "${properties_accessed}"; do
|
||||
inf "Updating references of ${require}.${require_prop} to ${require_name}.${require_prop}..."
|
||||
perl -pi -e 's/'"${require}"'\.'"${require_prop}"'([^'\''\w])/'"${require_name}"'\.'"${require_prop}"'\1/g' "${filepath}"
|
||||
done
|
||||
continue
|
||||
fi
|
||||
|
||||
local require_name=$(echo "${require}" | perl -pe 's/(\w+\.)+(\w+)/\2/g')
|
||||
inf "Updating require declaration for ${require}..."
|
||||
perl -pi -e 's/^(goog\.(require|requireType)\('\'"${require}"\''\);)/const '"${require_name}"' = \1/' "${filepath}"
|
||||
|
||||
inf "Updating references of ${require} to ${require_name}..."
|
||||
perl -pi -e 's/'"${require}"'([^'\''\w])/'"${require_name}"'\1/g' "${filepath}"
|
||||
inf "Updating direct references of ${require} to ${require_name}..."
|
||||
perl -pi -e 's/'"${require}"'([^'\''\w]\.)/'"${require_name}"'\1/g' "${filepath}"
|
||||
done
|
||||
|
||||
local missing_requires=$(perl -nle'print $& while m{(?<!'\'')Blockly(\.\w+)+}g' "${filepath}")
|
||||
if [[ ! -z "${missing_require_lines}" ]]; then
|
||||
err "Missing requires for: ${missing_requires} Please manually fix."
|
||||
missing_requires=$(echo "${missing_requires}" | tr ' ' '\n' | sort -u)
|
||||
if [[ -n "${missing_requires}" ]]; then
|
||||
err "Missing requires for:\n${missing_requires}\nPlease manually fix."
|
||||
fi
|
||||
|
||||
success "Completed automation for step 3. Please manually review and reorder requires."
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Runs step 4 of the automated conversion.
|
||||
# Arguments:
|
||||
# The filepath of the file being converted.
|
||||
#######################################
|
||||
step4() {
|
||||
local filepath="$1"
|
||||
if [ -z ${filepath} ]; then
|
||||
err "filepath is unset"
|
||||
return 1
|
||||
fi
|
||||
inf "Running clang-format"
|
||||
npx clang-format -i "${filepath}"
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Runs the specified step.
|
||||
# Arguments:
|
||||
@@ -244,11 +228,11 @@ step4() {
|
||||
run-step() {
|
||||
local step="$1"
|
||||
local filepath="$2"
|
||||
if [ -z "${step}" ]; then
|
||||
if [[ -z "${step}" ]]; then
|
||||
err "Missing argument (1-4)"
|
||||
return 1
|
||||
fi
|
||||
if [ -z "${filepath}" ]; then
|
||||
if [[ -z "${filepath}" ]]; then
|
||||
err "Missing argument filepath"
|
||||
return 1
|
||||
fi
|
||||
@@ -257,45 +241,60 @@ run-step() {
|
||||
|
||||
case "${step}" in
|
||||
2)
|
||||
step2 ${filepath}
|
||||
step2 "${filepath}"
|
||||
;;
|
||||
3)
|
||||
step3 ${filepath}
|
||||
step3 "${filepath}"
|
||||
;;
|
||||
4)
|
||||
step4 ${filepath}
|
||||
step4 "${filepath}"
|
||||
;;
|
||||
*)
|
||||
err 'INVALID ARGUMENT'
|
||||
err "INVALID ARGUMENT ${step}"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Prints usage information.
|
||||
#######################################
|
||||
function help {
|
||||
help() {
|
||||
echo "Conversion steps:"
|
||||
echo " 1. Use IDE to convert var to let/const"
|
||||
echo " 2. Rewrite the goog.provide statement as goog.module and explicitly enumerate exports"
|
||||
echo " 3. Rewrite goog.requires statements and add missing requires (often skipped for simple files)"
|
||||
echo " 4. Run clang-format on the whole file"
|
||||
echo ""
|
||||
echo "Usage: $0 [-h|-c <number>|-s <number>] <filepath>"
|
||||
echo " -h Display help"
|
||||
echo " -c <step> <filepath> Create a commit for the specified step [2-4]"
|
||||
echo " -s <step> <filepath> Run the specified step [1-4]"
|
||||
echo "Usage: $0 [-h] [-c <step> <filepath>|-s <step> <filepath>]"
|
||||
echo " -h Display help and exit"
|
||||
echo " -c <step> <filepath> Create a commit for the specified step [2-4]"
|
||||
echo " -s <step> <filepath> Run the specified step [1-4]"
|
||||
}
|
||||
|
||||
if [ "$1" = "" ]; then
|
||||
help
|
||||
else
|
||||
command="$1"
|
||||
shift
|
||||
case $command in
|
||||
-h) help $@;;
|
||||
-c) commit-step $@;;
|
||||
-s) run-step $@;;
|
||||
*) help;;
|
||||
esac
|
||||
fi
|
||||
#######################################
|
||||
# Main entry point.
|
||||
#######################################
|
||||
main() {
|
||||
if [ "$1" = "" ]; then
|
||||
help
|
||||
else
|
||||
local filepath=""
|
||||
# Support filepath as first argument.
|
||||
verify-filepath "$1" "false"
|
||||
if [[ $? -eq 0 ]]; then
|
||||
filepath="$1"
|
||||
shift
|
||||
fi
|
||||
|
||||
local command="$1"
|
||||
shift
|
||||
case $command in
|
||||
-c) commit-step "$@" "${filepath}" ;;
|
||||
-s) run-step "$@" "${filepath}" ;;
|
||||
*) err "INVALID ARGUMENT ${command}";;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
@@ -10,7 +10,7 @@ goog.addDependency('../../blocks/variables_dynamic.js', ['Blockly.Constants.Vari
|
||||
goog.addDependency('../../core/block.js', ['Blockly.Block'], ['Blockly.ASTNode', 'Blockly.Blocks', 'Blockly.Connection', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.IASTNodeLocation', 'Blockly.IDeletable', 'Blockly.Input', 'Blockly.Tooltip', 'Blockly.Workspace', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.fieldRegistry', 'Blockly.inputTypes', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.object'], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/block_animations.js', ['Blockly.blockAnimations'], ['Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/block_drag_surface.js', ['Blockly.BlockDragSurfaceSvg'], ['Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/block_dragger.js', ['Blockly.BlockDragger'], ['Blockly.Events', 'Blockly.Events.BlockDrag', 'Blockly.Events.BlockMove', 'Blockly.IBlockDragger', 'Blockly.InsertionMarkerManager', 'Blockly.blockAnimations', 'Blockly.constants', 'Blockly.registry', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']);
|
||||
goog.addDependency('../../core/block_dragger.js', ['Blockly.BlockDragger'], ['Blockly.Events', 'Blockly.Events.BlockDrag', 'Blockly.Events.BlockMove', 'Blockly.IBlockDragger', 'Blockly.InsertionMarkerManager', 'Blockly.blockAnimations', 'Blockly.registry', 'Blockly.utils.Coordinate', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/block_svg.js', ['Blockly.BlockSvg'], ['Blockly.ASTNode', 'Blockly.Block', 'Blockly.ContextMenu', 'Blockly.ContextMenuRegistry', 'Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Events.Selected', 'Blockly.IASTNodeLocationSvg', 'Blockly.IBoundedElement', 'Blockly.ICopyable', 'Blockly.IDraggable', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.TabNavigateCursor', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.Xml', 'Blockly.blockAnimations', 'Blockly.blockRendering.IPathObject', 'Blockly.browserEvents', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.deprecation', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent']);
|
||||
goog.addDependency('../../core/blockly.js', ['Blockly'], ['Blockly.ComponentManager', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.FinishedLoading', 'Blockly.Events.Ui', 'Blockly.Events.UiBase', 'Blockly.Events.VarCreate', 'Blockly.Procedures', 'Blockly.ShortcutRegistry', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.Variables', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.browserEvents', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.inject', 'Blockly.inputTypes', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.colour', 'Blockly.utils.deprecation', 'Blockly.utils.toolbox']);
|
||||
goog.addDependency('../../core/blocks.js', ['Blockly.Blocks'], [], {'lang': 'es6', 'module': 'goog'});
|
||||
@@ -28,7 +28,7 @@ goog.addDependency('../../core/contextmenu.js', ['Blockly.ContextMenu'], ['Block
|
||||
goog.addDependency('../../core/contextmenu_items.js', ['Blockly.ContextMenuItems'], ['Blockly.ContextMenuRegistry', 'Blockly.Events', 'Blockly.constants', 'Blockly.inputTypes'], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/contextmenu_registry.js', ['Blockly.ContextMenuRegistry'], [], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/css.js', ['Blockly.Css'], [], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/delete_area.js', ['Blockly.DeleteArea'], ['Blockly.BlockSvg', 'Blockly.DragTarget', 'Blockly.IDeleteArea']);
|
||||
goog.addDependency('../../core/delete_area.js', ['Blockly.DeleteArea'], ['Blockly.BlockSvg', 'Blockly.DragTarget', 'Blockly.IDeleteArea', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/drag_target.js', ['Blockly.DragTarget'], ['Blockly.IDragTarget'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/dropdowndiv.js', ['Blockly.DropDownDiv'], ['Blockly.utils.Rect', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.style']);
|
||||
goog.addDependency('../../core/events/block_events.js', ['Blockly.Events.BlockBase', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Events.Change', 'Blockly.Events.Create', 'Blockly.Events.Delete', 'Blockly.Events.Move'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml', 'Blockly.connectionTypes', 'Blockly.registry', 'Blockly.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml']);
|
||||
@@ -53,24 +53,24 @@ goog.addDependency('../../core/field_angle.js', ['Blockly.FieldAngle'], ['Blockl
|
||||
goog.addDependency('../../core/field_checkbox.js', ['Blockly.FieldCheckbox'], ['Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.utils.dom', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/field_colour.js', ['Blockly.FieldColour'], ['Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.browserEvents', 'Blockly.fieldRegistry', 'Blockly.utils.IdGenerator', 'Blockly.utils.KeyCodes', 'Blockly.utils.Size', 'Blockly.utils.aria', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/field_dropdown.js', ['Blockly.FieldDropdown'], ['Blockly.DropDownDiv', 'Blockly.Field', 'Blockly.Menu', 'Blockly.MenuItem', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.string', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/field_image.js', ['Blockly.FieldImage'], ['Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object']);
|
||||
goog.addDependency('../../core/field_image.js', ['Blockly.FieldImage'], ['Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/field_label.js', ['Blockly.FieldLabel'], ['Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.object']);
|
||||
goog.addDependency('../../core/field_label_serializable.js', ['Blockly.FieldLabelSerializable'], ['Blockly.FieldLabel', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.object']);
|
||||
goog.addDependency('../../core/field_multilineinput.js', ['Blockly.FieldMultilineInput'], ['Blockly.Css', 'Blockly.Field', 'Blockly.FieldTextInput', 'Blockly.WidgetDiv', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.KeyCodes', 'Blockly.utils.Svg', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent'], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/field_label_serializable.js', ['Blockly.FieldLabelSerializable'], ['Blockly.FieldLabel', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/field_multilineinput.js', ['Blockly.FieldMultilineInput'], ['Blockly.Css', 'Blockly.Field', 'Blockly.FieldTextInput', 'Blockly.WidgetDiv', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.KeyCodes', 'Blockly.utils.Svg', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/field_number.js', ['Blockly.FieldNumber'], ['Blockly.FieldTextInput', 'Blockly.fieldRegistry', 'Blockly.utils.aria', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/field_registry.js', ['Blockly.fieldRegistry'], ['Blockly.registry']);
|
||||
goog.addDependency('../../core/field_registry.js', ['Blockly.fieldRegistry'], ['Blockly.registry'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/field_textinput.js', ['Blockly.FieldTextInput'], ['Blockly', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.WidgetDiv', 'Blockly.browserEvents', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.KeyCodes', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/field_variable.js', ['Blockly.FieldVariable'], ['Blockly.Events.BlockChange', 'Blockly.FieldDropdown', 'Blockly.Msg', 'Blockly.VariableModel', 'Blockly.Variables', 'Blockly.Xml', 'Blockly.fieldRegistry', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.object']);
|
||||
goog.addDependency('../../core/field_variable.js', ['Blockly.FieldVariable'], ['Blockly.Events.BlockChange', 'Blockly.FieldDropdown', 'Blockly.Msg', 'Blockly.VariableModel', 'Blockly.Variables', 'Blockly.Xml', 'Blockly.fieldRegistry', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/flyout_base.js', ['Blockly.Flyout'], ['Blockly.Block', 'Blockly.ComponentManager', 'Blockly.DeleteArea', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'Blockly.FlyoutMetricsManager', 'Blockly.Gesture', 'Blockly.IFlyout', 'Blockly.ScrollbarPair', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.blockRendering', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.toolbox', 'Blockly.utils.xml']);
|
||||
goog.addDependency('../../core/flyout_button.js', ['Blockly.FlyoutButton'], ['Blockly.Css', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.style'], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/flyout_horizontal.js', ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.DropDownDiv', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.WidgetDiv', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.object', 'Blockly.utils.toolbox']);
|
||||
goog.addDependency('../../core/flyout_horizontal.js', ['Blockly.HorizontalFlyout'], ['Blockly.DropDownDiv', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.WidgetDiv', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.object', 'Blockly.utils.toolbox'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/flyout_vertical.js', ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.DropDownDiv', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.WidgetDiv', 'Blockly.constants', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.object', 'Blockly.utils.toolbox']);
|
||||
goog.addDependency('../../core/generator.js', ['Blockly.Generator'], ['Blockly.Block', 'Blockly.internalConstants', 'Blockly.utils.deprecation']);
|
||||
goog.addDependency('../../core/generator.js', ['Blockly.Generator'], ['Blockly', 'Blockly.internalConstants', 'Blockly.utils.deprecation'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/gesture.js', ['Blockly.Gesture'], ['Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.Events', 'Blockly.Events.Click', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.Workspace', 'Blockly.WorkspaceDragger', 'Blockly.blockAnimations', 'Blockly.browserEvents', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Coordinate']);
|
||||
goog.addDependency('../../core/grid.js', ['Blockly.Grid'], ['Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.userAgent']);
|
||||
goog.addDependency('../../core/icon.js', ['Blockly.Icon'], ['Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom']);
|
||||
goog.addDependency('../../core/grid.js', ['Blockly.Grid'], ['Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/icon.js', ['Blockly.Icon'], ['Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/inject.js', ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Tooltip', 'Blockly.WidgetDiv', 'Blockly.Workspace', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.WorkspaceSvg', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Svg', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.userAgent']);
|
||||
goog.addDependency('../../core/input.js', ['Blockly.Input'], ['Blockly.Connection', 'Blockly.FieldLabel', 'Blockly.fieldRegistry', 'Blockly.inputTypes'], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/input.js', ['Blockly.Input'], ['Blockly.Connection', 'Blockly.FieldLabel', 'Blockly.constants', 'Blockly.fieldRegistry', 'Blockly.inputTypes'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/input_types.js', ['Blockly.inputTypes'], ['Blockly.connectionTypes']);
|
||||
goog.addDependency('../../core/insertion_marker_manager.js', ['Blockly.InsertionMarkerManager'], ['Blockly.ComponentManager', 'Blockly.Events', 'Blockly.blockAnimations', 'Blockly.connectionTypes', 'Blockly.internalConstants'], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/interfaces/i_ast_node_location.js', ['Blockly.IASTNodeLocation'], [], {'lang': 'es6', 'module': 'goog'});
|
||||
@@ -91,7 +91,7 @@ goog.addDependency('../../core/interfaces/i_drag_target.js', ['Blockly.IDragTarg
|
||||
goog.addDependency('../../core/interfaces/i_draggable.js', ['Blockly.IDraggable'], ['Blockly.IDeletable'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/interfaces/i_flyout.js', ['Blockly.IFlyout'], ['Blockly.IRegistrable'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/interfaces/i_keyboard_accessible.js', ['Blockly.IKeyboardAccessible'], [], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/interfaces/i_metrics_manager.js', ['Blockly.IMetricsManager'], []);
|
||||
goog.addDependency('../../core/interfaces/i_metrics_manager.js', ['Blockly.IMetricsManager'], [], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/interfaces/i_movable.js', ['Blockly.IMovable'], [], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/interfaces/i_positionable.js', ['Blockly.IPositionable'], ['Blockly.IComponent'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/interfaces/i_registrable.js', ['Blockly.IRegistrable'], [], {'lang': 'es6', 'module': 'goog'});
|
||||
@@ -108,7 +108,7 @@ goog.addDependency('../../core/keyboard_nav/cursor.js', ['Blockly.Cursor'], ['Bl
|
||||
goog.addDependency('../../core/keyboard_nav/marker.js', ['Blockly.Marker'], ['Blockly.ASTNode']);
|
||||
goog.addDependency('../../core/keyboard_nav/tab_navigate_cursor.js', ['Blockly.TabNavigateCursor'], ['Blockly.ASTNode', 'Blockly.BasicCursor', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/marker_manager.js', ['Blockly.MarkerManager'], ['Blockly.Cursor', 'Blockly.Marker']);
|
||||
goog.addDependency('../../core/menu.js', ['Blockly.Menu'], ['Blockly.browserEvents', 'Blockly.utils.Coordinate', 'Blockly.utils.KeyCodes', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.style']);
|
||||
goog.addDependency('../../core/menu.js', ['Blockly.Menu'], ['Blockly.browserEvents', 'Blockly.utils.Coordinate', 'Blockly.utils.KeyCodes', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.style'], {'lang': 'es6', 'module': 'goog'});
|
||||
goog.addDependency('../../core/menuitem.js', ['Blockly.MenuItem'], ['Blockly.utils.IdGenerator', 'Blockly.utils.aria', 'Blockly.utils.dom']);
|
||||
goog.addDependency('../../core/metrics_manager.js', ['Blockly.FlyoutMetricsManager', 'Blockly.MetricsManager'], ['Blockly.IMetricsManager', 'Blockly.registry', 'Blockly.utils.Size', 'Blockly.utils.toolbox'], {'lang': 'es5'});
|
||||
goog.addDependency('../../core/msg.js', ['Blockly.Msg'], ['Blockly.utils.global']);
|
||||
|
||||
Reference in New Issue
Block a user