mirror of
https://github.com/google/blockly.git
synced 2026-01-07 09:00:11 +01:00
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:
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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. ` +
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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_() {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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_();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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, ' ');
|
||||
fieldElement.textContent =
|
||||
(/** @type {string} */ (this.getValue())).replace(/\n/g, ' ');
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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} */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 +
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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_();
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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());
|
||||
|
||||
22
core/xml.js
22
core/xml.js
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user