fix: Fix compilation errors under Closure's strict mode (#6073)

* fix: Fix errors under strict compilation.

* fix: Fix tests that referenced properties converted to data attributes.

* fix: Incorporate feedback on resolving compiler errors.

* refactor: Revert changes to skew and translate attributes.

* refactor: Introduce LegacyContextMenuOption type to correspond to documented fields.

* refactor: Introduce PathLeftShape and PathDownShape vs casting to PuzzleTab/Notch.

* chore: Added nullability modifiers to type annotations.

* refactor: Export FlyoutItem directly.

* chore: clang-format renderers/zelos/drawer.js.
This commit is contained in:
Aaron Dodson
2022-04-19 14:17:17 -07:00
committed by GitHub
parent b0612da6f3
commit edc2a5cd0c
58 changed files with 758 additions and 369 deletions

View File

@@ -20,6 +20,16 @@ const dom = goog.require('Blockly.utils.dom');
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
const {Svg} = goog.require('Blockly.utils.Svg');
/**
* A bounding box for a cloned block.
* @typedef {{
* x: number,
* y: number,
* width: number,
* height: number
* }}
*/
let CloneRect; // eslint-disable-line no-unused-vars
/**
* PID of disconnect UI animation. There can only be one at a time.
@@ -47,13 +57,13 @@ const disposeUiEffect = function(block) {
const xy = workspace.getSvgXY(svgGroup);
// Deeply clone the current block.
const clone = svgGroup.cloneNode(true);
clone.translateX_ = xy.x;
clone.translateY_ = xy.y;
clone.setAttribute('transform', 'translate(' + xy.x + ',' + xy.y + ')');
workspace.getParentSvg().appendChild(clone);
clone.bBox_ = clone.getBBox();
const bBox = clone.getBBox();
const cloneRect =
{'x': xy.x, 'y': xy.y, 'width': bBox.width, 'height': bBox.height};
// Start the animation.
disposeUiStep(clone, workspace.RTL, new Date, workspace.scale);
disposeUiStep(clone, cloneRect, workspace.RTL, new Date, workspace.scale);
};
exports.disposeUiEffect = disposeUiEffect;
@@ -62,25 +72,26 @@ exports.disposeUiEffect = disposeUiEffect;
* This is a class method, not an instance method since the original block has
* been destroyed and is no longer accessible.
* @param {!Element} clone SVG element to animate and dispose of.
* @param {!CloneRect} rect Starting rect of the clone.
* @param {boolean} rtl True if RTL, false if LTR.
* @param {!Date} start Date of animation's start.
* @param {number} workspaceScale Scale of workspace.
*/
const disposeUiStep = function(clone, rtl, start, workspaceScale) {
const ms = new Date - start;
const disposeUiStep = function(clone, rect, rtl, start, workspaceScale) {
const ms = (new Date).getTime() - start.getTime();
const percent = ms / 150;
if (percent > 1) {
dom.removeNode(clone);
} else {
const x = clone.translateX_ +
(rtl ? -1 : 1) * clone.bBox_.width * workspaceScale / 2 * percent;
const y = clone.translateY_ + clone.bBox_.height * workspaceScale * percent;
const x =
rect.x + (rtl ? -1 : 1) * rect.width * workspaceScale / 2 * percent;
const y = rect.y + rect.height * workspaceScale * percent;
const scale = (1 - percent) * workspaceScale;
clone.setAttribute(
'transform',
'translate(' + x + ',' + y + ')' +
' scale(' + scale + ')');
setTimeout(disposeUiStep, 10, clone, rtl, start, workspaceScale);
setTimeout(disposeUiStep, 10, clone, rect, rtl, start, workspaceScale);
}
};
@@ -129,7 +140,7 @@ exports.connectionUiEffect = connectionUiEffect;
* @param {number} scale Scale of workspace.
*/
const connectionUiStep = function(ripple, start, scale) {
const ms = new Date - start;
const ms = (new Date).getTime() - start.getTime();
const percent = ms / 150;
if (percent > 1) {
dom.removeNode(ripple);
@@ -174,19 +185,21 @@ const disconnectUiStep = function(group, magnitude, start) {
const DURATION = 200; // Milliseconds.
const WIGGLES = 3; // Half oscillations.
const ms = new Date - start;
const ms = (new Date).getTime() - start.getTime();
const percent = ms / DURATION;
if (percent > 1) {
group.skew_ = '';
(/** @type {?} */ (group)).skew_ = '';
} else {
const skew = Math.round(
Math.sin(percent * Math.PI * WIGGLES) * (1 - percent) * magnitude);
group.skew_ = 'skewX(' + skew + ')';
(/** @type {?} */ (group)).skew_ = 'skewX(' + skew + ')';
disconnectGroup = group;
disconnectPid = setTimeout(disconnectUiStep, 10, group, magnitude, start);
}
group.setAttribute('transform', group.translate_ + group.skew_);
group.setAttribute(
'transform',
(/** @type {?} */ (group)).translate_ + (/** @type {?} */ (group)).skew_);
};
/**
@@ -198,8 +211,8 @@ const disconnectUiStop = function() {
if (disconnectGroup) {
clearTimeout(disconnectPid);
const group = disconnectGroup;
group.skew_ = '';
group.setAttribute('transform', group.translate_);
(/** @type {?} */ (group)).skew_ = '';
group.setAttribute('transform', (/** @type {?} */ (group)).translate_);
disconnectGroup = null;
}
};

View File

@@ -30,6 +30,8 @@ const {Coordinate} = goog.require('Blockly.utils.Coordinate');
const {IBlockDragger} = goog.require('Blockly.IBlockDragger');
/* eslint-disable-next-line no-unused-vars */
const {IDragTarget} = goog.requireType('Blockly.IDragTarget');
/* eslint-disable-next-line no-unused-vars */
const {Icon} = goog.requireType('Blockly.Icon');
const {InsertionMarkerManager} = goog.require('Blockly.InsertionMarkerManager');
/* eslint-disable-next-line no-unused-vars */
const {WorkspaceSvg} = goog.requireType('Blockly.WorkspaceSvg');
@@ -99,7 +101,7 @@ const BlockDragger = class {
* 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.
* @type {Array<!Object>}
* @type {Array<!IconPositionData>}
* @protected
*/
this.dragIconData_ = initIconData(block);
@@ -450,12 +452,23 @@ const BlockDragger = class {
}
};
/**
* Data about the position of a given icon.
* @typedef {{
* location:!Coordinate,
* icon:!Icon,
* }}
*/
let IconPositionData;
exports.IconPositionData = IconPositionData;
/**
* 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 {!BlockSvg} block The root block that is being dragged.
* @return {!Array<!Object>} The list of all icons and their locations.
* @return {!Array<!IconPositionData>} The list of all icons and their
* locations.
*/
const initIconData = function(block) {
// Build a list of icons that need to be moved and where they started.

View File

@@ -26,7 +26,6 @@ const dom = goog.require('Blockly.utils.dom');
const eventUtils = goog.require('Blockly.Events.utils');
const internalConstants = goog.require('Blockly.internalConstants');
const svgMath = goog.require('Blockly.utils.svgMath');
const userAgent = goog.require('Blockly.utils.userAgent');
const {ASTNode} = goog.require('Blockly.ASTNode');
const {Block} = goog.require('Blockly.Block');
/* eslint-disable-next-line no-unused-vars */
@@ -131,7 +130,8 @@ class BlockSvg extends Block {
/**
* An optional method for defining custom block context menu items.
* @type {undefined|?function(!Array<!Object>)}
* @type {undefined|?function(!Array<!ContextMenuRegistry.ContextMenuOption|
* !ContextMenuRegistry.LegacyContextMenuOption>)}
*/
this.customContextMenu = this.customContextMenu;
@@ -196,7 +196,7 @@ class BlockSvg extends Block {
* @private
*/
this.svgGroup_ = dom.createSvgElement(Svg.G, {}, null);
this.svgGroup_.translate_ = '';
(/** @type {?} */ (this.svgGroup_)).translate_ = '';
/**
* A block style object.
@@ -252,13 +252,7 @@ class BlockSvg extends Block {
Tooltip.bindMouseEvents(svgPath);
// Expose this block's ID on its top-level SVG group.
if (this.svgGroup_.dataset) {
this.svgGroup_.dataset['id'] = this.id;
} else if (userAgent.IE) {
// SVGElement.dataset is not available on IE11, but data-* properties
// can be set with setAttribute().
this.svgGroup_.setAttribute('data-id', this.id);
}
this.svgGroup_.setAttribute('data-id', this.id);
this.doInit_();
}
@@ -552,10 +546,13 @@ class BlockSvg extends Block {
if (this.useDragSurface_) {
this.workspace.getBlockDragSurface().translateSurface(newLoc.x, newLoc.y);
} else {
this.svgGroup_.translate_ =
(/** @type {?} */ (this.svgGroup_)).translate_ =
'translate(' + newLoc.x + ',' + newLoc.y + ')';
this.svgGroup_.setAttribute(
'transform', this.svgGroup_.translate_ + this.svgGroup_.skew_);
(/** @type {?} */ (this.svgGroup_))
.setAttribute(
'transform',
(/** @type {?} */ (this.svgGroup_)).translate_ +
(/** @type {?} */ (this.svgGroup_)).skew_);
}
}
@@ -744,7 +741,9 @@ class BlockSvg extends Block {
/**
* Generate the context menu for this block.
* @return {?Array<!Object>} Context menu options or null if no menu.
* @return {?Array<!ContextMenuRegistry.ContextMenuOption|
* !ContextMenuRegistry.LegacyContextMenuOption>}
* Context menu options or null if no menu.
* @protected
*/
generateContextMenu() {
@@ -815,8 +814,8 @@ class BlockSvg extends Block {
setDragging(adding) {
if (adding) {
const group = this.getSvgRoot();
group.translate_ = '';
group.skew_ = '';
(/** @type {?} */ (group)).translate_ = '';
(/** @type {?} */ (group)).skew_ = '';
common.draggingConnections.push(...this.getConnections_(true));
dom.addClass(
/** @type {!Element} */ (this.svgGroup_), 'blocklyDragging');

View File

@@ -211,12 +211,22 @@ exports.unbind = unbind;
* @alias Blockly.browserEvents.isTargetInput
*/
const isTargetInput = function(e) {
return e.target.type === 'textarea' || e.target.type === 'text' ||
e.target.type === 'number' || e.target.type === 'email' ||
e.target.type === 'password' || e.target.type === 'search' ||
e.target.type === 'tel' || e.target.type === 'url' ||
e.target.isContentEditable ||
(e.target.dataset && e.target.dataset.isTextInput === 'true');
if (e.target instanceof HTMLElement) {
if (e.target.isContentEditable ||
e.target.getAttribute('data-is-text-input') === 'true') {
return true;
}
if (e.target instanceof HTMLInputElement) {
const target = e.target;
return target.type === 'textarea' || target.type === 'text' ||
target.type === 'number' || target.type === 'email' ||
target.type === 'password' || target.type === 'search' ||
target.type === 'tel' || target.type === 'url';
}
}
return false;
};
exports.isTargetInput = isTargetInput;
@@ -240,7 +250,7 @@ exports.isRightButton = isRightButton;
* Returns the converted coordinates of the given mouse event.
* The origin (0,0) is the top-left corner of the Blockly SVG.
* @param {!Event} e Mouse event.
* @param {!Element} svg SVG element.
* @param {!SVGSVGElement} svg SVG element.
* @param {?SVGMatrix} matrix Inverted screen CTM to use.
* @return {!SVGPoint} Object with .x and .y properties.
* @alias Blockly.browserEvents.mouseToSvg
@@ -259,7 +269,7 @@ exports.mouseToSvg = mouseToSvg;
/**
* Returns the scroll delta of a mouse event in pixel units.
* @param {!Event} e Mouse event.
* @param {!WheelEvent} e Mouse event.
* @return {{x: number, y: number}} Scroll delta object with .x and .y
* properties.
* @alias Blockly.browserEvents.getScrollDeltaPixels

View File

@@ -47,8 +47,8 @@ const Bubble = class {
/**
* @param {!WorkspaceSvg} workspace The workspace on which to draw the
* bubble.
* @param {!Element} content SVG content for the bubble.
* @param {!Element} shape SVG element to avoid eclipsing.
* @param {!SVGElement} content SVG content for the bubble.
* @param {!SVGElement} shape SVG element to avoid eclipsing.
* @param {!Coordinate} anchorXY Absolute position of bubble's
* anchor point.
* @param {?number} bubbleWidth Width of bubble, or null if not resizable.
@@ -227,7 +227,7 @@ const Bubble = class {
'filter': 'url(#' +
this.workspace_.getRenderer().getConstants().embossFilterId + ')',
};
if (userAgent.JAVA_FX) {
if (userAgent.JavaFx) {
// Multiple reports that JavaFX can't handle filters.
// https://github.com/google/blockly/issues/99
filter = {};
@@ -302,9 +302,7 @@ const Bubble = class {
* @param {string} id ID of block.
*/
setSvgId(id) {
if (this.bubbleGroup_.dataset) {
this.bubbleGroup_.dataset['blockId'] = id;
}
this.bubbleGroup_.setAttribute('data-block-id', id);
}
/**
@@ -443,7 +441,7 @@ const Bubble = class {
const optimalLeft = this.getOptimalRelativeLeft_(viewMetrics);
const optimalTop = this.getOptimalRelativeTop_(viewMetrics);
const bbox = this.shape_.getBBox();
const bbox = (/** @type {!SVGGraphicsElement} */ (this.shape_)).getBBox();
const topPosition = {
x: optimalLeft,

View File

@@ -29,8 +29,7 @@ const {IBubble} = goog.requireType('Blockly.IBubble');
const {IDeleteArea} = goog.requireType('Blockly.IDeleteArea');
/* eslint-disable-next-line no-unused-vars */
const {IDragTarget} = goog.requireType('Blockly.IDragTarget');
/* eslint-disable-next-line no-unused-vars */
const {WorkspaceCommentSvg} = goog.requireType('Blockly.WorkspaceCommentSvg');
const {WorkspaceCommentSvg} = goog.require('Blockly.WorkspaceCommentSvg');
/* eslint-disable-next-line no-unused-vars */
const {WorkspaceSvg} = goog.requireType('Blockly.WorkspaceSvg');
/** @suppress {extraRequire} */
@@ -243,12 +242,9 @@ const BubbleDragger = class {
* @private
*/
fireMoveEvent_() {
if (this.draggingBubble_.isComment) {
// TODO (adodson): Resolve build errors when requiring
// WorkspaceCommentSvg.
if (this.draggingBubble_ instanceof WorkspaceCommentSvg) {
const event = /** @type {!CommentMove} */
(new (eventUtils.get(eventUtils.COMMENT_MOVE))(
/** @type {!WorkspaceCommentSvg} */ (this.draggingBubble_)));
(new (eventUtils.get(eventUtils.COMMENT_MOVE))(this.draggingBubble_));
event.setOldCoordinate(this.startXY_);
event.recordNew();
eventUtils.fire(event);

View File

@@ -73,7 +73,7 @@ exports.paste = paste;
const duplicate = function(toDuplicate) {
const oldCopyData = copyData;
copy(toDuplicate);
const pastedThing = toDuplicate.workspace.paste(copyData.saveInfo);
const pastedThing = toDuplicate.toCopyData().source.paste(copyData.saveInfo);
copyData = oldCopyData;
return pastedThing;
};

View File

@@ -108,7 +108,7 @@ class Comment extends Icon {
/**
* The editable text area, or null if not created.
* @type {?Element}
* @type {?HTMLTextAreaElement}
* @private
*/
this.textarea_ = null;
@@ -181,7 +181,8 @@ class Comment extends Icon {
body.setAttribute('xmlns', dom.HTML_NS);
body.className = 'blocklyMinimalBody';
this.textarea_ = document.createElementNS(dom.HTML_NS, 'textarea');
this.textarea_ = /** @type {!HTMLTextAreaElement} */ (
document.createElementNS(dom.HTML_NS, 'textarea'));
const textarea = this.textarea_;
textarea.className = 'blocklyCommentTextarea';
textarea.setAttribute('dir', this.block_.RTL ? 'RTL' : 'LTR');

View File

@@ -135,11 +135,12 @@ const svgResize = function(workspace) {
}
const svg = mainWorkspace.getParentSvg();
const cachedSize = mainWorkspace.getCachedParentSvgSize();
const div = svg.parentNode;
if (!div) {
const div = svg.parentElement;
if (!(div instanceof HTMLElement)) {
// Workspace deleted, or something.
return;
}
const width = div.offsetWidth;
const height = div.offsetHeight;
if (cachedSize.width !== width) {
@@ -231,7 +232,7 @@ const createBlockDefinitionsFromJsonArray = function(jsonArray) {
console.warn(`Block definition #${i} in JSON array is ${elem}. Skipping`);
continue;
}
const type = elem.type;
const type = elem['type'];
if (!type) {
console.warn(
`Block definition #${i} in JSON array is missing a type attribute. ` +

View File

@@ -30,6 +30,8 @@ const {Block} = goog.requireType('Blockly.Block');
/* eslint-disable-next-line no-unused-vars */
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
const {config} = goog.require('Blockly.config');
/* eslint-disable-next-line no-unused-vars */
const {ContextMenuRegistry} = goog.requireType('Blockly.ContextMenuRegistry');
const {Coordinate} = goog.require('Blockly.utils.Coordinate');
const {MenuItem} = goog.require('Blockly.MenuItem');
const {Menu} = goog.require('Blockly.Menu');
@@ -104,7 +106,9 @@ let menu_ = null;
/**
* Construct the menu based on the list of options and show the menu.
* @param {!Event} e Mouse event.
* @param {!Array<!Object>} options Array of menu options.
* @param {!Array<!ContextMenuRegistry.ContextMenuOption|
* !ContextMenuRegistry.LegacyContextMenuOption>}
* options Array of menu options.
* @param {boolean} rtl True if RTL, false if LTR.
* @alias Blockly.ContextMenu.show
*/
@@ -129,7 +133,9 @@ exports.show = show;
/**
* Create the context menu object and populate it with the given options.
* @param {!Array<!Object>} options Array of menu options.
* @param {!Array<!ContextMenuRegistry.ContextMenuOption|
* !ContextMenuRegistry.LegacyContextMenuOption>}
* options Array of menu options.
* @param {boolean} rtl True if RTL, false if LTR.
* @return {!Menu} The menu that will be shown on right click.
* @private
@@ -292,7 +298,8 @@ exports.callbackFactory = callbackFactory;
* Make a context menu option for deleting the current workspace comment.
* @param {!WorkspaceCommentSvg} comment The workspace comment where the
* right-click originated.
* @return {!Object} A menu option, containing text, enabled, and a callback.
* @return {!ContextMenuRegistry.LegacyContextMenuOption} A menu option,
* containing text, enabled, and a callback.
* @alias Blockly.ContextMenu.commentDeleteOption
* @package
*/
@@ -314,7 +321,8 @@ exports.commentDeleteOption = commentDeleteOption;
* Make a context menu option for duplicating the current workspace comment.
* @param {!WorkspaceCommentSvg} comment The workspace comment where the
* right-click originated.
* @return {!Object} A menu option, containing text, enabled, and a callback.
* @return {!ContextMenuRegistry.LegacyContextMenuOption} A menu option,
* containing text, enabled, and a callback.
* @alias Blockly.ContextMenu.commentDuplicateOption
* @package
*/

View File

@@ -168,6 +168,17 @@ ContextMenuRegistry.RegistryItem;
*/
ContextMenuRegistry.ContextMenuOption;
/**
* A subset of ContextMenuOption corresponding to what was publicly documented.
* ContextMenuOption should be preferred for new code.
* @typedef {{
* text: string,
* enabled: boolean,
* callback: function(!ContextMenuRegistry.Scope),
* }}
*/
ContextMenuRegistry.LegacyContextMenuOption;
/**
* Singleton instance of this class. All interactions with this class should be
* done on this object.

View File

@@ -23,6 +23,14 @@ const {Block} = goog.requireType('Blockly.Block');
const {ConnectionType} = goog.require('Blockly.ConnectionType');
const {Coordinate} = goog.require('Blockly.utils.Coordinate');
/**
* @typedef {{
* parentId: string,
* inputName: string,
* coordinate: ?Coordinate,
* }}
*/
let BlockLocation; // eslint-disable-line no-unused-vars
/**
* Class for a block move event. Created before the move.
@@ -113,7 +121,7 @@ class BlockMove extends BlockBase {
/**
* Returns the parentId and input if the block is connected,
* or the XY location if disconnected.
* @return {!Object} Collection of location info.
* @return {!BlockLocation} Collection of location info.
* @private
*/
currentLocation_() {

View File

@@ -215,7 +215,7 @@ const checkNoMutatorProperties = function(mutationName, block) {
/**
* Checks if the given object has both the 'mutationToDom' and 'domToMutation'
* functions.
* @param {!Object} object The object to check.
* @param {?} object The object to check.
* @param {string} errorPrefix The string to prepend to any error message.
* @return {boolean} True if the object has both functions. False if it has
* neither function.
@@ -231,7 +231,7 @@ const checkXmlHooks = function(object, errorPrefix) {
/**
* Checks if the given object has both the 'saveExtraState' and 'loadExtraState'
* functions.
* @param {!Object} object The object to check.
* @param {?} object The object to check.
* @param {string} errorPrefix The string to prepend to any error message.
* @return {boolean} True if the object has both functions. False if it has
* neither function.
@@ -246,7 +246,7 @@ const checkJsonHooks = function(object, errorPrefix) {
/**
* Checks if the given object has both the 'compose' and 'decompose' functions.
* @param {!Object} object The object to check.
* @param {?} object The object to check.
* @param {string} errorPrefix The string to prepend to any error message.
* @return {boolean} True if the object has both functions. False if it has
* neither function.

View File

@@ -96,7 +96,7 @@ class Field {
/**
* A generic value possessed by the field.
* Should generally be non-null, only null when the field is created.
* @type {*}
* @type {?}
* @protected
*/
this.value_ =
@@ -472,7 +472,7 @@ class Field {
* Returns a stringified version of the XML state, if it should be used.
* Otherwise this returns null, to signal the field should use its own
* serialization.
* @param {*} callingClass The class calling this method.
* @param {?} callingClass The class calling this method.
* Used to see if `this` has overridden any relevant hooks.
* @return {?string} The stringified version of the XML state, or null.
* @protected
@@ -492,9 +492,9 @@ class Field {
}
/**
* Loads the given state using either the old XML hoooks, if they should be
* Loads the given state using either the old XML hooks, if they should be
* used. Returns true to indicate loading has been handled, false otherwise.
* @param {*} callingClass The class calling this method.
* @param {?} callingClass The class calling this method.
* Used to see if `this` has overridden any relevant hooks.
* @param {*} state The state to apply to the field.
* @return {boolean} Whether the state was applied or not.
@@ -835,7 +835,8 @@ class Field {
// Browsers are inconsistent in what they return for a bounding box.
// - Webkit / Blink: fill-box / object bounding box
// - Gecko / Triden / EdgeHTML: stroke-box
const bBox = this.sourceBlock_.getHeightWidth();
const bBox =
(/** @type {!BlockSvg} */ (this.sourceBlock_)).getHeightWidth();
const scale =
/** @type {!WorkspaceSvg} */ (this.sourceBlock_.workspace).scale;
xy = this.getAbsoluteXY_();
@@ -938,8 +939,8 @@ class Field {
forceRerender() {
this.isDirty_ = true;
if (this.sourceBlock_ && this.sourceBlock_.rendered) {
this.sourceBlock_.render();
this.sourceBlock_.bumpNeighbours();
(/** @type {!BlockSvg} */ (this.sourceBlock_)).render();
(/** @type {!BlockSvg} */ (this.sourceBlock_)).bumpNeighbours();
this.updateMarkers_();
}
}

View File

@@ -23,6 +23,7 @@ const dropDownDiv = goog.require('Blockly.dropDownDiv');
const fieldRegistry = goog.require('Blockly.fieldRegistry');
const math = goog.require('Blockly.utils.math');
const userAgent = goog.require('Blockly.utils.userAgent');
const {BlockSvg} = goog.require('Blockly.BlockSvg');
const {Field} = goog.require('Blockly.Field');
const {FieldTextInput} = goog.require('Blockly.FieldTextInput');
const {KeyCodes} = goog.require('Blockly.utils.KeyCodes');
@@ -236,9 +237,11 @@ class FieldAngle extends FieldTextInput {
this.dropdownCreate_();
dropDownDiv.getContentDiv().appendChild(this.editor_);
dropDownDiv.setColour(
this.sourceBlock_.style.colourPrimary,
this.sourceBlock_.style.colourTertiary);
if (this.sourceBlock_ instanceof BlockSvg) {
dropDownDiv.setColour(
this.sourceBlock_.style.colourPrimary,
this.sourceBlock_.style.colourTertiary);
}
dropDownDiv.showPositionedByField(this, this.dropdownDispose_.bind(this));

View File

@@ -23,6 +23,7 @@ const dom = goog.require('Blockly.utils.dom');
const dropDownDiv = goog.require('Blockly.dropDownDiv');
const fieldRegistry = goog.require('Blockly.fieldRegistry');
const idGenerator = goog.require('Blockly.utils.idGenerator');
const {BlockSvg} = goog.require('Blockly.BlockSvg');
const {Field} = goog.require('Blockly.Field');
const {KeyCodes} = goog.require('Blockly.utils.KeyCodes');
/* eslint-disable-next-line no-unused-vars */
@@ -185,7 +186,7 @@ class FieldColour extends Field {
if (!this.getConstants().FIELD_COLOUR_FULL_BLOCK) {
this.createBorderRect_();
this.borderRect_.style['fillOpacity'] = '1';
} else {
} else if (this.sourceBlock_ instanceof BlockSvg) {
this.clickTarget_ = this.sourceBlock_.getSvgRoot();
}
}
@@ -198,9 +199,9 @@ class FieldColour extends Field {
if (this.borderRect_) {
this.borderRect_.style.fill = /** @type {string} */ (this.getValue());
}
} else {
} else if (this.sourceBlock_ instanceof BlockSvg) {
this.sourceBlock_.pathObject.svgPath.setAttribute(
'fill', this.getValue());
'fill', /** @type {string} */ (this.getValue()));
this.sourceBlock_.pathObject.svgPath.setAttribute('stroke', '#fff');
}
}
@@ -228,8 +229,11 @@ class FieldColour extends Field {
this.value_ = newValue;
if (this.borderRect_) {
this.borderRect_.style.fill = /** @type {string} */ (newValue);
} else if (this.sourceBlock_ && this.sourceBlock_.rendered) {
this.sourceBlock_.pathObject.svgPath.setAttribute('fill', newValue);
} else if (
this.sourceBlock_ && this.sourceBlock_.rendered &&
this.sourceBlock_ instanceof BlockSvg) {
this.sourceBlock_.pathObject.svgPath.setAttribute(
'fill', /** @type {string} */ (newValue));
this.sourceBlock_.pathObject.svgPath.setAttribute('stroke', '#fff');
}
}
@@ -295,7 +299,7 @@ class FieldColour extends Field {
*/
onClick_(e) {
const cell = /** @type {!Element} */ (e.target);
const colour = cell && cell.label;
const colour = cell && cell.getAttribute('data-colour');
if (colour !== null) {
this.setValue(colour);
dropDownDiv.hideIfOwner(this);
@@ -326,7 +330,7 @@ class FieldColour extends Field {
// Select the highlighted colour.
const highlighted = this.getHighlighted_();
if (highlighted) {
const colour = highlighted && highlighted.label;
const colour = highlighted && highlighted.getAttribute('data-colour');
if (colour !== null) {
this.setValue(colour);
}
@@ -346,6 +350,10 @@ class FieldColour extends Field {
* @private
*/
moveHighlightBy_(dx, dy) {
if (!this.highlightedIndex_) {
return;
}
const colours = this.colours_ || FieldColour.COLOURS;
const columns = this.columns_ || FieldColour.COLUMNS;
@@ -434,6 +442,10 @@ class FieldColour extends Field {
* @private
*/
getHighlighted_() {
if (!this.highlightedIndex_) {
return null;
}
const columns = this.columns_ || FieldColour.COLUMNS;
const x = this.highlightedIndex_ % columns;
const y = Math.floor(this.highlightedIndex_ / columns);
@@ -478,7 +490,8 @@ class FieldColour extends Field {
const titles = this.titles_ || FieldColour.TITLES;
const selectedColour = this.getValue();
// Create the palette.
const table = document.createElement('table');
const table =
/** @type {!HTMLTableElement} */ (document.createElement('table'));
table.className = 'blocklyColourTable';
table.tabIndex = 0;
table.dir = 'ltr';
@@ -494,9 +507,11 @@ class FieldColour extends Field {
aria.setRole(row, aria.Role.ROW);
table.appendChild(row);
}
const cell = document.createElement('td');
const cell =
/** @type {!HTMLTableCellElement} */ (document.createElement('td'));
row.appendChild(cell);
cell.label = colours[i]; // This becomes the value, if clicked.
cell.setAttribute(
'data-colour', colours[i]); // This becomes the value, if clicked.
cell.title = titles[i] || colours[i];
cell.id = idGenerator.getNextUniqueId();
cell.setAttribute('data-index', i);

View File

@@ -26,6 +26,8 @@ const fieldRegistry = goog.require('Blockly.fieldRegistry');
const parsing = goog.require('Blockly.utils.parsing');
const userAgent = goog.require('Blockly.utils.userAgent');
const utilsString = goog.require('Blockly.utils.string');
/* eslint-disable-next-line no-unused-vars */
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
const {Coordinate} = goog.require('Blockly.utils.Coordinate');
const {Field} = goog.require('Blockly.Field');
const {MenuItem} = goog.require('Blockly.MenuItem');
@@ -204,7 +206,8 @@ class FieldDropdown extends Field {
if (this.shouldAddBorderRect_()) {
this.createBorderRect_();
} else {
this.clickTarget_ = this.sourceBlock_.getSvgRoot();
this.clickTarget_ =
(/** @type {!BlockSvg} */ (this.sourceBlock_)).getSvgRoot();
}
this.createTextElement_();
@@ -290,8 +293,9 @@ class FieldDropdown extends Field {
this.sourceBlock_.getParent().getColour() :
this.sourceBlock_.getColour();
const borderColour = (this.sourceBlock_.isShadow()) ?
this.sourceBlock_.getParent().style.colourTertiary :
this.sourceBlock_.style.colourTertiary;
(/** @type {!BlockSvg} */ (this.sourceBlock_.getParent()))
.style.colourTertiary :
(/** @type {!BlockSvg} */ (this.sourceBlock_)).style.colourTertiary;
dropDownDiv.setColour(primaryColour, borderColour);
}
@@ -504,12 +508,11 @@ class FieldDropdown extends Field {
* @package
*/
applyColour() {
const style = (/** @type {!BlockSvg} */ (this.sourceBlock_)).style;
if (this.borderRect_) {
this.borderRect_.setAttribute(
'stroke', this.sourceBlock_.style.colourTertiary);
this.borderRect_.setAttribute('stroke', style.colourTertiary);
if (this.menu_) {
this.borderRect_.setAttribute(
'fill', this.sourceBlock_.style.colourTertiary);
this.borderRect_.setAttribute('fill', style.colourTertiary);
} else {
this.borderRect_.setAttribute('fill', 'transparent');
}
@@ -517,9 +520,9 @@ class FieldDropdown extends Field {
// Update arrow's colour.
if (this.sourceBlock_ && this.arrow_) {
if (this.sourceBlock_.isShadow()) {
this.arrow_.style.fill = this.sourceBlock_.style.colourSecondary;
this.arrow_.style.fill = style.colourSecondary;
} else {
this.arrow_.style.fill = this.sourceBlock_.style.colourPrimary;
this.arrow_.style.fill = style.colourPrimary;
}
}
}

View File

@@ -88,7 +88,7 @@ class FieldMultilineInput extends FieldTextInput {
*/
configure_(config) {
super.configure_(config);
config.maxLines && this.setMaxLines(config.maxLines);
config['maxLines'] && this.setMaxLines(config['maxLines']);
}
/**
@@ -103,7 +103,8 @@ class FieldMultilineInput extends FieldTextInput {
// needed so the plain-text representation of the XML produced by
// `Blockly.Xml.domToText` will appear on a single line (this is a
// limitation of the plain-text format).
fieldElement.textContent = this.getValue().replace(/\n/g, '&#10;');
fieldElement.textContent =
(/** @type {string} */ (this.getValue())).replace(/\n/g, '&#10;');
return fieldElement;
}
@@ -282,7 +283,7 @@ class FieldMultilineInput extends FieldTextInput {
let totalWidth = 0;
let totalHeight = 0;
for (let i = 0; i < nodes.length; i++) {
const tspan = /** @type {!Element} */ (nodes[i]);
const tspan = /** @type {!SVGTextElement} */ (nodes[i]);
const textWidth = dom.getTextWidth(tspan);
if (textWidth > totalWidth) {
totalWidth = textWidth;
@@ -377,8 +378,8 @@ class FieldMultilineInput extends FieldTextInput {
div.appendChild(htmlInput);
htmlInput.value = htmlInput.defaultValue = this.getEditorText_(this.value_);
htmlInput.untypedDefaultValue_ = this.value_;
htmlInput.oldValue_ = null;
htmlInput.setAttribute('data-untyped-default-value', this.value_);
htmlInput.setAttribute('data-old-value', '');
if (userAgent.GECKO) {
// In FF, ensure the browser reflows before resizing to avoid issue #2777.
setTimeout(this.resizeEditor_.bind(this), 0);

View File

@@ -71,7 +71,7 @@ class FieldTextInput extends Field {
/**
* The HTML input element.
* @type {HTMLElement}
* @type {?HTMLInputElement}
* @protected
*/
this.htmlInput_ = null;
@@ -175,7 +175,8 @@ class FieldTextInput extends Field {
}
if (this.fullBlockClickTarget_) {
this.clickTarget_ = this.sourceBlock_.getSvgRoot();
this.clickTarget_ =
(/** @type {!BlockSvg} */ (this.sourceBlock_)).getSvgRoot();
} else {
this.createBorderRect_();
}
@@ -209,7 +210,7 @@ class FieldTextInput extends Field {
this.isTextValid_ = false;
const oldValue = this.value_;
// Revert value when the text becomes invalid.
this.value_ = this.htmlInput_.untypedDefaultValue_;
this.value_ = this.htmlInput_.getAttribute('data-untyped-default-value');
if (this.sourceBlock_ && eventUtils.isEnabled()) {
eventUtils.fire(new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
this.sourceBlock_, 'field', this.name || null, oldValue,
@@ -243,10 +244,13 @@ class FieldTextInput extends Field {
if (this.sourceBlock_ && this.getConstants().FULL_BLOCK_FIELDS) {
if (this.borderRect_) {
this.borderRect_.setAttribute(
'stroke', this.sourceBlock_.style.colourTertiary);
'stroke',
(/** @type {!BlockSvg} */ (this.sourceBlock_))
.style.colourTertiary);
} else {
this.sourceBlock_.pathObject.svgPath.setAttribute(
'fill', this.getConstants().FIELD_BORDER_RECT_COLOUR);
(/** @type {!BlockSvg} */ (this.sourceBlock_))
.pathObject.svgPath.setAttribute(
'fill', this.getConstants().FIELD_BORDER_RECT_COLOUR);
}
}
}
@@ -328,11 +332,13 @@ class FieldTextInput extends Field {
*/
showInlineEditor_(quietInput) {
WidgetDiv.show(this, this.sourceBlock_.RTL, this.widgetDispose_.bind(this));
this.htmlInput_ = this.widgetCreate_();
this.htmlInput_ = /** @type {!HTMLInputElement} */ (this.widgetCreate_());
this.isBeingEdited_ = true;
if (!quietInput) {
this.htmlInput_.focus({preventScroll: true});
(/** @type {!HTMLElement} */ (this.htmlInput_)).focus({
preventScroll: true,
});
this.htmlInput_.select();
}
}
@@ -365,8 +371,9 @@ class FieldTextInput extends Field {
borderRadius = (bBox.bottom - bBox.top) / 2 + 'px';
// Pull stroke colour from the existing shadow block
const strokeColour = this.sourceBlock_.getParent() ?
this.sourceBlock_.getParent().style.colourTertiary :
this.sourceBlock_.style.colourTertiary;
(/** @type {!BlockSvg} */ (this.sourceBlock_.getParent()))
.style.colourTertiary :
(/** @type {!BlockSvg} */ (this.sourceBlock_)).style.colourTertiary;
htmlInput.style.border = (1 * scale) + 'px solid ' + strokeColour;
div.style.borderRadius = borderRadius;
div.style.transition = 'box-shadow 0.25s ease 0s';
@@ -380,8 +387,8 @@ class FieldTextInput extends Field {
div.appendChild(htmlInput);
htmlInput.value = htmlInput.defaultValue = this.getEditorText_(this.value_);
htmlInput.untypedDefaultValue_ = this.value_;
htmlInput.oldValue_ = null;
htmlInput.setAttribute('data-untyped-default-value', this.value_);
htmlInput.setAttribute('data-old-value', '');
this.resizeEditor_();
@@ -466,13 +473,13 @@ class FieldTextInput extends Field {
WidgetDiv.hide();
dropDownDiv.hideWithoutAnimation();
} else if (e.keyCode === KeyCodes.ESC) {
this.setValue(this.htmlInput_.untypedDefaultValue_);
this.setValue(this.htmlInput_.getAttribute('data-untyped-default-value'));
WidgetDiv.hide();
dropDownDiv.hideWithoutAnimation();
} else if (e.keyCode === KeyCodes.TAB) {
WidgetDiv.hide();
dropDownDiv.hideWithoutAnimation();
this.sourceBlock_.tab(this, !e.shiftKey);
(/** @type {!BlockSvg} */ (this.sourceBlock_)).tab(this, !e.shiftKey);
e.preventDefault();
}
}
@@ -484,8 +491,8 @@ class FieldTextInput extends Field {
*/
onHtmlInputChange_(_e) {
const text = this.htmlInput_.value;
if (text !== this.htmlInput_.oldValue_) {
this.htmlInput_.oldValue_ = text;
if (text !== this.htmlInput_.getAttribute('data-old-value')) {
this.htmlInput_.setAttribute('data-old-value', text);
const value = this.getValueFromEditorText_(text);
this.setValue(value);

View File

@@ -55,7 +55,6 @@ goog.require('Blockly.Touch');
/** @suppress {extraRequire} */
goog.require('Blockly.blockRendering');
/**
* Class for a flyout.
* @abstract
@@ -585,9 +584,7 @@ class Flyout extends DeleteArea {
// Parse the Array, Node or NodeList into a a list of flyout items.
const parsedContent = toolbox.convertFlyoutDefToJsonArray(flyoutDef);
const flyoutInfo =
/** @type {{contents:!Array<!Object>, gaps:!Array<number>}} */ (
this.createFlyoutInfo_(parsedContent));
const flyoutInfo = this.createFlyoutInfo_(parsedContent);
this.layout_(flyoutInfo.contents, flyoutInfo.gaps);
@@ -629,8 +626,8 @@ class Flyout extends DeleteArea {
* the flyout.
* @param {!toolbox.FlyoutItemInfoArray} parsedContent The array
* of objects to show in the flyout.
* @return {{contents:Array<Object>, gaps:Array<number>}} The list of contents
* and gaps needed to lay out the flyout.
* @return {{contents:!Array<!FlyoutItem>, gaps:!Array<number>}} The
* list of contents and gaps needed to lay out the flyout.
* @private
*/
createFlyoutInfo_(parsedContent) {
@@ -1218,7 +1215,8 @@ Flyout.prototype.setMetrics_;
/**
* Lay out the blocks in the flyout.
* @param {!Array<!Object>} contents The blocks and buttons to lay out.
* @param {!Array<!FlyoutItem>} contents The blocks and buttons to lay
* out.
* @param {!Array<number>} gaps The visible gaps between blocks.
* @protected
*/
@@ -1226,7 +1224,7 @@ Flyout.prototype.layout_;
/**
* Scroll the flyout.
* @param {!Event} e Mouse wheel scroll event.
* @param {!WheelEvent} e Mouse wheel scroll event.
* @protected
*/
Flyout.prototype.wheel_;
@@ -1251,4 +1249,30 @@ Flyout.prototype.getX;
*/
Flyout.prototype.getY;
/**
* Scroll the flyout to the beginning of its contents.
*/
Flyout.prototype.scrollToStart;
/**
* The type of a flyout content item.
* @enum {string}
*/
Flyout.FlyoutItemType = {
BLOCK: 'block',
BUTTON: 'button',
};
/**
* A flyout content item.
* @typedef {{
* type: !Flyout.FlyoutItemType,
* button: (!FlyoutButton|undefined),
* block: (!BlockSvg|undefined),
* }}
*/
let FlyoutItem;
exports.FlyoutItem = FlyoutItem;
exports.Flyout = Flyout;

View File

@@ -24,6 +24,10 @@ const toolbox = goog.require('Blockly.utils.toolbox');
const {Coordinate} = goog.requireType('Blockly.utils.Coordinate');
const {Flyout} = goog.require('Blockly.Flyout');
/* eslint-disable-next-line no-unused-vars */
const {FlyoutItem} = goog.requireType('Blockly.Flyout');
/* eslint-disable-next-line no-unused-vars */
const {FlyoutButton} = goog.requireType('Blockly.FlyoutButton');
/* 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');
@@ -209,7 +213,7 @@ class HorizontalFlyout extends Flyout {
/**
* Scroll the flyout.
* @param {!Event} e Mouse wheel scroll event.
* @param {!WheelEvent} e Mouse wheel scroll event.
* @protected
*/
wheel_(e) {
@@ -237,7 +241,8 @@ class HorizontalFlyout extends Flyout {
/**
* Lay out the blocks in the flyout.
* @param {!Array<!Object>} contents The blocks and buttons to lay out.
* @param {!Array<!FlyoutItem>} contents The blocks and buttons to lay
* out.
* @param {!Array<number>} gaps The visible gaps between blocks.
* @protected
*/
@@ -279,8 +284,9 @@ class HorizontalFlyout extends Flyout {
this.addBlockListeners_(root, block, rect);
} else if (item.type === 'button') {
this.initFlyoutButton_(item.button, cursorX, cursorY);
cursorX += (item.button.width + gaps[i]);
const button = /** @type {!FlyoutButton} */ (item.button);
this.initFlyoutButton_(button, cursorX, cursorY);
cursorX += (button.width + gaps[i]);
}
}
}

View File

@@ -24,6 +24,10 @@ const toolbox = goog.require('Blockly.utils.toolbox');
const {Coordinate} = goog.requireType('Blockly.utils.Coordinate');
const {Flyout} = goog.require('Blockly.Flyout');
/* eslint-disable-next-line no-unused-vars */
const {FlyoutItem} = goog.requireType('Blockly.Flyout');
/* eslint-disable-next-line no-unused-vars */
const {FlyoutButton} = goog.requireType('Blockly.FlyoutButton');
/* 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');
@@ -195,7 +199,7 @@ class VerticalFlyout extends Flyout {
/**
* Scroll the flyout.
* @param {!Event} e Mouse wheel scroll event.
* @param {!WheelEvent} e Mouse wheel scroll event.
* @protected
*/
wheel_(e) {
@@ -222,7 +226,8 @@ class VerticalFlyout extends Flyout {
/**
* Lay out the blocks in the flyout.
* @param {!Array<!Object>} contents The blocks and buttons to lay out.
* @param {!Array<!FlyoutItem>} contents The blocks and buttons to lay
* out.
* @param {!Array<number>} gaps The visible gaps between blocks.
* @protected
*/
@@ -257,8 +262,9 @@ class VerticalFlyout extends Flyout {
cursorY += blockHW.height + gaps[i];
} else if (item.type === 'button') {
this.initFlyoutButton_(item.button, cursorX, cursorY);
cursorY += item.button.height + gaps[i];
const button = /** @type {!FlyoutButton} */ (item.button);
this.initFlyoutButton_(button, cursorX, cursorY);
cursorY += button.height + gaps[i];
}
}
}

View File

@@ -36,6 +36,16 @@ const {RenderedConnection} = goog.requireType('Blockly.RenderedConnection');
const {WorkspaceSvg} = goog.requireType('Blockly.WorkspaceSvg');
/**
* Represents a nearby valid connection.
* @typedef {{
* closest: ?RenderedConnection,
* local: ?RenderedConnection,
* radius: number,
* }}
*/
let CandidateConnection; // eslint-disable-line no-unused-vars
/**
* An error message to throw if the block created by createMarkerBlock_ is
* missing any components.
@@ -359,8 +369,9 @@ class InsertionMarkerManager {
/**
* Whether the previews (insertion marker and replacement marker) should be
* updated based on the closest candidate and the current drag distance.
* @param {!Object} candidate An object containing a local connection, a
* closest connection, and a radius. Returned by getCandidate_.
* @param {!CandidateConnection} candidate An object containing a local
* connection, a closest connection, and a radius. Returned by
* getCandidate_.
* @param {!Coordinate} dxy Position relative to drag start,
* in workspace units.
* @return {boolean} Whether the preview should be updated.
@@ -412,8 +423,8 @@ class InsertionMarkerManager {
* closest connection.
* @param {!Coordinate} dxy Position relative to drag start,
* in workspace units.
* @return {!Object} An object containing a local connection, a closest
* connection, and a radius.
* @return {!CandidateConnection} An object containing a local connection, a
* closest connection, and a radius.
* @private
*/
getCandidate_(dxy) {
@@ -465,9 +476,8 @@ class InsertionMarkerManager {
/**
* Whether ending the drag would delete the block.
* @param {!Object} candidate An object containing a local connection, a
* closest
* connection, and a radius.
* @param {!CandidateConnection} candidate An object containing a local
* connection, a closest connection, and a radius.
* @param {?IDragTarget} dragTarget The drag target that the block is
* currently over.
* @return {boolean} Whether dropping the block immediately would delete the
@@ -493,8 +503,8 @@ class InsertionMarkerManager {
* needed.
* At the beginning of this function, this.localConnection_ and
* this.closestConnection_ should both be null.
* @param {!Object} candidate An object containing a local connection, a
* closest connection, and a radius.
* @param {!CandidateConnection} candidate An object containing a local
* connection, a closest connection, and a radius.
* @private
*/
maybeShowPreview_(candidate) {
@@ -560,8 +570,8 @@ class InsertionMarkerManager {
* needed.
* At the end of this function, this.localConnection_ and
* this.closestConnection_ should both be null.
* @param {!Object} candidate An object containing a local connection, a
* closest connection, and a radius.
* @param {!CandidateConnection} candidate An object containing a local
* connection, a closest connection, and a radius.
* @private
*/
maybeHidePreview_(candidate) {

View File

@@ -151,4 +151,10 @@ IMetricsManager.prototype.getContentMetrics;
*/
IMetricsManager.prototype.getMetrics;
/**
* Returns common metrics used by UI elements.
* @return {!MetricsManager.UiMetrics} The UI metrics.
*/
IMetricsManager.prototype.getUiMetrics;
exports.IMetricsManager = IMetricsManager;

View File

@@ -514,7 +514,7 @@ class Mutator extends Icon {
const flyout = ws.getFlyout();
if (flyout) {
const flyoutBlocks = flyout.workspace_.getAllBlocks(false);
const flyoutBlocks = flyout.getWorkspace().getAllBlocks(false);
for (let i = 0, block; (block = flyoutBlocks[i]); i++) {
block.setStyle(block.getStyleName());
}

View File

@@ -33,6 +33,21 @@ const {Connection} = goog.require('Blockly.Connection');
const {Coordinate} = goog.require('Blockly.utils.Coordinate');
const {Svg} = goog.require('Blockly.utils.Svg');
/**
* A shape that has a pathDown property.
* @typedef {{
* pathDown: string,
* }}
*/
let PathDownShape; // eslint-disable-line no-unused-vars
/**
* A shape that has a pathLeft property.
* @typedef {{
* pathLeft: string,
* }}
*/
let PathLeftShape; // eslint-disable-line no-unused-vars
/**
* Maximum randomness in workspace units for bumping a block.
@@ -274,7 +289,7 @@ class RenderedConnection extends Connection {
* @param {number} maxLimit The maximum radius to another connection.
* @param {!Coordinate} dxy Offset between this connection's location
* in the database and the current location (as a result of dragging).
* @return {!{connection: ?Connection, radius: number}} Contains two
* @return {!{connection: ?RenderedConnection, radius: number}} Contains two
* properties: 'connection' which is either another connection or null,
* and 'radius' which is the distance.
*/
@@ -296,13 +311,15 @@ class RenderedConnection extends Connection {
// Vertical line, puzzle tab, vertical line.
const yLen = renderConstants.TAB_OFFSET_FROM_TOP;
steps = svgPaths.moveBy(0, -yLen) + svgPaths.lineOnAxis('v', yLen) +
shape.pathDown + svgPaths.lineOnAxis('v', yLen);
(/** @type {!PathDownShape} */ (shape)).pathDown +
svgPaths.lineOnAxis('v', yLen);
} else {
const xLen =
renderConstants.NOTCH_OFFSET_LEFT - renderConstants.CORNER_RADIUS;
// Horizontal line, notch, horizontal line.
steps = svgPaths.moveBy(-xLen, 0) + svgPaths.lineOnAxis('h', xLen) +
shape.pathLeft + svgPaths.lineOnAxis('h', xLen);
(/** @type {!PathLeftShape} */ (shape)).pathLeft +
svgPaths.lineOnAxis('h', xLen);
}
const xy = this.sourceBlock_.getRelativeToSurfaceXY();
const x = this.x - xy.x;

View File

@@ -28,6 +28,108 @@ const {Svg} = goog.require('Blockly.utils.Svg');
/* eslint-disable-next-line no-unused-vars */
const {Theme} = goog.requireType('Blockly.Theme');
/**
* An object containing sizing and path information about outside corners.
* @typedef {{
* topLeft: string,
* topRight: string,
* bottomRight: string,
* bottomLeft: string,
* rightHeight: number
* }}
*/
let OutsideCorners;
exports.OutsideCorners = OutsideCorners;
/**
* An object containing sizing and path information about inside corners.
* @typedef {{
* width: number,
* height: number,
* pathTop: string,
* pathBottom: string
* }}
*/
let InsideCorners;
exports.InsideCorners = InsideCorners;
/**
* An object containing sizing and path information about a start hat.
* @typedef {{
* height: number,
* width: number,
* path: string
* }}
*/
let StartHat;
exports.StartHat = StartHat;
/**
* An object containing sizing and path information about a notch.
* @typedef {{
* type: number,
* width: number,
* height: number,
* pathLeft: string,
* pathRight: string
* }}
*/
let Notch;
exports.Notch = Notch;
/**
* An object containing sizing and path information about a puzzle tab.
* @typedef {{
* type: number,
* width: number,
* height: number,
* pathDown: (string|function(number)),
* pathUp: (string|function(number))
* }}
*/
let PuzzleTab;
exports.PuzzleTab = PuzzleTab;
/**
* An object containing sizing and path information about collapsed block
* indicators.
* @typedef {{
* height: number,
* width: number,
* path: string
* }}
*/
let JaggedTeeth;
exports.JaggedTeeth = JaggedTeeth;
/**
* An object containing sizing and type information about a shape.
* @typedef {{
* type: number,
* width: number,
* height: number
* }}
*/
let Shape;
exports.Shape = Shape;
/**
* An object containing sizing and type information about a dynamic shape.
* @typedef {{
* type: number,
* width: (function(number)),
* height: (function(number)),
* isDynamic: boolean,
* connectionOffsetY: (function(number)),
* connectionOffsetX: (function(number)),
* pathDown: (function(number)),
* pathUp: (function(number)),
* pathRightDown: (function(number)),
* pathRightUp: (function(number)),
* }}
*/
let DynamicShape;
exports.DynamicShape = DynamicShape;
/**
* An object that provides constants for rendering blocks.
@@ -550,37 +652,37 @@ class ConstantProvider {
/**
* An object containing sizing and path information about collapsed block
* indicators.
* @type {!Object}
* @type {!JaggedTeeth}
*/
this.JAGGED_TEETH = this.makeJaggedTeeth();
/**
* An object containing sizing and path information about notches.
* @type {!Object}
* @type {!Notch}
*/
this.NOTCH = this.makeNotch();
/**
* An object containing sizing and path information about start hats
* @type {!Object}
* @type {!StartHat}
*/
this.START_HAT = this.makeStartHat();
/**
* An object containing sizing and path information about puzzle tabs.
* @type {!Object}
* @type {!PuzzleTab}
*/
this.PUZZLE_TAB = this.makePuzzleTab();
/**
* An object containing sizing and path information about inside corners
* @type {!Object}
* @type {!InsideCorners}
*/
this.INSIDE_CORNERS = this.makeInsideCorners();
/**
* An object containing sizing and path information about outside corners.
* @type {!Object}
* @type {!OutsideCorners}
*/
this.OUTSIDE_CORNERS = this.makeOutsideCorners();
}
@@ -777,8 +879,8 @@ class ConstantProvider {
}
/**
* @return {!Object} An object containing sizing and path information about
* collapsed block indicators.
* @return {!JaggedTeeth} An object containing sizing and path information
* about collapsed block indicators.
* @package
*/
makeJaggedTeeth() {
@@ -794,7 +896,7 @@ class ConstantProvider {
}
/**
* @return {!Object} An object containing sizing and path information about
* @return {!StartHat} An object containing sizing and path information about
* start hats.
* @package
*/
@@ -811,7 +913,7 @@ class ConstantProvider {
}
/**
* @return {!Object} An object containing sizing and path information about
* @return {!PuzzleTab} An object containing sizing and path information about
* puzzle tabs.
* @package
*/
@@ -868,7 +970,7 @@ class ConstantProvider {
}
/**
* @return {!Object} An object containing sizing and path information about
* @return {!Notch} An object containing sizing and path information about
* notches.
* @package
*/
@@ -904,8 +1006,8 @@ class ConstantProvider {
}
/**
* @return {!Object} An object containing sizing and path information about
* inside corners.
* @return {!InsideCorners} An object containing sizing and path information
* about inside corners.
* @package
*/
makeInsideCorners() {
@@ -926,8 +1028,8 @@ class ConstantProvider {
}
/**
* @return {!Object} An object containing sizing and path information about
* outside corners.
* @return {!OutsideCorners} An object containing sizing and path information
* about outside corners.
* @package
*/
makeOutsideCorners() {
@@ -974,7 +1076,7 @@ class ConstantProvider {
* type of the connection.
* @param {!RenderedConnection} connection The connection to find a
* shape object for
* @return {!Object} The shape object for the connection.
* @return {!Shape} The shape object for the connection.
* @package
*/
shapeFor(connection) {

View File

@@ -441,7 +441,7 @@ class Debug {
/**
* Configuration object containing booleans to enable and disable debug
* rendering of specific rendering components.
* @type {!Object<string, boolean>}
* @struct
*/
Debug.config = {
rowSpacers: true,

View File

@@ -21,7 +21,7 @@ const svgPaths = goog.require('Blockly.utils.svgPaths');
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
const {Connection} = goog.require('Blockly.blockRendering.Connection');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
const {ConstantProvider, Notch, PuzzleTab} = goog.requireType('Blockly.blockRendering.ConstantProvider');
/* eslint-disable-next-line no-unused-vars */
const {ExternalValueInput} = goog.requireType('Blockly.blockRendering.ExternalValueInput');
/* eslint-disable-next-line no-unused-vars */
@@ -31,6 +31,8 @@ const {Icon} = goog.requireType('Blockly.blockRendering.Icon');
/* eslint-disable-next-line no-unused-vars */
const {InlineInput} = goog.requireType('Blockly.blockRendering.InlineInput');
/* eslint-disable-next-line no-unused-vars */
const {PreviousConnection} = goog.requireType('Blockly.blockRendering.PreviousConnection');
/* eslint-disable-next-line no-unused-vars */
const {RenderInfo} = goog.requireType('Blockly.blockRendering.RenderInfo');
/* eslint-disable-next-line no-unused-vars */
const {Row} = goog.requireType('Blockly.blockRendering.Row');
@@ -152,7 +154,10 @@ class Drawer {
this.outlinePath_ += this.constants_.OUTSIDE_CORNERS.topRight;
} else if (
Types.isPreviousConnection(elem) && elem instanceof Connection) {
this.outlinePath_ += elem.shape.pathLeft;
this.outlinePath_ +=
(/** @type {!Notch} */ (
(/** @type {!PreviousConnection} */ (elem)).shape))
.pathLeft;
} else if (Types.isHat(elem)) {
this.outlinePath_ += this.constants_.START_HAT.path;
} else if (Types.isSpacer(elem)) {
@@ -182,11 +187,11 @@ class Drawer {
*/
drawValueInput_(row) {
const input =
/** @type {ExternalValueInput|InlineInput} */ (row.getLastInput());
/** @type {!ExternalValueInput|!InlineInput} */ (row.getLastInput());
this.positionExternalValueConnection_(row);
const pathDown = (typeof input.shape.pathDown === 'function') ?
input.shape.pathDown(input.height) :
(/** @type {function(number)} */ (input.shape.pathDown))(input.height) :
input.shape.pathDown;
this.outlinePath_ += svgPaths.lineOnAxis('H', input.xPos + input.width) +
@@ -204,7 +209,7 @@ class Drawer {
// Where to start drawing the notch, which is on the right side in LTR.
const x = input.xPos + input.notchOffset + input.shape.width;
const innerTopLeftCorner = input.shape.pathRight +
const innerTopLeftCorner = (/** @type {!Notch} */ (input.shape)).pathRight +
svgPaths.lineOnAxis(
'h', -(input.notchOffset - this.constants_.INSIDE_CORNERS.width)) +
this.constants_.INSIDE_CORNERS.pathTop;
@@ -244,7 +249,7 @@ class Drawer {
let outlinePath = '';
for (let i = elems.length - 1, elem; (elem = elems[i]); i--) {
if (Types.isNextConnection(elem) && elem instanceof Connection) {
outlinePath += elem.shape.pathRight;
outlinePath += (/** @type {!Notch} */ (elem.shape)).pathRight;
} else if (Types.isLeftSquareCorner(elem)) {
outlinePath += svgPaths.lineOnAxis('H', bottomRow.xPos);
} else if (Types.isLeftRoundedCorner(elem)) {
@@ -275,7 +280,8 @@ class Drawer {
const tabBottom =
outputConnection.connectionOffsetY + outputConnection.height;
const pathUp = (typeof outputConnection.shape.pathUp === 'function') ?
outputConnection.shape.pathUp(outputConnection.height) :
(/** @type {function(number)} */ (outputConnection.shape.pathUp))(
outputConnection.height) :
outputConnection.shape.pathUp;
// Draw a line up to the bottom of the tab.
@@ -363,7 +369,8 @@ class Drawer {
const connectionRight = input.xPos + input.connectionWidth;
this.inlinePath_ += svgPaths.moveTo(connectionRight, yPos) +
svgPaths.lineOnAxis('v', connectionTop) + input.shape.pathDown +
svgPaths.lineOnAxis('v', connectionTop) +
(/** @type {!PuzzleTab} */ (input.shape)).pathDown +
svgPaths.lineOnAxis('v', height - connectionBottom) +
svgPaths.lineOnAxis('h', width - input.connectionWidth) +
svgPaths.lineOnAxis('v', -height) + 'z';

View File

@@ -26,7 +26,7 @@ const {ConnectionType} = goog.require('Blockly.ConnectionType');
/* eslint-disable-next-line no-unused-vars */
const {Connection} = goog.requireType('Blockly.Connection');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
const {ConstantProvider, Notch, PuzzleTab} = goog.requireType('Blockly.blockRendering.ConstantProvider');
/* eslint-disable-next-line no-unused-vars */
const {Field} = goog.requireType('Blockly.Field');
/* eslint-disable-next-line no-unused-vars */
@@ -90,21 +90,21 @@ class MarkerSvg {
/**
* The workspace, field, or block that the marker SVG element should be
* attached to.
* @type {IASTNodeLocationSvg}
* @type {?IASTNodeLocationSvg}
* @private
*/
this.parent_ = null;
/**
* The constants necessary to draw the marker.
* @type {ConstantProvider}
* @type {!ConstantProvider}
* @protected
*/
this.constants_ = constants;
/**
* The current SVG element for the marker.
* @type {Element}
* @type {?Element}
*/
this.currentMarkerSvg = null;
@@ -119,7 +119,7 @@ class MarkerSvg {
/**
* The root SVG group containing the marker.
* @type {SVGGElement}
* @type {?SVGGElement}
* @protected
*/
this.markerSvg_ = null;
@@ -240,7 +240,7 @@ class MarkerSvg {
// Ensures the marker will be visible immediately after the move.
const animate = this.currentMarkerSvg.childNodes[0];
if (animate !== undefined) {
animate.beginElement && animate.beginElement();
animate instanceof SVGAnimationElement && animate.beginElement();
}
}
@@ -291,11 +291,13 @@ class MarkerSvg {
if (block.previousConnection) {
const connectionShape =
this.constants_.shapeFor(block.previousConnection);
/** @type {!Notch|!PuzzleTab} */ (
this.constants_.shapeFor(block.previousConnection));
this.positionPrevious_(
width, markerOffset, markerHeight, connectionShape);
} else if (block.outputConnection) {
const connectionShape = this.constants_.shapeFor(block.outputConnection);
const connectionShape = /** @type {!Notch|!PuzzleTab} */ (
this.constants_.shapeFor(block.outputConnection));
this.positionOutput_(width, height, connectionShape);
} else {
this.positionBlock_(width, markerOffset, markerHeight);
@@ -358,7 +360,7 @@ class MarkerSvg {
* @protected
*/
showWithField_(curNode) {
const field = /** @type {Field} */ (curNode.getLocation());
const field = /** @type {!Field} */ (curNode.getLocation());
const width = field.getSize().width;
const height = field.getSize().height;
@@ -374,7 +376,7 @@ class MarkerSvg {
* @protected
*/
showWithInput_(curNode) {
const connection = /** @type {RenderedConnection} */
const connection = /** @type {!RenderedConnection} */
(curNode.getLocation());
const sourceBlock = /** @type {!BlockSvg} */ (connection.getSourceBlock());
@@ -393,7 +395,7 @@ class MarkerSvg {
const connection =
/** @type {!RenderedConnection} */ (curNode.getLocation());
const targetBlock =
/** @type {BlockSvg} */ (connection.getSourceBlock());
/** @type {!BlockSvg} */ (connection.getSourceBlock());
let x = 0;
const y = connection.getOffsetInBlock().y;
const width = targetBlock.getHeightWidth().width;
@@ -412,7 +414,7 @@ class MarkerSvg {
* @protected
*/
showWithStack_(curNode) {
const block = /** @type {BlockSvg} */ (curNode.getLocation());
const block = /** @type {!BlockSvg} */ (curNode.getLocation());
// Gets the height and width of entire stack.
const heightWidth = block.getHeightWidth();
@@ -482,8 +484,9 @@ class MarkerSvg {
const x = connection.getOffsetInBlock().x;
const y = connection.getOffsetInBlock().y;
const path =
svgPaths.moveTo(0, 0) + this.constants_.shapeFor(connection).pathDown;
const path = svgPaths.moveTo(0, 0) +
(/** @type {!PuzzleTab} */ (this.constants_.shapeFor(connection)))
.pathDown;
this.markerInput_.setAttribute('d', path);
this.markerInput_.setAttribute(
@@ -513,7 +516,8 @@ class MarkerSvg {
* Displays a puzzle outline and the top and bottom path.
* @param {number} width The width of the block.
* @param {number} height The height of the block.
* @param {!Object} connectionShape The shape object for the connection.
* @param {!Notch|!PuzzleTab} connectionShape The shape object for the
* connection.
* @protected
*/
positionOutput_(width, height, connectionShape) {
@@ -537,7 +541,8 @@ class MarkerSvg {
* @param {number} markerOffset The offset of the marker from around the
* block.
* @param {number} markerHeight The height of the marker.
* @param {!Object} connectionShape The shape object for the connection.
* @param {!Notch|!PuzzleTab} connectionShape The shape object for the
* connection.
* @protected
*/
positionPrevious_(width, markerOffset, markerHeight, connectionShape) {
@@ -702,9 +707,9 @@ class MarkerSvg {
if (this.isCursor()) {
const values = this.colour_ + ';transparent;transparent;';
this.markerSvgLine_.firstChild.setAttribute('values', values);
this.markerInput_.firstChild.setAttribute('values', values);
this.markerBlock_.firstChild.setAttribute('values', values);
this.markerSvgLine_.firstElementChild.setAttribute('values', values);
this.markerInput_.firstElementChild.setAttribute('values', values);
this.markerBlock_.firstElementChild.setAttribute('values', values);
}
}

View File

@@ -19,6 +19,70 @@ const svgPaths = goog.require('Blockly.utils.svgPaths');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
/**
* An object containing sizing and path information about an outside corner.
* @typedef {{
* height: number,
* topLeft: (function(boolean)),
* bottomLeft: (function()),
* }}
*/
let OutsideCorner;
exports.OutsideCorner = OutsideCorner;
/**
* An object containing sizing and path information about an inside corner.
* @typedef {{
* width: number,
* height: number,
* pathTop: (function(boolean)),
* pathBottom: (function(boolean))
* }}
*/
let InsideCorner;
exports.InsideCorner = InsideCorner;
/**
* An object containing sizing and path information about a start hat.
* @typedef {{
* path: (function(boolean))
* }}
*/
let StartHat;
exports.StartHat = StartHat;
/**
* An object containing sizing and path information about a notch.
* @typedef {{
* pathLeft: string
* }}
*/
let Notch;
exports.Notch = Notch;
/**
* An object containing sizing and path information about a puzzle tab.
* @typedef {{
* width: number,
* height: number,
* pathDown: (function(boolean)),
* pathUp: (function(boolean))
* }}
*/
let PuzzleTab;
exports.PuzzleTab = PuzzleTab;
/**
* An object containing sizing and path information about collapsed block
* indicators.
* @typedef {{
* height: number,
* width: number,
* pathLeft: string
* }}
*/
let JaggedTeeth;
exports.JaggedTeeth = JaggedTeeth;
/**
* An object that provides constants for rendering highlights on blocks.
@@ -62,48 +126,48 @@ class HighlightConstantProvider {
/**
* An object containing sizing and path information about inside corner
* highlights.
* @type {!Object}
* @type {!InsideCorner}
*/
this.INSIDE_CORNER = this.makeInsideCorner();
/**
* An object containing sizing and path information about outside corner
* highlights.
* @type {!Object}
* @type {!OutsideCorner}
*/
this.OUTSIDE_CORNER = this.makeOutsideCorner();
/**
* An object containing sizing and path information about puzzle tab
* highlights.
* @type {!Object}
* @type {!PuzzleTab}
*/
this.PUZZLE_TAB = this.makePuzzleTab();
/**
* An object containing sizing and path information about notch highlights.
* @type {!Object}
* @type {!Notch}
*/
this.NOTCH = this.makeNotch();
/**
* An object containing sizing and path information about highlights for
* collapsed block indicators.
* @type {!Object}
* @type {!JaggedTeeth}
*/
this.JAGGED_TEETH = this.makeJaggedTeeth();
/**
* An object containing sizing and path information about start hat
* highlights.
* @type {!Object}
* @type {!StartHat}
*/
this.START_HAT = this.makeStartHat();
}
/**
* @return {!Object} An object containing sizing and path information about
* inside corner highlights.
* @return {!InsideCorner} An object containing sizing and path information
* about inside corner highlights.
* @package
*/
makeInsideCorner() {
@@ -147,8 +211,8 @@ class HighlightConstantProvider {
}
/**
* @return {!Object} An object containing sizing and path information about
* outside corner highlights.
* @return {!OutsideCorner} An object containing sizing and path information
* about outside corner highlights.
* @package
*/
makeOutsideCorner() {
@@ -198,7 +262,7 @@ class HighlightConstantProvider {
}
/**
* @return {!Object} An object containing sizing and path information about
* @return {!PuzzleTab} An object containing sizing and path information about
* puzzle tab highlights.
* @package
*/
@@ -248,7 +312,7 @@ class HighlightConstantProvider {
}
/**
* @return {!Object} An object containing sizing and path information about
* @return {!Notch} An object containing sizing and path information about
* notch highlights.
* @package
*/
@@ -260,8 +324,8 @@ class HighlightConstantProvider {
}
/**
* @return {!Object} An object containing sizing and path information about
* collapsed block edge highlights.
* @return {!JaggedTeeth} An object containing sizing and path information
* about collapsed block edge highlights.
* @package
*/
makeJaggedTeeth() {
@@ -271,7 +335,7 @@ class HighlightConstantProvider {
}
/**
* @return {!Object} An object containing sizing and path information about
* @return {!StartHat} An object containing sizing and path information about
* start highlights.
* @package
*/

View File

@@ -17,13 +17,12 @@
goog.module('Blockly.blockRendering.Connection');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
const {ConstantProvider, Shape} = goog.requireType('Blockly.blockRendering.ConstantProvider');
const {Measurable} = goog.require('Blockly.blockRendering.Measurable');
/* eslint-disable-next-line no-unused-vars */
const {RenderedConnection} = goog.requireType('Blockly.RenderedConnection');
const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* The base class to represent a connection and the space that it takes up on
* the block.
@@ -44,7 +43,7 @@ class Connection extends Measurable {
/** @type {!RenderedConnection} */
this.connectionModel = connectionModel;
/** @type {!Object} */
/** @type {!Shape} */
this.shape = this.constants_.shapeFor(connectionModel);
/** @type {boolean} */

View File

@@ -17,7 +17,7 @@
goog.module('Blockly.blockRendering.InlineInput');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
const {ConstantProvider, DynamicShape} = goog.requireType('Blockly.blockRendering.ConstantProvider');
const {InputConnection} = goog.require('Blockly.blockRendering.InputConnection');
/* eslint-disable-next-line no-unused-vars */
const {Input} = goog.requireType('Blockly.Input');
@@ -56,23 +56,26 @@ class InlineInput extends InputConnection {
/** @type {number} */
this.connectionHeight = !this.isDynamicShape ?
this.shape.height :
this.shape.height(this.height);
(/** @type {!DynamicShape} */ (this.shape)).height(this.height);
/** @type {number} */
this.connectionWidth =
!this.isDynamicShape ? this.shape.width : this.shape.width(this.height);
this.connectionWidth = !this.isDynamicShape ?
this.shape.width :
(/** @type {!DynamicShape} */ (this.shape)).width(this.height);
if (!this.connectedBlock) {
this.width += this.connectionWidth * (this.isDynamicShape ? 2 : 1);
}
/** @type {number} */
this.connectionOffsetY = this.isDynamicShape ?
this.shape.connectionOffsetY(this.connectionHeight) :
(/** @type {!DynamicShape} */ (this.shape))
.connectionOffsetY(this.connectionHeight) :
this.constants_.TAB_OFFSET_FROM_TOP;
/** @type {number} */
this.connectionOffsetX = this.isDynamicShape ?
this.shape.connectionOffsetX(this.connectionWidth) :
(/** @type {!DynamicShape} */ (this.shape))
.connectionOffsetX(this.connectionWidth) :
0;
}
}

View File

@@ -21,9 +21,26 @@ const dom = goog.require('Blockly.utils.dom');
const svgPaths = goog.require('Blockly.utils.svgPaths');
const utilsColour = goog.require('Blockly.utils.colour');
const {ConnectionType} = goog.require('Blockly.ConnectionType');
const {ConstantProvider: BaseConstantProvider} = goog.require('Blockly.blockRendering.ConstantProvider');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider: BaseConstantProvider, DynamicShape, Shape} = goog.require('Blockly.blockRendering.ConstantProvider');
const {Svg} = goog.require('Blockly.utils.Svg');
/**
* An object containing sizing and path information about inside corners.
* @typedef {{
* width: number,
* height: number,
* pathTop: string,
* pathBottom: string,
* rightWidth: number,
* rightHeight: number,
* pathTopRight: string,
* pathBottomRight: string
* }}
*/
let InsideCorners;
exports.InsideCorners = InsideCorners;
/**
* An object that provides constants for rendering blocks in Zelos mode.
@@ -389,21 +406,21 @@ class ConstantProvider extends BaseConstantProvider {
/**
* The object containing information about the hexagon used for a boolean
* reporter block. Null before init is called.
* @type {Object}
* @type {?DynamicShape}
*/
this.HEXAGONAL = null;
/**
* The object containing information about the hexagon used for a number or
* string reporter block. Null before init is called.
* @type {Object}
* @type {?DynamicShape}
*/
this.ROUNDED = null;
/**
* The object containing information about the hexagon used for a
* rectangular reporter block. Null before init is called.
* @type {Object}
* @type {?DynamicShape}
*/
this.SQUARED = null;
}
@@ -428,8 +445,8 @@ class ConstantProvider extends BaseConstantProvider {
this.ROUNDED = this.makeRounded();
this.SQUARED = this.makeSquared();
this.STATEMENT_INPUT_NOTCH_OFFSET =
this.NOTCH_OFFSET_LEFT + this.INSIDE_CORNERS.rightWidth;
this.STATEMENT_INPUT_NOTCH_OFFSET = this.NOTCH_OFFSET_LEFT +
(/** @type {InsideCorners} */ (this.INSIDE_CORNERS)).rightWidth;
}
/**
@@ -486,8 +503,8 @@ class ConstantProvider extends BaseConstantProvider {
/**
* Create sizing and path information about a hexagonal shape.
* @return {!Object} An object containing sizing and path information about
* a hexagonal shape for connections.
* @return {!DynamicShape} An object containing sizing and path information
* about a hexagonal shape for connections.
* @package
*/
makeHexagonal() {
@@ -549,8 +566,8 @@ class ConstantProvider extends BaseConstantProvider {
/**
* Create sizing and path information about a rounded shape.
* @return {!Object} An object containing sizing and path information about
* a rounded shape for connections.
* @return {!DynamicShape} An object containing sizing and path information
* about a rounded shape for connections.
* @package
*/
makeRounded() {
@@ -620,8 +637,8 @@ class ConstantProvider extends BaseConstantProvider {
/**
* Create sizing and path information about a squared shape.
* @return {!Object} An object containing sizing and path information about
* a squared shape for connections.
* @return {!DynamicShape} An object containing sizing and path information
* about a squared shape for connections.
* @package
*/
makeSquared() {
@@ -700,24 +717,24 @@ class ConstantProvider extends BaseConstantProvider {
if (outputShape !== null) {
switch (outputShape) {
case this.SHAPES.HEXAGONAL:
return /** @type {!Object} */ (this.HEXAGONAL);
return /** @type {!Shape} */ (this.HEXAGONAL);
case this.SHAPES.ROUND:
return /** @type {!Object} */ (this.ROUNDED);
return /** @type {!Shape} */ (this.ROUNDED);
case this.SHAPES.SQUARE:
return /** @type {!Object} */ (this.SQUARED);
return /** @type {!Shape} */ (this.SQUARED);
}
}
// Includes doesn't work in IE.
if (checks && checks.indexOf('Boolean') !== -1) {
return /** @type {!Object} */ (this.HEXAGONAL);
return /** @type {!Shape} */ (this.HEXAGONAL);
}
if (checks && checks.indexOf('Number') !== -1) {
return /** @type {!Object} */ (this.ROUNDED);
return /** @type {!Shape} */ (this.ROUNDED);
}
if (checks && checks.indexOf('String') !== -1) {
return /** @type {!Object} */ (this.ROUNDED);
return /** @type {!Shape} */ (this.ROUNDED);
}
return /** @type {!Object} */ (this.ROUNDED);
return /** @type {!Shape} */ (this.ROUNDED);
case ConnectionType.PREVIOUS_STATEMENT:
case ConnectionType.NEXT_STATEMENT:
return this.NOTCH;

View File

@@ -30,6 +30,10 @@ const {Row} = goog.requireType('Blockly.blockRendering.Row');
const {SpacerRow} = goog.requireType('Blockly.blockRendering.SpacerRow');
/* eslint-disable-next-line no-unused-vars */
const {StatementInput} = goog.requireType('Blockly.zelos.StatementInput');
/* eslint-disable-next-line no-unused-vars */
const {InsideCorners} = goog.requireType('Blockly.zelos.ConstantProvider');
/* eslint-disable-next-line no-unused-vars */
const {DynamicShape, Notch} = goog.requireType('Blockly.blockRendering.ConstantProvider');
const {Types} = goog.require('Blockly.blockRendering.Types');
@@ -124,19 +128,23 @@ class Drawer extends BaseDrawer {
if (Types.isSpacer(row)) {
const spacerRow = /** @type {!SpacerRow} */ (row);
if (spacerRow.precedesStatement || spacerRow.followsStatement) {
const cornerHeight = this.constants_.INSIDE_CORNERS.rightHeight;
const cornerHeight =
(/** @type {!InsideCorners} */ (this.constants_.INSIDE_CORNERS))
.rightHeight;
const remainingHeight =
spacerRow.height - (spacerRow.precedesStatement ? cornerHeight : 0);
this.outlinePath_ +=
(spacerRow.followsStatement ?
this.constants_.INSIDE_CORNERS.pathBottomRight :
'') +
(spacerRow.followsStatement ? (/** @type {!InsideCorners} */ (
this.constants_.INSIDE_CORNERS))
.pathBottomRight :
'') +
(remainingHeight > 0 ?
svgPaths.lineOnAxis('V', spacerRow.yPos + remainingHeight) :
'') +
(spacerRow.precedesStatement ?
this.constants_.INSIDE_CORNERS.pathTopRight :
'');
(spacerRow.precedesStatement ? (/** @type {!InsideCorners} */ (
this.constants_.INSIDE_CORNERS))
.pathTopRight :
'');
return;
}
}
@@ -148,8 +156,9 @@ class Drawer extends BaseDrawer {
* @protected
*/
drawRightDynamicConnection_() {
this.outlinePath_ += this.info_.outputConnection.shape.pathRightDown(
this.info_.outputConnection.height);
this.outlinePath_ +=
(/** @type {!DynamicShape} */ (this.info_.outputConnection.shape))
.pathRightDown(this.info_.outputConnection.height);
}
/**
@@ -159,8 +168,9 @@ class Drawer extends BaseDrawer {
drawLeftDynamicConnection_() {
this.positionOutputConnection_();
this.outlinePath_ += this.info_.outputConnection.shape.pathUp(
this.info_.outputConnection.height);
this.outlinePath_ +=
(/** @type {!DynamicShape} */ (this.info_.outputConnection.shape))
.pathUp(this.info_.outputConnection.height);
// Close off the path. This draws a vertical line up to the start of the
// block's path, which may be either a rounded or a sharp corner.
@@ -212,9 +222,10 @@ class Drawer extends BaseDrawer {
const outlinePath = svgPaths.moveTo(connectionRight, yPos) +
svgPaths.lineOnAxis('h', width) +
input.shape.pathRightDown(input.height) +
svgPaths.lineOnAxis('h', -width) + input.shape.pathUp(input.height) +
'z';
(/** @type {!DynamicShape} */ (input.shape))
.pathRightDown(input.height) +
svgPaths.lineOnAxis('h', -width) +
(/** @type {!DynamicShape} */ (input.shape)).pathUp(input.height) + 'z';
this.block_.pathObject.setOutlinePath(inputName, outlinePath);
}
@@ -226,7 +237,7 @@ class Drawer extends BaseDrawer {
// Where to start drawing the notch, which is on the right side in LTR.
const x = input.xPos + input.notchOffset + input.shape.width;
const innerTopLeftCorner = input.shape.pathRight +
const innerTopLeftCorner = (/** @type {!Notch} */ (input.shape)).pathRight +
svgPaths.lineOnAxis(
'h', -(input.notchOffset - this.constants_.INSIDE_CORNERS.width)) +
this.constants_.INSIDE_CORNERS.pathTop;
@@ -237,7 +248,9 @@ class Drawer extends BaseDrawer {
const innerBottomLeftCorner = this.constants_.INSIDE_CORNERS.pathBottom +
svgPaths.lineOnAxis(
'h', (input.notchOffset - this.constants_.INSIDE_CORNERS.width)) +
(input.connectedBottomNextConnection ? '' : input.shape.pathLeft);
(input.connectedBottomNextConnection ?
'' :
(/** @type {!Notch} */ (input.shape)).pathLeft);
this.outlinePath_ += svgPaths.lineOnAxis('H', x) + innerTopLeftCorner +
svgPaths.lineOnAxis('v', innerHeight) + innerBottomLeftCorner +

View File

@@ -21,7 +21,9 @@ const {Align} = goog.require('Blockly.Input');
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
const {BottomRow} = goog.require('Blockly.zelos.BottomRow');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.zelos.ConstantProvider');
const {ConstantProvider, InsideCorners} = goog.requireType('Blockly.zelos.ConstantProvider');
/* eslint-disable-next-line no-unused-vars */
const {DynamicShape} = goog.requireType('Blockly.blockRendering.ConstantProvider');
const {Field} = goog.require('Blockly.blockRendering.Field');
const {FieldImage} = goog.require('Blockly.FieldImage');
const {FieldLabel} = goog.require('Blockly.FieldLabel');
@@ -101,7 +103,7 @@ class RenderInfo extends BaseRenderInfo {
/**
* An object with rendering information about the right connection shape.
* @type {RightConnectionShape}
* @type {?RightConnectionShape}
*/
this.rightSide = this.outputConnection ?
new RightConnectionShape(this.constants_) :
@@ -165,7 +167,10 @@ class RenderInfo extends BaseRenderInfo {
*/
getDesiredRowWidth_(row) {
if (row.hasStatement) {
const rightCornerWidth = this.constants_.INSIDE_CORNERS.rightWidth || 0;
const rightCornerWidth =
(/** @type {!InsideCorners} */ (this.constants_.INSIDE_CORNERS))
.rightWidth ||
0;
return this.width - this.startX - rightCornerWidth;
}
return super.getDesiredRowWidth_(row);
@@ -213,7 +218,10 @@ class RenderInfo extends BaseRenderInfo {
const followsStatement = Types.isInputRow(prev) && prev.hasStatement;
const precedesStatement = Types.isInputRow(next) && next.hasStatement;
if (precedesStatement || followsStatement) {
const cornerHeight = this.constants_.INSIDE_CORNERS.rightHeight || 0;
const cornerHeight =
(/** @type {!InsideCorners} */ (this.constants_.INSIDE_CORNERS))
.rightHeight ||
0;
const height = Math.max(this.constants_.NOTCH_HEIGHT, cornerHeight);
return precedesStatement && followsStatement ?
Math.max(height, this.constants_.DUMMY_INPUT_MIN_HEIGHT) :
@@ -403,16 +411,22 @@ class RenderInfo extends BaseRenderInfo {
const blockHeight = this.bottomRow.hasNextConnection ?
this.height - this.bottomRow.descenderHeight :
this.height;
const connectionHeight = this.outputConnection.shape.height(blockHeight);
const connectionWidth = this.outputConnection.shape.width(blockHeight);
const connectionHeight =
(/** @type {!DynamicShape} */ (this.outputConnection.shape))
.height(blockHeight);
const connectionWidth =
(/** @type {!DynamicShape} */ (this.outputConnection.shape))
.width(blockHeight);
this.outputConnection.height = connectionHeight;
this.outputConnection.width = connectionWidth;
this.outputConnection.startX = connectionWidth;
this.outputConnection.connectionOffsetY =
this.outputConnection.shape.connectionOffsetY(connectionHeight);
(/** @type {!DynamicShape} */ (this.outputConnection.shape))
.connectionOffsetY(connectionHeight);
this.outputConnection.connectionOffsetX =
this.outputConnection.shape.connectionOffsetX(connectionWidth);
(/** @type {!DynamicShape} */ (this.outputConnection.shape))
.connectionOffsetX(connectionWidth);
// Add the right connection measurable.
// Don't add it if we have a value-to-statement or a value-to-stack block.

View File

@@ -171,7 +171,7 @@ class MarkerSvg extends BaseMarkerSvg {
if (this.isCursor()) {
const values = this.colour_ + ';transparent;transparent;';
this.markerCircle_.firstChild.setAttribute('values', values);
this.markerCircle_.firstElementChild.setAttribute('values', values);
}
}
}

View File

@@ -83,10 +83,10 @@ class Scrollbar {
this.oldHostMetrics_ = null;
/**
* The ratio of handle position offset to workspace content displacement.
* @type {?number}
* @type {number}
* @package
*/
this.ratio = null;
this.ratio = 1;
/**
* The location of the origin of the workspace that the scrollbar is in,

View File

@@ -209,7 +209,7 @@ class ShortcutRegistry {
* Handles key down events.
* @param {!Workspace} workspace The main workspace where the event was
* captured.
* @param {!Event} e The key down event.
* @param {!KeyboardEvent} e The key down event.
* @return {boolean} True if the event was handled, false otherwise.
* @public
*/
@@ -264,7 +264,7 @@ class ShortcutRegistry {
/**
* Serializes a key event.
* @param {!Event} e A key down event.
* @param {!KeyboardEvent} e A key down event.
* @return {string} The serialized key code for the given event.
* @private
*/

View File

@@ -20,7 +20,6 @@ goog.module('Blockly.sprite');
/**
* Contains the path to a single png tat holds the images for the trashcan
* as well as the zoom controls.
* @const {!Object}
* @alias Blockly.sprite.SPRITE
*/
const SPRITE = {

View File

@@ -506,7 +506,7 @@ class ToolboxCategory extends ToolboxItem {
let category = this;
while (category.getParent()) {
category = category.getParent();
if (!category.isExpanded()) {
if (!(/** @type {ICollapsibleToolboxItem} */ (category)).isExpanded()) {
return false;
}
}

View File

@@ -323,12 +323,13 @@ class Toolbox extends DeleteArea {
/** @type {!WorkspaceSvg} */ (common.getMainWorkspace()).hideChaff(false);
} else {
const targetElement = e.target;
const itemId = targetElement.getAttribute('id');
const itemId =
(/** @type {!Element} */ (targetElement)).getAttribute('id');
if (itemId) {
const item = this.getToolboxItemById(itemId);
if (item.isSelectable()) {
this.setSelectedItem(item);
item.onClick(e);
(/** @type {!ISelectableToolboxItem} */ (item)).onClick(e);
}
}
// Just close popups.
@@ -1012,10 +1013,12 @@ class Toolbox extends DeleteArea {
return false;
}
if (this.selectedItem_.isCollapsible() && this.selectedItem_.isExpanded()) {
if (this.selectedItem_.isCollapsible() &&
(/** @type {!ICollapsibleToolboxItem} */ (this.selectedItem_))
.isExpanded()) {
const collapsibleItem =
/** @type {!ICollapsibleToolboxItem} */ (this.selectedItem_);
collapsibleItem.setExpanded(false);
collapsibleItem.toggleExpanded();
return true;
} else if (
this.selectedItem_.getParent() &&
@@ -1039,7 +1042,7 @@ class Toolbox extends DeleteArea {
const collapsibleItem = /** @type {ICollapsibleToolboxItem} */
(this.selectedItem_);
if (!collapsibleItem.isExpanded()) {
collapsibleItem.setExpanded(true);
collapsibleItem.toggleExpanded();
return true;
} else {
this.selectNext_();

View File

@@ -128,7 +128,7 @@ class ToolboxItem {
/**
* Gets the parent if the toolbox item is nested.
* @return {?IToolboxItem} The parent toolbox item, or null if
* @return {?ICollapsibleToolboxItem} The parent toolbox item, or null if
* this toolbox item is not nested.
* @public
*/

View File

@@ -152,7 +152,7 @@ exports.isRightButton = isRightButton;
* Returns the converted coordinates of the given mouse event.
* The origin (0,0) is the top-left corner of the Blockly SVG.
* @param {!Event} e Mouse event.
* @param {!Element} svg SVG element.
* @param {!SVGSVGElement} svg SVG element.
* @param {?SVGMatrix} matrix Inverted screen CTM to use.
* @return {!SVGPoint} Object with .x and .y properties.
* @deprecated Use Blockly.browserEvents.mouseToSvg instead;
@@ -168,7 +168,7 @@ exports.mouseToSvg = mouseToSvg;
/**
* Returns the scroll delta of a mouse event in pixel units.
* @param {!Event} e Mouse event.
* @param {!WheelEvent} e Mouse event.
* @return {{x: number, y: number}} Scroll delta object with .x and .y
* properties.
* @deprecated Use Blockly.browserEvents.getScrollDeltaPixels instead.

View File

@@ -280,7 +280,7 @@ exports.stopTextWidthCache = stopTextWidthCache;
/**
* Gets the width of a text element, caching it in the process.
* @param {!Element} textElement An SVG 'text' element.
* @param {!SVGTextElement} textElement An SVG 'text' element.
* @return {number} Width of element.
* @alias Blockly.utils.dom.getTextWidth
*/
@@ -366,14 +366,16 @@ const getFastTextWidthWithSizeString = function(
if (!canvasContext) {
// Inject the canvas element used for computing text widths.
const computeCanvas = document.createElement('canvas');
const computeCanvas =
/** @type {!HTMLCanvasElement} */ (document.createElement('canvas'));
computeCanvas.className = 'blocklyComputeCanvas';
document.body.appendChild(computeCanvas);
// Initialize the HTML canvas context and set the font.
// The context font must match blocklyText's fontsize and font-family
// set in CSS.
canvasContext = computeCanvas.getContext('2d');
canvasContext = /** @type {!CanvasRenderingContext2D} */ (
computeCanvas.getContext('2d'));
}
// Set the desired font size and family.
canvasContext.font = fontWeight + ' ' + fontSize + ' ' + fontFamily;
@@ -399,7 +401,7 @@ exports.getFastTextWidthWithSizeString = getFastTextWidthWithSizeString;
* @alias Blockly.utils.dom.measureFontMetrics
*/
const measureFontMetrics = function(text, fontSize, fontWeight, fontFamily) {
const span = document.createElement('span');
const span = /** @type {!HTMLSpanElement} */ (document.createElement('span'));
span.style.font = fontWeight + ' ' + fontSize + ' ' + fontFamily;
span.textContent = text;

View File

@@ -20,6 +20,7 @@
goog.module('Blockly.utils.style');
const {Coordinate} = goog.require('Blockly.utils.Coordinate');
const {Rect} = goog.require('Blockly.utils.Rect');
const {Size} = goog.require('Blockly.utils.Size');
@@ -203,21 +204,16 @@ exports.isRightToLeft = isRightToLeft;
* Gets the computed border widths (on all sides) in pixels
* Copied from Closure's goog.style.getBorderBox
* @param {!Element} element The element to get the border widths for.
* @return {!Object} The computed border widths.
* @return {!Rect} The computed border widths.
* @alias Blockly.utils.style.getBorderBox
*/
const getBorderBox = function(element) {
const left = getComputedStyle(element, 'borderLeftWidth');
const right = getComputedStyle(element, 'borderRightWidth');
const top = getComputedStyle(element, 'borderTopWidth');
const bottom = getComputedStyle(element, 'borderBottomWidth');
const left = parseFloat(getComputedStyle(element, 'borderLeftWidth'));
const right = parseFloat(getComputedStyle(element, 'borderRightWidth'));
const top = parseFloat(getComputedStyle(element, 'borderTopWidth'));
const bottom = parseFloat(getComputedStyle(element, 'borderBottomWidth'));
return {
top: parseFloat(top),
right: parseFloat(right),
bottom: parseFloat(bottom),
left: parseFloat(left),
};
return new Rect(top, bottom, left, right);
};
exports.getBorderBox = getBorderBox;

View File

@@ -257,7 +257,9 @@ const svgSize = function(svg) {
'Blockly.svgSize', 'March 2021', 'March 2022',
'workspace.getCachedParentSvgSize');
svg = /** @type {?} */ (svg);
return new Size(svg.cachedWidth_, svg.cachedHeight_);
return new Size(
Number(svg.getAttribute('data-cached-width')),
Number(svg.getAttribute('data-cached-height')));
};
exports.svgSize = svgSize;

View File

@@ -427,9 +427,10 @@ const addAttributes = function(node, obj) {
/**
* Parse the provided toolbox tree into a consistent DOM format.
* @param {?Node|?string} toolboxDef DOM tree of blocks, or text representation
* @param {?Element|?string} toolboxDef DOM tree of blocks, or text
* representation
* of same.
* @return {?Node} DOM tree of blocks, or null.
* @return {?Element} DOM tree of blocks, or null.
* @alias Blockly.utils.toolbox.parseToolboxTree
*/
const parseToolboxTree = function(toolboxDef) {

View File

@@ -144,7 +144,8 @@ class WorkspaceAudio {
if (sound) {
// Don't play one sound on top of another.
const now = new Date;
if (this.lastSound_ !== null && now - this.lastSound_ < SOUND_LIMIT) {
if (this.lastSound_ !== null &&
now.getTime() - this.lastSound_.getTime() < SOUND_LIMIT) {
return;
}
this.lastSound_ = now;

View File

@@ -366,8 +366,9 @@ class WorkspaceComment {
/**
* Decode an XML comment tag and return the results in an object.
* @param {!Element} xml XML comment element.
* @return {{w: number, h: number, x: number, y: number, content: string}} An
* object containing the id, size, position, and comment string.
* @return {{id: string, w: number, h: number, x: number, y: number, content:
* string}} An object containing the id, size, position, and comment
* string.
* @package
*/
static parseAttributes(xml) {

View File

@@ -114,7 +114,7 @@ class WorkspaceCommentSvg extends WorkspaceComment {
this.eventsInit_ = false;
/**
* @type {?Element}
* @type {?HTMLTextAreaElement}
* @private
*/
this.textarea_ = null;
@@ -174,7 +174,7 @@ class WorkspaceCommentSvg extends WorkspaceComment {
*/
this.svgGroup_ =
dom.createSvgElement(Svg.G, {'class': 'blocklyComment'}, null);
this.svgGroup_.translate_ = '';
(/** @type {?} */ (this.svgGroup_)).translate_ = '';
this.svgRect_ = dom.createSvgElement(Svg.RECT, {
'class': 'blocklyCommentRect',
@@ -485,10 +485,13 @@ class WorkspaceCommentSvg extends WorkspaceComment {
if (dragSurface) {
dragSurface.translateSurface(newLoc.x, newLoc.y);
} else {
this.svgGroup_.translate_ =
(/** @type {?} */ (this.svgGroup_)).translate_ =
'translate(' + newLoc.x + ',' + newLoc.y + ')';
this.svgGroup_.setAttribute(
'transform', this.svgGroup_.translate_ + this.svgGroup_.skew_);
(/** @type {?} */ (this.svgGroup_))
.setAttribute(
'transform',
(/** @type {?} */ (this.svgGroup_)).translate_ +
(/** @type {?} */ (this.svgGroup_)).skew_);
}
}
@@ -583,8 +586,8 @@ class WorkspaceCommentSvg extends WorkspaceComment {
setDragging(adding) {
if (adding) {
const group = this.getSvgRoot();
group.translate_ = '';
group.skew_ = '';
(/** @type {?} */ (group)).translate_ = '';
(/** @type {?} */ (group)).skew_ = '';
dom.addClass(
/** @type {!Element} */ (this.svgGroup_), 'blocklyDragging');
} else {
@@ -658,7 +661,7 @@ class WorkspaceCommentSvg extends WorkspaceComment {
* @package
*/
toXmlWithXY(opt_noId) {
let width; // Not used in LTR.
let width = 0; // Not used in LTR.
if (this.workspace.RTL) {
// Here be performance dragons: This calls getMetrics().
width = this.workspace.getWidth();
@@ -781,7 +784,8 @@ class WorkspaceCommentSvg extends WorkspaceComment {
const body = document.createElementNS(dom.HTML_NS, 'body');
body.setAttribute('xmlns', dom.HTML_NS);
body.className = 'blocklyMinimalBody';
const textarea = document.createElementNS(dom.HTML_NS, 'textarea');
const textarea = /** @type {HTMLTextAreaElement} */ (
document.createElementNS(dom.HTML_NS, 'textarea'));
textarea.className = 'blocklyCommentTextarea';
textarea.setAttribute('dir', this.RTL ? 'RTL' : 'LTR');
textarea.readOnly = !this.isEditable();

View File

@@ -749,7 +749,7 @@ class WorkspaceSvg extends Workspace {
if (this.inverseScreenCTMDirty_) {
const ctm = this.getParentSvg().getScreenCTM();
if (ctm) {
this.inverseScreenCTM_ = ctm.inverse();
this.inverseScreenCTM_ = (/** @type {!SVGMatrix} */ (ctm)).inverse();
this.inverseScreenCTMDirty_ = false;
}
}
@@ -1243,13 +1243,13 @@ class WorkspaceSvg extends Workspace {
this.cachedParentSvgSize_.width = width;
// This is set to support the public (but deprecated) Blockly.svgSize
// method.
svg.cachedWidth_ = width;
svg.setAttribute('data-cached-width', width);
}
if (height != null) {
this.cachedParentSvgSize_.height = height;
// This is set to support the public (but deprecated) Blockly.svgSize
// method.
svg.cachedHeight_ = height;
svg.setAttribute('data-cached-height', height);
}
}
@@ -1265,7 +1265,7 @@ class WorkspaceSvg extends Workspace {
* Get the SVG element that contains this workspace.
* Note: We assume this is only called after the workspace has been injected
* into the DOM.
* @return {!SVGElement} SVG element.
* @return {!SVGSVGElement} SVG element.
*/
getParentSvg() {
if (!this.cachedParentSvg_) {
@@ -1275,10 +1275,10 @@ class WorkspaceSvg extends Workspace {
this.cachedParentSvg_ = element;
break;
}
element = /** @type {!SVGElement} */ (element.parentNode);
element = /** @type {!SVGSVGElement} */ (element.parentNode);
}
}
return /** @type {!SVGElement} */ (this.cachedParentSvg_);
return /** @type {!SVGSVGElement} */ (this.cachedParentSvg_);
}
/**
@@ -1865,7 +1865,7 @@ class WorkspaceSvg extends Workspace {
/**
* Handle a mouse-wheel on SVG drawing surface.
* @param {!Event} e Mouse wheel event.
* @param {!WheelEvent} e Mouse wheel event.
* @private
*/
onMouseWheel_(e) {
@@ -2074,11 +2074,11 @@ class WorkspaceSvg extends Workspace {
try {
// In IE11, use setActive (which is IE only) so the page doesn't scroll
// to the workspace gaining focus.
this.getParentSvg().parentNode.setActive();
(/** @type {?} */ (this.getParentSvg().parentElement)).setActive();
} catch (e) {
// setActive support was discontinued in Edge so when that fails, call
// focus instead.
this.getParentSvg().parentNode.focus({preventScroll: true});
this.getParentSvg().parentElement.focus({preventScroll: true});
}
}
}
@@ -2115,7 +2115,8 @@ class WorkspaceSvg extends Workspace {
// canvas' space, so that they are in workspace units relative to the top
// left of the visible portion of the workspace.
let matrix = this.getCanvas().getCTM();
let center = this.getParentSvg().createSVGPoint();
let center =
(/** @type {SVGSVGElement} */ (this.getParentSvg())).createSVGPoint();
center.x = x;
center.y = y;
center = center.matrixTransform(matrix.inverse());

View File

@@ -108,7 +108,7 @@ const blockToDomWithXY = function(block, opt_noId) {
}
}
let width; // Not used in LTR.
let width = 0; // Not used in LTR.
if (block.workspace.RTL) {
width = block.workspace.getWidth();
}
@@ -299,7 +299,7 @@ const cloneShadow = function(shadow, opt_noId) {
if (opt_noId && node.nodeName === 'shadow') {
// Strip off IDs from shadow blocks. There should never be a 'block' as
// a child of a 'shadow', so no need to check that.
node.removeAttribute('id');
(/** @type {!Element} */ (node)).removeAttribute('id');
}
if (node.firstChild) {
node = node.firstChild;
@@ -308,7 +308,8 @@ const cloneShadow = function(shadow, opt_noId) {
textNode = node;
node = node.parentNode;
if (textNode.nodeType === dom.NodeType.TEXT_NODE &&
textNode.data.trim() === '' && node.firstChild !== textNode) {
(/** @type {!Text} */ (textNode)).data.trim() === '' &&
node.firstChild !== textNode) {
// Prune whitespace after a tag.
dom.removeNode(textNode);
}
@@ -317,7 +318,7 @@ const cloneShadow = function(shadow, opt_noId) {
textNode = node;
node = node.nextSibling;
if (textNode.nodeType === dom.NodeType.TEXT_NODE &&
textNode.data.trim() === '') {
(/** @type {!Text} */ (textNode)).data.trim() === '') {
// Prune whitespace before a tag.
dom.removeNode(textNode);
}
@@ -433,7 +434,7 @@ const domToWorkspace = function(xml, workspace) {
'swap the arguments.');
}
let width; // Not used in LTR.
let width = 0; // Not used in LTR.
if (workspace.RTL) {
width = workspace.getWidth();
}
@@ -610,10 +611,10 @@ const domToBlock = function(xmlBlock, workspace) {
topBlockSvg.setConnectionTracking(false);
// Render each block.
for (let i = blocks.length - 1; i >= 0; i--) {
blocks[i].initSvg();
(/** @type {!BlockSvg} */ (blocks[i])).initSvg();
}
for (let i = blocks.length - 1; i >= 0; i--) {
blocks[i].render(false);
(/** @type {!BlockSvg} */ (blocks[i])).render(false);
}
// Populating the connection database may be deferred until after the
// blocks have rendered.
@@ -661,11 +662,8 @@ exports.domToBlock = domToBlock;
* @alias Blockly.Xml.domToVariables
*/
const domToVariables = function(xmlVariables, workspace) {
for (let i = 0; i < xmlVariables.childNodes.length; i++) {
const xmlChild = xmlVariables.childNodes[i];
if (xmlChild.nodeType !== dom.NodeType.ELEMENT_NODE) {
continue; // Skip text nodes.
}
for (let i = 0; i < xmlVariables.children.length; i++) {
const xmlChild = xmlVariables.children[i];
const type = xmlChild.getAttribute('type');
const id = xmlChild.getAttribute('id');
const name = xmlChild.textContent;