Merge branch 'goog_module' into field_textinput

This commit is contained in:
Aaron Dodson
2021-07-23 15:31:02 -07:00
committed by GitHub
21 changed files with 1057 additions and 982 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 '&#10'. 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(/&#10;/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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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');

View File

@@ -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;

View File

@@ -14,6 +14,7 @@
goog.module('Blockly.IRegistrableField');
goog.module.declareLegacyNamespace();
/* eslint-disable-next-line no-unused-vars */
const Field = goog.requireType('Blockly.Field');

View File

@@ -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');

View File

@@ -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');

View File

@@ -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;

View File

@@ -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');

View File

@@ -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 "$@"

View File

@@ -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']);